@omnicross/daemon 0.4.2 → 0.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -930,7 +930,11 @@ var TOKEN_FIELDS = {
930
930
  claude: ["accessToken", "refreshToken"],
931
931
  codex: ["accessToken", "refreshToken", "idToken"],
932
932
  gemini: ["accessToken", "refreshToken"],
933
- opencodego: ["apiKey"]
933
+ opencodego: ["apiKey"],
934
+ kimi: ["accessToken", "refreshToken"],
935
+ grok: ["accessToken", "refreshToken"],
936
+ copilot: ["accessToken", "refreshToken"],
937
+ antigravity: ["accessToken", "refreshToken"]
934
938
  };
935
939
  function transformTokenBlock(block, fields, fn) {
936
940
  const next = { ...block };
@@ -1170,16 +1174,18 @@ import { setSubscriptionRegistryForOutbound } from "@omnicross/core/outbound-api
1170
1174
  import { getSharedAccountHealth as getSharedAccountHealth4 } from "@omnicross/core/pipeline/SubscriptionAccountHealth";
1171
1175
  import {
1172
1176
  __resetSharedAccountAllowanceStoreForTests,
1173
- AccountAllowanceStore as AccountAllowanceStore9,
1177
+ AccountAllowanceStore as AccountAllowanceStore10,
1174
1178
  setSharedAccountAllowanceStore
1175
1179
  } from "@omnicross/core/pipeline/AccountAllowanceStore";
1176
1180
  import {
1177
1181
  __resetSharedAccountAllowanceSchedulingForTests,
1178
1182
  getSharedAccountAllowanceScheduling as getSharedAccountAllowanceScheduling5
1179
1183
  } from "@omnicross/core/pipeline/AccountAllowanceScheduling";
1180
- import { fetchUpstream as fetchUpstream14, setUpstreamProxyResolver } from "@omnicross/core/pipeline/upstreamFetch";
1184
+ import { fetchUpstream as fetchUpstream16, setUpstreamProxyResolver } from "@omnicross/core/pipeline/upstreamFetch";
1181
1185
  import { __resetSharedIdentityStoreForTests } from "@omnicross/core/provider-proxy/identity/SubscriptionIdentityStore";
1182
1186
  import { setGeminiCodeAssistResolver } from "@omnicross/core/ports/gemini-code-assist-resolver";
1187
+ import { setAntigravitySandboxFailover } from "@omnicross/core/transformer/transformers/antigravityFailover";
1188
+ import { setOpenCodeGoUserAgent } from "@omnicross/core/provider-proxy/identity/openCodeGoHeaders";
1183
1189
  import {
1184
1190
  __resetProviderProxyForTests,
1185
1191
  createNativeResponsesHostedImageIngress,
@@ -1563,7 +1569,7 @@ function handleCopilotOAuthStatus(sessionId, deps) {
1563
1569
 
1564
1570
  // src/allowance/AccountAllowanceService.ts
1565
1571
  import {
1566
- getSharedAccountAllowanceStore as getSharedAccountAllowanceStore8
1572
+ getSharedAccountAllowanceStore as getSharedAccountAllowanceStore9
1567
1573
  } from "@omnicross/core/pipeline/AccountAllowanceStore";
1568
1574
  import {
1569
1575
  getSharedAccountAllowanceScheduling
@@ -2953,11 +2959,328 @@ var GeminiAllowanceCollector = class {
2953
2959
  }
2954
2960
  };
2955
2961
 
2956
- // src/allowance/OpenCodeGoAllowanceCollector.ts
2962
+ // src/allowance/AntigravityAllowanceCollector.ts
2963
+ import { ANTIGRAVITY_CODE_ASSIST_ENDPOINT } from "@omnicross/core/auth/GeminiCodeAssistProjectResolver";
2964
+ import {
2965
+ ANTIGRAVITY_COUNTER_TO_MODEL_FAMILY,
2966
+ antigravityCounterFamiliesForBucketId
2967
+ } from "@omnicross/core/pipeline/antigravityQuotaFamily";
2957
2968
  import {
2958
2969
  getSharedAccountAllowanceStore as getSharedAccountAllowanceStore7
2959
2970
  } from "@omnicross/core/pipeline/AccountAllowanceStore";
2960
2971
  import { fetchUpstream as fetchUpstream7 } from "@omnicross/core/pipeline/upstreamFetch";
2972
+ import { getAntigravityUserAgent } from "@omnicross/core/transformer/transformers/antigravityIdentity";
2973
+ var ANTIGRAVITY_ALLOWANCE_CACHE_MS = 5 * 6e4;
2974
+ var RETRIEVE_USER_QUOTA_SUMMARY_PATH = "/v1internal:retrieveUserQuotaSummary";
2975
+ var FETCH_AVAILABLE_MODELS_PATH = "/v1internal:fetchAvailableModels";
2976
+ var ANTIGRAVITY_DISCOVERY_DENYLIST = /* @__PURE__ */ new Set([
2977
+ "chat_20706",
2978
+ "chat_23310",
2979
+ "gemini-2.5-pro"
2980
+ ]);
2981
+ function isRecord5(value) {
2982
+ return !!value && typeof value === "object" && !Array.isArray(value);
2983
+ }
2984
+ function secondsUntil7(instant, now) {
2985
+ if (!instant) return void 0;
2986
+ return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
2987
+ }
2988
+ var WINDOW_LABELS = {
2989
+ "five-hour": "5 Hour",
2990
+ weekly: "Weekly",
2991
+ daily: "Daily"
2992
+ };
2993
+ function classifyWindowId(...sources) {
2994
+ for (const source of sources) {
2995
+ if (!source) continue;
2996
+ const text = source.toLowerCase();
2997
+ if (text.includes("week") || text.includes("7d") || /7[\s_-]*day/.test(text)) return "weekly";
2998
+ if (text.includes("5h") || text.includes("five hour") || /5[\s_-]*hour/.test(text)) return "five-hour";
2999
+ if (text.includes("day") || text.includes("daily") || text.includes("24h")) return "daily";
3000
+ }
3001
+ return void 0;
3002
+ }
3003
+ function inferWindowFromReset(resetsAt, now) {
3004
+ if (resetsAt !== void 0 && Date.parse(resetsAt) - now > 24 * 60 * 60 * 1e3) return "weekly";
3005
+ return "daily";
3006
+ }
3007
+ function clampFraction(value) {
3008
+ if (value === void 0 || !Number.isFinite(value)) return void 0;
3009
+ return Math.min(1, Math.max(0, value));
3010
+ }
3011
+ function usedPercentFromFraction(fraction) {
3012
+ const clamped = clampFraction(fraction);
3013
+ if (clamped === void 0) return null;
3014
+ return Math.round((1 - clamped) * 1e3) / 10;
3015
+ }
3016
+ function toResetsAt(resetTime) {
3017
+ if (!resetTime || !Number.isFinite(Date.parse(resetTime))) return void 0;
3018
+ return new Date(Date.parse(resetTime)).toISOString();
3019
+ }
3020
+ function parseAntigravityQuotaSummary(payload, now) {
3021
+ if (!isRecord5(payload)) return null;
3022
+ const groups = Array.isArray(payload["groups"]) ? payload["groups"] : [];
3023
+ const topBuckets = Array.isArray(payload["buckets"]) ? payload["buckets"] : [];
3024
+ const hasGrouped = groups.some((group) => Array.isArray(group.buckets) && group.buckets.length > 0);
3025
+ if (!hasGrouped && topBuckets.length === 0) return null;
3026
+ const windows = /* @__PURE__ */ new Map();
3027
+ const addBucket = (bucket, groupName) => {
3028
+ const families = antigravityCounterFamiliesForBucketId(bucket.bucketId, groupName);
3029
+ if (families.length === 0) return;
3030
+ const resetsAt = toResetsAt(bucket.resetTime);
3031
+ const windowId = classifyWindowId(bucket.window, bucket.displayName, bucket.bucketId) ?? (resetsAt !== void 0 ? inferWindowFromReset(resetsAt, now) : void 0);
3032
+ if (windowId === void 0) return;
3033
+ const usedPercent = usedPercentFromFraction(bucket.remainingFraction) ?? (bucket.disabled === true || bucket.resetTime ? bucket.disabled === true ? 100 : null : null);
3034
+ for (const family of families) {
3035
+ const id = `antigravity:${family}:${windowId}`;
3036
+ const candidate = {
3037
+ id,
3038
+ label: `${WINDOW_LABELS[windowId]} (${family})`,
3039
+ scope: "model-family",
3040
+ // The window carries the MODEL family (gemini/claude/gpt-oss) — the
3041
+ // scheduling gate compares it against the requested model's family.
3042
+ modelFamily: ANTIGRAVITY_COUNTER_TO_MODEL_FAMILY[family],
3043
+ usedPercent,
3044
+ ...resetsAt !== void 0 ? { resetsAt } : {},
3045
+ remainingSeconds: secondsUntil7(resetsAt, now),
3046
+ state: "fresh",
3047
+ ...bucket.disabled === true ? { disabled: true } : {}
3048
+ };
3049
+ const existing = windows.get(id);
3050
+ if (!existing || candidate.disabled === true || existing.disabled !== true && (candidate.usedPercent ?? -1) > (existing.usedPercent ?? -1)) {
3051
+ windows.set(id, candidate);
3052
+ }
3053
+ }
3054
+ };
3055
+ if (hasGrouped) {
3056
+ for (const group of groups) {
3057
+ for (const bucket of group.buckets ?? []) addBucket(bucket, group.displayName);
3058
+ }
3059
+ } else {
3060
+ for (const bucket of topBuckets) addBucket(bucket);
3061
+ }
3062
+ const result = [...windows.values()];
3063
+ return result.length > 0 ? result : null;
3064
+ }
3065
+ function legacyQuotaInfos(model) {
3066
+ const out = [];
3067
+ const source = {
3068
+ ...model.apiProvider ? { apiProvider: model.apiProvider } : {},
3069
+ ...model.modelProvider ? { modelProvider: model.modelProvider } : {}
3070
+ };
3071
+ const add = (value, windowDefault) => {
3072
+ if (!value) return;
3073
+ const list = Array.isArray(value) ? value : [value];
3074
+ for (const info of list) {
3075
+ out.push({ ...source, ...windowDefault ? { windowId: windowDefault } : {}, ...info });
3076
+ }
3077
+ };
3078
+ add(model.quotaInfo);
3079
+ add(model.quotaInfos);
3080
+ add(model.dailyQuotaInfo, "daily");
3081
+ add(model.dailyQuotaInfos, "daily");
3082
+ add(model.weeklyQuotaInfo, "weekly");
3083
+ add(model.weeklyQuotaInfos, "weekly");
3084
+ return out;
3085
+ }
3086
+ function legacyCounterFamily(info) {
3087
+ switch (info.modelProvider ?? info.apiProvider) {
3088
+ case "MODEL_PROVIDER_ANTHROPIC":
3089
+ case "API_PROVIDER_ANTHROPIC_VERTEX":
3090
+ return "anthropic";
3091
+ case "MODEL_PROVIDER_GOOGLE":
3092
+ case "API_PROVIDER_GOOGLE_GEMINI":
3093
+ return "google";
3094
+ case "MODEL_PROVIDER_OPENAI":
3095
+ case "API_PROVIDER_OPENAI_VERTEX":
3096
+ return "openai";
3097
+ default:
3098
+ return void 0;
3099
+ }
3100
+ }
3101
+ function parseAntigravityLegacyQuota(payload, now) {
3102
+ if (!isRecord5(payload)) return null;
3103
+ const models = payload["models"];
3104
+ if (!isRecord5(models)) return null;
3105
+ const windows = /* @__PURE__ */ new Map();
3106
+ for (const info of Object.values(models).flatMap(legacyQuotaInfos)) {
3107
+ const family = legacyCounterFamily(info);
3108
+ if (!family) continue;
3109
+ const resetsAt = toResetsAt(info.resetTime);
3110
+ const windowId = classifyWindowId(info.windowId, info.windowLabel) ?? (resetsAt !== void 0 ? inferWindowFromReset(resetsAt, now) : void 0);
3111
+ if (windowId === void 0) continue;
3112
+ const id = `antigravity:${family}:${windowId}`;
3113
+ const candidate = {
3114
+ id,
3115
+ label: `${WINDOW_LABELS[windowId]} (${family})`,
3116
+ scope: "model-family",
3117
+ modelFamily: ANTIGRAVITY_COUNTER_TO_MODEL_FAMILY[family],
3118
+ usedPercent: usedPercentFromFraction(info.remainingFraction),
3119
+ ...resetsAt !== void 0 ? { resetsAt } : {},
3120
+ remainingSeconds: secondsUntil7(resetsAt, now),
3121
+ state: "fresh"
3122
+ };
3123
+ const existing = windows.get(id);
3124
+ if (!existing || (candidate.usedPercent ?? -1) > (existing.usedPercent ?? -1)) {
3125
+ windows.set(id, candidate);
3126
+ }
3127
+ }
3128
+ const result = [...windows.values()];
3129
+ return result.length > 0 ? result : null;
3130
+ }
3131
+ var AntigravityAllowanceCollector = class {
3132
+ constructor(credentials, store = getSharedAccountAllowanceStore7(), fetchImpl = (url, init, accountId) => fetchUpstream7(url, init, { providerId: "antigravity", accountId, redactBodies: true }), now = Date.now) {
3133
+ this.credentials = credentials;
3134
+ this.store = store;
3135
+ this.fetchImpl = fetchImpl;
3136
+ this.now = now;
3137
+ }
3138
+ credentials;
3139
+ store;
3140
+ fetchImpl;
3141
+ now;
3142
+ inFlight = /* @__PURE__ */ new Map();
3143
+ async collectMany(accounts, options = {}) {
3144
+ const settled = await Promise.allSettled(
3145
+ accounts.map((account) => this.collect(account, options))
3146
+ );
3147
+ return settled.flatMap((result) => result.status === "fulfilled" ? [result.value] : []);
3148
+ }
3149
+ collect(account, options = {}) {
3150
+ const now = this.now();
3151
+ if (account.tokens.authMethod !== "oauth") {
3152
+ const existing = this.store.get("antigravity", account.id, now);
3153
+ if (existing?.windows.every((window) => window.state === "unsupported")) {
3154
+ return Promise.resolve(existing);
3155
+ }
3156
+ const snapshot = this.unsupportedSnapshot(account.id, now);
3157
+ this.store.set(snapshot);
3158
+ return Promise.resolve(snapshot);
3159
+ }
3160
+ const cached = this.store.get("antigravity", account.id, now);
3161
+ if (!options.force && cached && this.isCacheValid(cached, now, options.refreshAheadMs)) {
3162
+ return Promise.resolve(cached);
3163
+ }
3164
+ const running = this.inFlight.get(account.id);
3165
+ if (running) return running;
3166
+ const promise = this.fetchAccount(account.id).catch(() => this.failureSnapshot(account.id, "antigravity_usage_request_failed", this.now())).finally(() => this.inFlight.delete(account.id));
3167
+ this.inFlight.set(account.id, promise);
3168
+ return promise;
3169
+ }
3170
+ isCacheValid(snapshot, now, refreshAheadMs) {
3171
+ if (snapshot.windows.every((window) => window.state === "unsupported")) return true;
3172
+ const expiresAt = snapshot.expiresAt ? Date.parse(snapshot.expiresAt) : 0;
3173
+ const ahead = typeof refreshAheadMs === "number" && Number.isFinite(refreshAheadMs) ? Math.max(0, refreshAheadMs) : 0;
3174
+ return Number.isFinite(expiresAt) && expiresAt > now + ahead;
3175
+ }
3176
+ async fetchAccount(accountId) {
3177
+ let accessToken = await this.credentials.getAccessTokenForAccount("antigravity", accountId);
3178
+ if (!accessToken) return this.failureSnapshot(accountId, "antigravity_usage_token_unavailable", this.now());
3179
+ let response = await this.request(accountId, accessToken, RETRIEVE_USER_QUOTA_SUMMARY_PATH, {
3180
+ project: void 0
3181
+ });
3182
+ if (response.status === 401 || response.status === 403) {
3183
+ const refreshed = await this.credentials.refreshAccountToken("antigravity", accountId);
3184
+ if (!refreshed) return this.failureSnapshot(accountId, "antigravity_usage_unauthorized", this.now());
3185
+ accessToken = await this.credentials.getAccessTokenForAccount("antigravity", accountId);
3186
+ if (!accessToken) return this.failureSnapshot(accountId, "antigravity_usage_token_unavailable", this.now());
3187
+ response = await this.request(accountId, accessToken, RETRIEVE_USER_QUOTA_SUMMARY_PATH, {
3188
+ project: void 0
3189
+ });
3190
+ if (response.status === 401 || response.status === 403) {
3191
+ return this.failureSnapshot(accountId, "antigravity_usage_unauthorized", this.now());
3192
+ }
3193
+ }
3194
+ if (response.ok) {
3195
+ const payload = await response.json().catch(() => null);
3196
+ const windows = parseAntigravityQuotaSummary(payload, this.now());
3197
+ if (windows) {
3198
+ const snapshot2 = this.snapshot(accountId, windows);
3199
+ this.store.set(snapshot2);
3200
+ return snapshot2;
3201
+ }
3202
+ }
3203
+ const legacy = await this.request(accountId, accessToken, FETCH_AVAILABLE_MODELS_PATH, {});
3204
+ if (!legacy.ok) {
3205
+ return this.failureSnapshot(accountId, "antigravity_usage_http_error", this.now());
3206
+ }
3207
+ const legacyPayload = await legacy.json().catch(() => null);
3208
+ const legacyWindows = parseAntigravityLegacyQuota(legacyPayload, this.now());
3209
+ if (!legacyWindows) {
3210
+ return this.failureSnapshot(accountId, "antigravity_usage_invalid_response", this.now());
3211
+ }
3212
+ const snapshot = this.snapshot(accountId, legacyWindows);
3213
+ this.store.set(snapshot);
3214
+ return snapshot;
3215
+ }
3216
+ /** One upstream round-trip with the antigravity/hub masquerade UA. */
3217
+ request(accountId, accessToken, path2, body) {
3218
+ return this.fetchImpl(`${ANTIGRAVITY_CODE_ASSIST_ENDPOINT}${path2}`, {
3219
+ method: "POST",
3220
+ headers: {
3221
+ Authorization: `Bearer ${accessToken}`,
3222
+ Accept: "application/json",
3223
+ "Content-Type": "application/json",
3224
+ "User-Agent": getAntigravityUserAgent()
3225
+ },
3226
+ body: JSON.stringify(body),
3227
+ signal: AbortSignal.timeout(15e3)
3228
+ }, accountId);
3229
+ }
3230
+ snapshot(accountId, windows, now = this.now()) {
3231
+ return {
3232
+ providerId: "antigravity",
3233
+ accountId,
3234
+ source: "oauth-usage-api",
3235
+ observedAt: new Date(now).toISOString(),
3236
+ expiresAt: new Date(now + ANTIGRAVITY_ALLOWANCE_CACHE_MS).toISOString(),
3237
+ windows
3238
+ };
3239
+ }
3240
+ failureSnapshot(accountId, code, now) {
3241
+ const existing = this.store.get("antigravity", accountId, now);
3242
+ const snapshot = existing ? {
3243
+ ...existing,
3244
+ expiresAt: new Date(now + ANTIGRAVITY_ALLOWANCE_CACHE_MS).toISOString(),
3245
+ windows: existing.windows.map((window) => ({
3246
+ ...window,
3247
+ state: window.state === "unsupported" ? "unsupported" : window.usedPercent !== null || window.resetsAt || window.disabled ? "stale" : "unavailable"
3248
+ })),
3249
+ lastErrorCode: code
3250
+ } : {
3251
+ providerId: "antigravity",
3252
+ accountId,
3253
+ source: "oauth-usage-api",
3254
+ observedAt: new Date(now).toISOString(),
3255
+ expiresAt: new Date(now + ANTIGRAVITY_ALLOWANCE_CACHE_MS).toISOString(),
3256
+ windows: [
3257
+ { id: "antigravity-quota", label: "Antigravity quota", scope: "all", usedPercent: null, state: "unavailable" }
3258
+ ],
3259
+ lastErrorCode: code
3260
+ };
3261
+ this.store.set(snapshot);
3262
+ return snapshot;
3263
+ }
3264
+ unsupportedSnapshot(accountId, now) {
3265
+ return {
3266
+ providerId: "antigravity",
3267
+ accountId,
3268
+ source: "oauth-usage-api",
3269
+ observedAt: new Date(now).toISOString(),
3270
+ windows: [
3271
+ { id: "antigravity-quota", label: "Antigravity quota", scope: "all", usedPercent: null, state: "unsupported" }
3272
+ ],
3273
+ lastErrorCode: "antigravity_usage_unsupported_auth"
3274
+ };
3275
+ }
3276
+ };
3277
+
3278
+ // src/allowance/OpenCodeGoAllowanceCollector.ts
3279
+ import {
3280
+ getSharedAccountAllowanceStore as getSharedAccountAllowanceStore8
3281
+ } from "@omnicross/core/pipeline/AccountAllowanceStore";
3282
+ import { fetchUpstream as fetchUpstream8 } from "@omnicross/core/pipeline/upstreamFetch";
3283
+ import { getOpenCodeGoUserAgent } from "@omnicross/core/provider-proxy/identity/openCodeGoHeaders";
2961
3284
  import { normalizeOpenCodeGoBaseUrl } from "@omnicross/subscriptions";
2962
3285
  var OPENCODEGO_ALLOWANCE_CACHE_MS = 5 * 6e4;
2963
3286
  var OPENCODEGO_DEFAULT_GO_BASE = "https://opencode.ai/zen/go";
@@ -2971,7 +3294,7 @@ function isoInstant2(value) {
2971
3294
  const time = Date.parse(value);
2972
3295
  return Number.isFinite(time) ? new Date(time).toISOString() : void 0;
2973
3296
  }
2974
- function secondsUntil7(instant, now) {
3297
+ function secondsUntil8(instant, now) {
2975
3298
  if (!instant) return void 0;
2976
3299
  return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
2977
3300
  }
@@ -2986,12 +3309,12 @@ function windowFromPayload3(id, label, minutes, payload, now) {
2986
3309
  usedPercent,
2987
3310
  windowMinutes: minutes,
2988
3311
  ...resetsAt !== void 0 ? { resetsAt } : {},
2989
- remainingSeconds: secondsUntil7(resetsAt, now),
3312
+ remainingSeconds: secondsUntil8(resetsAt, now),
2990
3313
  state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
2991
3314
  };
2992
3315
  }
2993
3316
  var OpenCodeGoAllowanceCollector = class {
2994
- constructor(credentials, store = getSharedAccountAllowanceStore7(), fetchImpl = (url, init, accountId) => fetchUpstream7(url, init, { providerId: "opencodego", accountId, redactBodies: true }), now = Date.now) {
3317
+ constructor(credentials, store = getSharedAccountAllowanceStore8(), fetchImpl = (url, init, accountId) => fetchUpstream8(url, init, { providerId: "opencodego", accountId, redactBodies: true }), now = Date.now) {
2995
3318
  this.credentials = credentials;
2996
3319
  this.store = store;
2997
3320
  this.fetchImpl = fetchImpl;
@@ -3024,7 +3347,14 @@ var OpenCodeGoAllowanceCollector = class {
3024
3347
  const base = account.tokens.baseUrl ? normalizeOpenCodeGoBaseUrl(account.tokens.baseUrl) : OPENCODEGO_DEFAULT_GO_BASE;
3025
3348
  const response = await this.fetchImpl(`${base}/v1/usage`, {
3026
3349
  method: "GET",
3027
- headers: { Authorization: `Bearer ${apiKey}`, Accept: "application/json" },
3350
+ // opencodego-egress-identity: the background poll identifies itself with
3351
+ // the same configured/default UA the relay carries (no session header —
3352
+ // a poll has no conversation).
3353
+ headers: {
3354
+ Authorization: `Bearer ${apiKey}`,
3355
+ Accept: "application/json",
3356
+ "User-Agent": getOpenCodeGoUserAgent()
3357
+ },
3028
3358
  signal: AbortSignal.timeout(15e3)
3029
3359
  }, account.id);
3030
3360
  if (response.status === 401 || response.status === 403) {
@@ -3096,7 +3426,7 @@ function codexUnavailable(accountId, now) {
3096
3426
  };
3097
3427
  }
3098
3428
  var AccountAllowanceService = class {
3099
- constructor(credentials, store = getSharedAccountAllowanceStore8(), collector, codexCollector, kimiCollector, opencodegoCollector, grokCollector, copilotCollector, geminiCollector, now = Date.now) {
3429
+ constructor(credentials, store = getSharedAccountAllowanceStore9(), collector, codexCollector, kimiCollector, opencodegoCollector, grokCollector, copilotCollector, geminiCollector, antigravityCollector, now = Date.now) {
3100
3430
  this.credentials = credentials;
3101
3431
  this.store = store;
3102
3432
  this.now = now;
@@ -3107,6 +3437,7 @@ var AccountAllowanceService = class {
3107
3437
  this.grokCollector = grokCollector ?? new GrokAllowanceCollector(credentials, store);
3108
3438
  this.copilotCollector = copilotCollector ?? new CopilotAllowanceCollector(credentials, store);
3109
3439
  this.geminiCollector = geminiCollector ?? new GeminiAllowanceCollector(credentials, store);
3440
+ this.antigravityCollector = antigravityCollector ?? new AntigravityAllowanceCollector(credentials, store);
3110
3441
  }
3111
3442
  credentials;
3112
3443
  store;
@@ -3118,6 +3449,7 @@ var AccountAllowanceService = class {
3118
3449
  copilotCollector;
3119
3450
  opencodegoCollector;
3120
3451
  geminiCollector;
3452
+ antigravityCollector;
3121
3453
  /**
3122
3454
  * Read all/filtered snapshots. Claude's and Codex's five-minute caches are
3123
3455
  * refreshed lazily on read (Codex polls `/backend-api/wham/usage`; the
@@ -3166,6 +3498,11 @@ var AccountAllowanceService = class {
3166
3498
  (account) => !filter.accountId || account.id === filter.accountId
3167
3499
  );
3168
3500
  if (wantsGemini) await this.geminiCollector.collectMany(geminiAccounts);
3501
+ const wantsAntigravity = !filter.providerId || filter.providerId === "antigravity";
3502
+ const antigravityAccounts = (config.antigravityAccounts ?? []).filter(
3503
+ (account) => !filter.accountId || account.id === filter.accountId
3504
+ );
3505
+ if (wantsAntigravity) await this.antigravityCollector.collectMany(antigravityAccounts);
3169
3506
  const known = /* @__PURE__ */ new Set();
3170
3507
  if (wantsClaude) for (const account of claudeAccounts) known.add(`claude\0${account.id}`);
3171
3508
  if (wantsCodex) for (const account of codexAccounts) known.add(`codex\0${account.id}`);
@@ -3174,6 +3511,7 @@ var AccountAllowanceService = class {
3174
3511
  if (wantsGrok) for (const account of grokAccounts) known.add(`grok\0${account.id}`);
3175
3512
  if (wantsCopilot) for (const account of copilotAccounts) known.add(`copilot\0${account.id}`);
3176
3513
  if (wantsGemini) for (const account of geminiAccounts) known.add(`gemini\0${account.id}`);
3514
+ if (wantsAntigravity) for (const account of antigravityAccounts) known.add(`antigravity\0${account.id}`);
3177
3515
  return this.store.list(filter).filter((snapshot) => known.has(`${snapshot.providerId}\0${snapshot.accountId}`));
3178
3516
  }
3179
3517
  knownAccounts(config) {
@@ -3184,7 +3522,8 @@ var AccountAllowanceService = class {
3184
3522
  ...(config.opencodegoAccounts ?? []).map((account) => ({ providerId: "opencodego", accountId: account.id })),
3185
3523
  ...(config.grokAccounts ?? []).map((account) => ({ providerId: "grok", accountId: account.id })),
3186
3524
  ...(config.copilotAccounts ?? []).map((account) => ({ providerId: "copilot", accountId: account.id })),
3187
- ...(config.geminiAccounts ?? []).map((account) => ({ providerId: "gemini", accountId: account.id }))
3525
+ ...(config.geminiAccounts ?? []).map((account) => ({ providerId: "gemini", accountId: account.id })),
3526
+ ...(config.antigravityAccounts ?? []).map((account) => ({ providerId: "antigravity", accountId: account.id }))
3188
3527
  ];
3189
3528
  }
3190
3529
  /** Force-refresh Claude usage for one account or every stored Claude account. */
@@ -3254,6 +3593,15 @@ var AccountAllowanceService = class {
3254
3593
  );
3255
3594
  return this.geminiCollector.collectMany(accounts, { force: true });
3256
3595
  }
3596
+ /** Force-refresh Antigravity usage (quotaSummary dual buckets) for one/all accounts. */
3597
+ async refreshAntigravity(accountId) {
3598
+ const config = await this.credentials.getFullConfig();
3599
+ this.store.pruneToKnownAccounts(this.knownAccounts(config));
3600
+ const accounts = (config.antigravityAccounts ?? []).filter(
3601
+ (account) => !accountId || account.id === accountId
3602
+ );
3603
+ return this.antigravityCollector.collectMany(accounts, { force: true });
3604
+ }
3257
3605
  /**
3258
3606
  * Keep Claude + Codex + Kimi snapshots warm for allowance-aware routing. All
3259
3607
  * collectors preserve their cache + per-account in-flight coalescing; a tick
@@ -3271,6 +3619,7 @@ var AccountAllowanceService = class {
3271
3619
  await this.grokCollector.collectMany(config.grokAccounts ?? [], { refreshAheadMs });
3272
3620
  await this.copilotCollector.collectMany(config.copilotAccounts ?? [], { refreshAheadMs });
3273
3621
  await this.geminiCollector.collectMany(config.geminiAccounts ?? [], { refreshAheadMs });
3622
+ await this.antigravityCollector.collectMany(config.antigravityAccounts ?? [], { refreshAheadMs });
3274
3623
  }
3275
3624
  /** Remove a cache row as soon as an account is deleted by the admin path. */
3276
3625
  removeAccountSnapshot(providerId, accountId) {
@@ -3700,7 +4049,7 @@ import {
3700
4049
  } from "@omnicross/contracts/image-generation-types";
3701
4050
  import { getSharedAccountAllowanceScheduling as getSharedAccountAllowanceScheduling2 } from "@omnicross/core/pipeline/AccountAllowanceScheduling";
3702
4051
  import { getSharedAccountHealth } from "@omnicross/core/pipeline/SubscriptionAccountHealth";
3703
- import { fetchUpstream as fetchUpstream8 } from "@omnicross/core/pipeline/upstreamFetch";
4052
+ import { fetchUpstream as fetchUpstream10 } from "@omnicross/core/pipeline/upstreamFetch";
3704
4053
  import { mergeExtraHeaders } from "@omnicross/core";
3705
4054
 
3706
4055
  // src/image-generation/imagesConfigValidation.ts
@@ -4034,6 +4383,19 @@ function resolveAdminConfig(admin) {
4034
4383
  token: typeof admin?.token === "string" && admin.token.length > 0 ? admin.token : void 0
4035
4384
  };
4036
4385
  }
4386
+ function validateAntigravity(raw) {
4387
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
4388
+ const a = raw;
4389
+ if (typeof a["sandboxFailover"] !== "boolean") return void 0;
4390
+ return { sandboxFailover: a["sandboxFailover"] };
4391
+ }
4392
+ function validateOpenCodeGo(raw) {
4393
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
4394
+ const o = raw;
4395
+ const ua = o["userAgent"];
4396
+ if (typeof ua !== "string" || ua.trim().length === 0) return void 0;
4397
+ return { userAgent: ua.trim() };
4398
+ }
4037
4399
  function validateUsage(raw) {
4038
4400
  if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
4039
4401
  const u = raw;
@@ -4327,7 +4689,9 @@ function validateConfig(raw) {
4327
4689
  const admin = validateAdmin(obj["admin"]);
4328
4690
  const logging = validateLogging(obj["logging"]);
4329
4691
  const usage = validateUsage(obj["usage"]);
4330
- return { providers, server, admin, logging };
4692
+ const antigravity = validateAntigravity(obj["antigravity"]);
4693
+ const opencodego = validateOpenCodeGo(obj["opencodego"]);
4694
+ return { providers, server, admin, logging, usage, antigravity, opencodego };
4331
4695
  }
4332
4696
  var secretBox = null;
4333
4697
  function setSecretBox(box) {
@@ -5455,6 +5819,167 @@ function createUpstreamProxyResolver(src = {}) {
5455
5819
  };
5456
5820
  }
5457
5821
 
5822
+ // src/admin/accountsAntigravityOAuth.ts
5823
+ import { getAntigravityProjectResolver } from "@omnicross/core/auth/GeminiCodeAssistProjectResolver";
5824
+ import { antigravityOAuth } from "@omnicross/subscriptions";
5825
+ function err5(status, message) {
5826
+ return { status, body: { error: { type: "admin_api_error", message } } };
5827
+ }
5828
+ var DEFAULT_ANTIGRAVITY_OAUTH_TTL_MS = 10 * 6e4;
5829
+ function handleAntigravityOAuthStart(deps) {
5830
+ if (deps.antigravitySessions.isBusy()) {
5831
+ return err5(
5832
+ 409,
5833
+ "an antigravity sign-in is already in progress (loopback 127.0.0.1:51121 is held) \u2014 finish it in the browser or wait for it to time out"
5834
+ );
5835
+ }
5836
+ const { authUrl, state } = antigravityOAuth.generateAuthParams();
5837
+ const { sessionId, signal } = deps.antigravitySessions.begin();
5838
+ void runAntigravityLoopback(sessionId, state, signal, deps);
5839
+ return { status: 200, body: { authUrl, sessionId } };
5840
+ }
5841
+ async function runAntigravityLoopback(sessionId, state, signal, deps) {
5842
+ const isPending = () => !signal.aborted && deps.antigravitySessions.get(sessionId)?.status === "pending";
5843
+ try {
5844
+ const code = await deps.antigravityAwaitLoopback(state, void 0, signal);
5845
+ if (!isPending()) return;
5846
+ const exchangeFetch = deps.oauthExchangeFetch("antigravity");
5847
+ const result = await antigravityOAuth.exchangeCodeForTokens(code, exchangeFetch);
5848
+ if (!isPending()) return;
5849
+ const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
5850
+ const email = await antigravityOAuth.fetchUserEmail(result.accessToken, exchangeFetch);
5851
+ if (!isPending()) return;
5852
+ const projectId = await getAntigravityProjectResolver().resolveProject(result.accessToken);
5853
+ if (!isPending()) return;
5854
+ const block = {
5855
+ authMethod: "oauth",
5856
+ status: "authorized",
5857
+ accessToken: result.accessToken,
5858
+ refreshToken: result.refreshToken,
5859
+ expiresAt,
5860
+ ...email ? { email } : {},
5861
+ ...projectId ? { projectId } : {},
5862
+ lastRefreshedAt: (/* @__PURE__ */ new Date()).toISOString()
5863
+ };
5864
+ await deps.subscriptionAccountAppender.appendProviderAccount("antigravity", block);
5865
+ if (isPending()) deps.antigravitySessions.settle(sessionId, "done");
5866
+ } catch (e) {
5867
+ if (!isPending()) return;
5868
+ const reason = e instanceof Error ? e.message : "antigravity sign-in failed";
5869
+ deps.antigravitySessions.settle(sessionId, "error", reason);
5870
+ }
5871
+ }
5872
+ function handleAntigravityOAuthCancel(sessionId, deps) {
5873
+ if (!deps.antigravitySessions.cancel(sessionId)) {
5874
+ return err5(404, "unknown or expired antigravity sign-in session");
5875
+ }
5876
+ return { status: 200, body: { ok: true } };
5877
+ }
5878
+ function handleAntigravityOAuthStatus(sessionId, deps) {
5879
+ const s = deps.antigravitySessions.get(sessionId);
5880
+ if (!s) return err5(404, "unknown or expired antigravity sign-in session");
5881
+ return { status: 200, body: { state: s.status, ...s.error ? { message: s.error } : {} } };
5882
+ }
5883
+
5884
+ // src/allowance/AntigravityModelDiscovery.ts
5885
+ import { lookupCanonicalCapabilities } from "@omnicross/contracts/canonical-models";
5886
+ import { SUBSCRIPTION_MODEL_CATALOG } from "@omnicross/contracts/subscription-model-catalog";
5887
+ import { ANTIGRAVITY_CODE_ASSIST_ENDPOINT as ANTIGRAVITY_CODE_ASSIST_ENDPOINT2 } from "@omnicross/core/auth/GeminiCodeAssistProjectResolver";
5888
+ import { fetchUpstream as fetchUpstream9 } from "@omnicross/core/pipeline/upstreamFetch";
5889
+ import { getAntigravityUserAgent as getAntigravityUserAgent2 } from "@omnicross/core/transformer/transformers/antigravityIdentity";
5890
+ function isRecord6(value) {
5891
+ return !!value && typeof value === "object" && !Array.isArray(value);
5892
+ }
5893
+ function optionalString(value) {
5894
+ return typeof value === "string" && value.length > 0 ? value : void 0;
5895
+ }
5896
+ function optionalNumber(value) {
5897
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : void 0;
5898
+ }
5899
+ function optionalBoolean(value) {
5900
+ return typeof value === "boolean" ? value : void 0;
5901
+ }
5902
+ function parseAntigravityAvailableModels(payload) {
5903
+ if (!isRecord6(payload)) return [];
5904
+ const models = payload["models"];
5905
+ if (!isRecord6(models)) return [];
5906
+ const out = [];
5907
+ for (const [id, raw] of Object.entries(models)) {
5908
+ if (ANTIGRAVITY_DISCOVERY_DENYLIST.has(id)) continue;
5909
+ if (!isRecord6(raw)) continue;
5910
+ if (raw["isInternal"] === true) continue;
5911
+ out.push({
5912
+ id,
5913
+ ...optionalString(raw["displayName"]) ? { displayName: optionalString(raw["displayName"]) } : {},
5914
+ ...optionalBoolean(raw["supportsImages"]) !== void 0 ? { supportsImages: optionalBoolean(raw["supportsImages"]) } : {},
5915
+ ...optionalBoolean(raw["supportsThinking"]) !== void 0 ? { supportsThinking: optionalBoolean(raw["supportsThinking"]) } : {},
5916
+ ...optionalNumber(raw["thinkingBudget"]) !== void 0 ? { thinkingBudget: optionalNumber(raw["thinkingBudget"]) } : {},
5917
+ ...optionalNumber(raw["maxTokens"]) !== void 0 ? { maxTokens: optionalNumber(raw["maxTokens"]) } : {},
5918
+ ...optionalNumber(raw["maxOutputTokens"]) !== void 0 ? { maxOutputTokens: optionalNumber(raw["maxOutputTokens"]) } : {}
5919
+ });
5920
+ }
5921
+ out.sort((a, b) => a.id.localeCompare(b.id));
5922
+ return out;
5923
+ }
5924
+ function mergeAntigravityCatalog(discovered, log = (line) => console.warn(line), staticIds = SUBSCRIPTION_MODEL_CATALOG.antigravity) {
5925
+ const entries = staticIds.map((id) => {
5926
+ const capabilities = lookupCanonicalCapabilities(id);
5927
+ return {
5928
+ id,
5929
+ origin: "static",
5930
+ displayName: id,
5931
+ ...capabilities?.vision !== void 0 ? { supportsImages: capabilities.vision } : {},
5932
+ ...capabilities?.reasoning !== void 0 ? { supportsThinking: capabilities.reasoning } : {},
5933
+ ...capabilities?.thinkingTokenLimit ? { thinkingBudget: capabilities.thinkingTokenLimit.max } : {},
5934
+ // Discovery calls the context window maxTokens, not the output ceiling.
5935
+ ...capabilities?.contextLength !== void 0 ? { maxTokens: capabilities.contextLength } : {},
5936
+ ...capabilities?.maxTokens !== void 0 ? { maxOutputTokens: capabilities.maxTokens } : {}
5937
+ };
5938
+ });
5939
+ const staticSet = new Set(staticIds);
5940
+ for (const model of discovered) {
5941
+ if (staticSet.has(model.id)) {
5942
+ log(
5943
+ `[AntigravityModelDiscovery] dynamic model '${model.id}' conflicts with the static catalog \u2014 static entry kept`
5944
+ );
5945
+ continue;
5946
+ }
5947
+ entries.push({ ...model, origin: "discovered" });
5948
+ }
5949
+ return entries;
5950
+ }
5951
+ async function fetchAntigravityAvailableModels(accessToken, fetchImpl = (url, init) => fetchUpstream9(url, init, { providerId: "antigravity", redactBodies: true })) {
5952
+ let response;
5953
+ try {
5954
+ response = await fetchImpl(`${ANTIGRAVITY_CODE_ASSIST_ENDPOINT2}/v1internal:fetchAvailableModels`, {
5955
+ method: "POST",
5956
+ headers: {
5957
+ Authorization: `Bearer ${accessToken}`,
5958
+ Accept: "application/json",
5959
+ "Content-Type": "application/json",
5960
+ "User-Agent": getAntigravityUserAgent2()
5961
+ },
5962
+ body: JSON.stringify({}),
5963
+ signal: AbortSignal.timeout(15e3)
5964
+ });
5965
+ } catch {
5966
+ return null;
5967
+ }
5968
+ if (!response.ok) return null;
5969
+ const payload = await response.json().catch(() => null);
5970
+ if (!isRecord6(payload) || !isRecord6(payload["models"])) return null;
5971
+ return parseAntigravityAvailableModels(payload);
5972
+ }
5973
+ async function handleAntigravityModelsRoute(deps) {
5974
+ const accessToken = await deps.resolveAntigravityAccessToken().catch(() => null);
5975
+ const discovered = accessToken ? await fetchAntigravityAvailableModels(accessToken, deps.fetchImpl) : null;
5976
+ const models = mergeAntigravityCatalog(discovered ?? []);
5977
+ return {
5978
+ status: 200,
5979
+ body: { models, discovered: discovered !== null }
5980
+ };
5981
+ }
5982
+
5458
5983
  // src/admin/accountsOAuth.ts
5459
5984
  import { claudeOAuth, geminiOAuth } from "@omnicross/subscriptions";
5460
5985
 
@@ -5466,7 +5991,8 @@ var VALID_PROVIDER_IDS = [
5466
5991
  "opencodego",
5467
5992
  "kimi",
5468
5993
  "grok",
5469
- "copilot"
5994
+ "copilot",
5995
+ "antigravity"
5470
5996
  ];
5471
5997
  function asSubscriptionProviderId(id) {
5472
5998
  return VALID_PROVIDER_IDS.includes(id) ? id : null;
@@ -5648,7 +6174,7 @@ function validateCopilot(body) {
5648
6174
  ]);
5649
6175
  return out;
5650
6176
  }
5651
- function validateOpenCodeGo(body) {
6177
+ function validateOpenCodeGo2(body) {
5652
6178
  const authMethod = str(body["authMethod"]);
5653
6179
  const status = str(body["status"]);
5654
6180
  if (authMethod !== "manual") return null;
@@ -5682,7 +6208,7 @@ function validateTokenBody(providerId, body) {
5682
6208
  case "gemini":
5683
6209
  return validateGemini(body);
5684
6210
  case "opencodego":
5685
- return validateOpenCodeGo(body);
6211
+ return validateOpenCodeGo2(body);
5686
6212
  case "kimi":
5687
6213
  return validateKimi(body);
5688
6214
  case "grok":
@@ -5718,12 +6244,12 @@ async function statusEntryFor(reader, providerId) {
5718
6244
 
5719
6245
  // src/admin/accountsOAuth.ts
5720
6246
  var OAUTH_HTTP_PROVIDERS = /* @__PURE__ */ new Set(["claude", "gemini"]);
5721
- function err5(status, message) {
6247
+ function err6(status, message) {
5722
6248
  return { status, body: { error: { type: "admin_api_error", message } } };
5723
6249
  }
5724
6250
  function handleOAuthStart(providerId, deps) {
5725
6251
  if (!OAUTH_HTTP_PROVIDERS.has(providerId)) {
5726
- return err5(400, `oauth not available for provider '${providerId}'`);
6252
+ return err6(400, `oauth not available for provider '${providerId}'`);
5727
6253
  }
5728
6254
  const flow = providerId === "claude" ? claudeOAuth : geminiOAuth;
5729
6255
  const { authUrl, codeVerifier, state } = flow.generateAuthParams();
@@ -5732,23 +6258,23 @@ function handleOAuthStart(providerId, deps) {
5732
6258
  }
5733
6259
  async function handleOAuthComplete(providerId, body, deps) {
5734
6260
  if (!OAUTH_HTTP_PROVIDERS.has(providerId)) {
5735
- return err5(400, `oauth not available for provider '${providerId}'`);
6261
+ return err6(400, `oauth not available for provider '${providerId}'`);
5736
6262
  }
5737
6263
  const sessionId = typeof body["sessionId"] === "string" ? body["sessionId"] : "";
5738
6264
  const rawCode = typeof body["code"] === "string" ? body["code"] : "";
5739
- if (!sessionId) return err5(400, "oauth complete requires { sessionId }");
5740
- if (!rawCode) return err5(400, "oauth complete requires { code }");
6265
+ if (!sessionId) return err6(400, "oauth complete requires { sessionId }");
6266
+ if (!rawCode) return err6(400, "oauth complete requires { code }");
5741
6267
  const session = deps.oauthSessions.peek(sessionId);
5742
- if (!session) return err5(410, "oauth session is unknown, expired, or already used");
6268
+ if (!session) return err6(410, "oauth session is unknown, expired, or already used");
5743
6269
  if (session.providerId !== providerId) {
5744
- return err5(400, `oauth session does not match provider '${providerId}'`);
6270
+ return err6(400, `oauth session does not match provider '${providerId}'`);
5745
6271
  }
5746
6272
  let code = rawCode.trim();
5747
6273
  if (providerId === "claude") {
5748
6274
  const [splitCode, pastedState] = code.split("#");
5749
- if (!splitCode) return err5(400, "no authorization code was provided");
6275
+ if (!splitCode) return err6(400, "no authorization code was provided");
5750
6276
  if (pastedState && pastedState !== session.state) {
5751
- return err5(400, "oauth state did not match (possible CSRF) \u2014 aborting");
6277
+ return err6(400, "oauth state did not match (possible CSRF) \u2014 aborting");
5752
6278
  }
5753
6279
  code = splitCode;
5754
6280
  }
@@ -5758,7 +6284,7 @@ async function handleOAuthComplete(providerId, body, deps) {
5758
6284
  block = providerId === "claude" ? await exchangeClaude(code, session.codeVerifier, session.state, exchangeFetch) : await exchangeGemini(code, session.codeVerifier, exchangeFetch);
5759
6285
  } catch (exchangeError) {
5760
6286
  const reason = exchangeError instanceof Error ? exchangeError.message : "token exchange failed";
5761
- return err5(502, `oauth token exchange failed for '${providerId}': ${reason}`);
6287
+ return err6(502, `oauth token exchange failed for '${providerId}': ${reason}`);
5762
6288
  }
5763
6289
  deps.oauthSessions.consume(sessionId);
5764
6290
  const label = typeof body["label"] === "string" && body["label"].trim() ? body["label"].trim() : void 0;
@@ -6096,8 +6622,8 @@ function errBody(message) {
6096
6622
  return { error: { type: "admin_api_error", message } };
6097
6623
  }
6098
6624
  var defaultCommandRunner = (command) => new Promise((resolve11) => {
6099
- exec(command, { timeout: 18e4 }, (err8, _stdout, stderr) => {
6100
- if (err8) resolve11({ ok: false, error: stderr.trim() || err8.message });
6625
+ exec(command, { timeout: 18e4 }, (err9, _stdout, stderr) => {
6626
+ if (err9) resolve11({ ok: false, error: stderr.trim() || err9.message });
6101
6627
  else resolve11({ ok: true });
6102
6628
  });
6103
6629
  });
@@ -6143,8 +6669,8 @@ async function handleCliLaunch(cli, body, ctx) {
6143
6669
  providerId: typeof body["providerId"] === "string" ? body["providerId"] : void 0,
6144
6670
  model: typeof body["model"] === "string" ? body["model"] : void 0
6145
6671
  });
6146
- } catch (err8) {
6147
- return { status: 400, body: errBody(err8 instanceof Error ? err8.message : "no launch target") };
6672
+ } catch (err9) {
6673
+ return { status: 400, body: errBody(err9 instanceof Error ? err9.message : "no launch target") };
6148
6674
  }
6149
6675
  const id = randomUUID2();
6150
6676
  let leaseId2;
@@ -6172,9 +6698,9 @@ async function handleCliLaunch(cli, body, ctx) {
6172
6698
  } else {
6173
6699
  launch = await buildLaunchEnv(cli, ctx.llmConfig, target);
6174
6700
  }
6175
- } catch (err8) {
6176
- const status = err8 instanceof RouteLeaseError2 ? err8.status : 400;
6177
- return { status, body: errBody(err8 instanceof Error ? err8.message : "failed to build launch env") };
6701
+ } catch (err9) {
6702
+ const status = err9 instanceof RouteLeaseError2 ? err9.status : 400;
6703
+ return { status, body: errBody(err9 instanceof Error ? err9.message : "failed to build launch env") };
6178
6704
  }
6179
6705
  const cwd = typeof body["cwd"] === "string" && body["cwd"].trim() ? body["cwd"].trim() : void 0;
6180
6706
  const opener = ctx.opener ?? defaultTerminalOpener;
@@ -6202,9 +6728,9 @@ async function handleCliLaunch(cli, body, ctx) {
6202
6728
  onFailure: onSessionEnd
6203
6729
  });
6204
6730
  if (cleanup) openerCleanup = cleanup;
6205
- } catch (err8) {
6731
+ } catch (err9) {
6206
6732
  onSessionEnd();
6207
- return { status: 500, body: errBody(err8 instanceof Error ? err8.message : "failed to open terminal") };
6733
+ return { status: 500, body: errBody(err9 instanceof Error ? err9.message : "failed to open terminal") };
6208
6734
  }
6209
6735
  if (ended) {
6210
6736
  openerCleanup?.();
@@ -6767,7 +7293,7 @@ async function handleSearchQuery(req, res, deps) {
6767
7293
  // src/admin/searchAdminView.ts
6768
7294
  var API_KEY_PROVIDERS = /* @__PURE__ */ new Set(["tavily", "jina", "zhipu", "z.ai"]);
6769
7295
  var BASIC_AUTH_PROVIDERS = /* @__PURE__ */ new Set(["searxng"]);
6770
- function isRecord5(value) {
7296
+ function isRecord7(value) {
6771
7297
  return value !== null && typeof value === "object" && !Array.isArray(value);
6772
7298
  }
6773
7299
  function redactSearchServerConfig(search) {
@@ -6817,13 +7343,13 @@ function resolveSecretField(entry, field, stored) {
6817
7343
  else delete entry[field];
6818
7344
  }
6819
7345
  function preserveSearchSecrets(incoming, current) {
6820
- if (!isRecord5(incoming)) return incoming;
7346
+ if (!isRecord7(incoming)) return incoming;
6821
7347
  const section = { ...incoming };
6822
7348
  const providersValue = section["providers"];
6823
- if (!isRecord5(providersValue)) return section;
7349
+ if (!isRecord7(providersValue)) return section;
6824
7350
  const providers = {};
6825
7351
  for (const [id, entryValue] of Object.entries(providersValue)) {
6826
- if (!isRecord5(entryValue)) {
7352
+ if (!isRecord7(entryValue)) {
6827
7353
  providers[id] = entryValue;
6828
7354
  continue;
6829
7355
  }
@@ -6901,7 +7427,7 @@ function parseKeyPolicyBody(body) {
6901
7427
  var ENDPOINTS = /* @__PURE__ */ new Set(["chat", "responses", "messages", "gemini"]);
6902
7428
  var TARGET_KINDS = /* @__PURE__ */ new Set(["account", "account-group", "account-pool", "provider"]);
6903
7429
  var FALLBACKS = /* @__PURE__ */ new Set(["next", "fail", "global"]);
6904
- function isRecord6(value) {
7430
+ function isRecord8(value) {
6905
7431
  return !!value && typeof value === "object" && !Array.isArray(value);
6906
7432
  }
6907
7433
  function nonBlank(value) {
@@ -6921,7 +7447,7 @@ function validateGatewayBindingsSegment(patch) {
6921
7447
  const ids = /* @__PURE__ */ new Set();
6922
7448
  raw.forEach((entry, index) => {
6923
7449
  const path2 = `bindings[${index}]`;
6924
- if (!isRecord6(entry)) {
7450
+ if (!isRecord8(entry)) {
6925
7451
  errors.push(`${path2} must be an object`);
6926
7452
  return;
6927
7453
  }
@@ -6950,12 +7476,12 @@ function validateGatewayBindingsSegment(patch) {
6950
7476
  } else if (entry.modelMappings.length > 100) {
6951
7477
  errors.push(`${path2}.modelMappings cannot contain more than 100 entries`);
6952
7478
  } else if (entry.modelMappings.some(
6953
- (mapping) => !isRecord6(mapping) || !nonBlank(mapping.source) || !nonBlank(mapping.target)
7479
+ (mapping) => !isRecord8(mapping) || !nonBlank(mapping.source) || !nonBlank(mapping.target)
6954
7480
  )) {
6955
7481
  errors.push(`${path2}.modelMappings must contain non-empty source and target strings`);
6956
7482
  }
6957
7483
  }
6958
- if (!isRecord6(entry.target) || !TARGET_KINDS.has(String(entry.target.kind))) {
7484
+ if (!isRecord8(entry.target) || !TARGET_KINDS.has(String(entry.target.kind))) {
6959
7485
  errors.push(`${path2}.target is invalid`);
6960
7486
  } else {
6961
7487
  if (!nonBlank(entry.target.providerId)) errors.push(`${path2}.target.providerId is required`);
@@ -6970,7 +7496,7 @@ function validateGatewayBindingsSegment(patch) {
6970
7496
  }
6971
7497
  }
6972
7498
  if (entry.modelMap !== void 0) {
6973
- if (!isRecord6(entry.modelMap) || Object.values(entry.modelMap).some((value) => typeof value !== "string")) {
7499
+ if (!isRecord8(entry.modelMap) || Object.values(entry.modelMap).some((value) => typeof value !== "string")) {
6974
7500
  errors.push(`${path2}.modelMap must contain string values`);
6975
7501
  }
6976
7502
  }
@@ -7267,7 +7793,12 @@ var PROVIDER_KEYS = {
7267
7793
  },
7268
7794
  kimi: { block: "kimi", accounts: "kimiAccounts", active: "activeKimiAccountId" },
7269
7795
  grok: { block: "grok", accounts: "grokAccounts", active: "activeGrokAccountId" },
7270
- copilot: { block: "copilot", accounts: "copilotAccounts", active: "activeCopilotAccountId" }
7796
+ copilot: { block: "copilot", accounts: "copilotAccounts", active: "activeCopilotAccountId" },
7797
+ antigravity: {
7798
+ block: "antigravity",
7799
+ accounts: "antigravityAccounts",
7800
+ active: "activeAntigravityAccountId"
7801
+ }
7271
7802
  };
7272
7803
  function clone(value) {
7273
7804
  return JSON.parse(JSON.stringify(value));
@@ -7789,7 +8320,7 @@ async function applyImport(packString, passphrase, mode, deps, parseProviderInpu
7789
8320
  }
7790
8321
 
7791
8322
  // src/admin/adminMigration.ts
7792
- function err6(status, message) {
8323
+ function err7(status, message) {
7793
8324
  return { status, body: { error: { type: "admin_api_error", message } } };
7794
8325
  }
7795
8326
  async function handleExport(body, deps) {
@@ -7799,30 +8330,30 @@ async function handleExport(body, deps) {
7799
8330
  return { status: 200, body: { pack, version: BUNDLE_VERSION } };
7800
8331
  } catch (error) {
7801
8332
  if (error instanceof WeakPassphraseError) {
7802
- return err6(400, error.message);
8333
+ return err7(400, error.message);
7803
8334
  }
7804
- return err6(500, "failed to build the migration pack");
8335
+ return err7(500, "failed to build the migration pack");
7805
8336
  }
7806
8337
  }
7807
8338
  async function handleImport(body, deps) {
7808
8339
  const blob = typeof body["blob"] === "string" ? body["blob"] : "";
7809
8340
  const passphrase = typeof body["passphrase"] === "string" ? body["passphrase"] : "";
7810
8341
  const mode = body["mode"] === "overwrite" ? "overwrite" : "merge";
7811
- if (!blob) return err6(400, "import requires { blob }");
8342
+ if (!blob) return err7(400, "import requires { blob }");
7812
8343
  try {
7813
8344
  const counts = await applyImport(blob, passphrase, mode, deps, deps.parseProviderInput);
7814
8345
  return { status: 200, body: counts };
7815
8346
  } catch (error) {
7816
8347
  if (error instanceof WeakPassphraseError) {
7817
- return err6(400, error.message);
8348
+ return err7(400, error.message);
7818
8349
  }
7819
- return err6(400, error instanceof Error ? error.message : "import failed");
8350
+ return err7(400, error instanceof Error ? error.message : "import failed");
7820
8351
  }
7821
8352
  }
7822
8353
 
7823
8354
  // src/admin/usagePricing.ts
7824
8355
  import { getSharedUsageThroughputTracker } from "@omnicross/core/usage";
7825
- var err7 = (status, message) => ({
8356
+ var err8 = (status, message) => ({
7826
8357
  status,
7827
8358
  body: { error: { type: "admin_api_error", message } }
7828
8359
  });
@@ -7835,7 +8366,7 @@ function parseRange(query2) {
7835
8366
  const startTs = parseFiniteInt(query2.get("startTs"));
7836
8367
  const endTs = parseFiniteInt(query2.get("endTs"));
7837
8368
  if (startTs === null || endTs === null) {
7838
- return err7(400, "startTs and endTs are required finite-integer unix-millis query params");
8369
+ return err8(400, "startTs and endTs are required finite-integer unix-millis query params");
7839
8370
  }
7840
8371
  return { startTs, endTs };
7841
8372
  }
@@ -7860,14 +8391,14 @@ async function handleUsageGet(view, query2, deps) {
7860
8391
  case "timeseries": {
7861
8392
  const bucket = query2.get("bucket");
7862
8393
  if (bucket !== "hour" && bucket !== "day" && bucket !== "month") {
7863
- return err7(400, "bucket must be one of 'hour', 'day', 'month'");
8394
+ return err8(400, "bucket must be one of 'hour', 'day', 'month'");
7864
8395
  }
7865
8396
  const now = Date.now();
7866
8397
  const clamped = { startTs: range.startTs, endTs: Math.min(range.endTs, now) };
7867
8398
  if (clamped.startTs < clamped.endTs) {
7868
8399
  const projected = Math.ceil((clamped.endTs - clamped.startTs) / BUCKET_SPAN_MS[bucket]) + 1;
7869
8400
  if (projected > MAX_TIMESERIES_BUCKETS) {
7870
- return err7(
8401
+ return err8(
7871
8402
  400,
7872
8403
  `requested range projects ~${projected} '${bucket}' buckets (max ${MAX_TIMESERIES_BUCKETS}); narrow the range or use a coarser bucket`
7873
8404
  );
@@ -7890,7 +8421,7 @@ async function handleUsageGet(view, query2, deps) {
7890
8421
  };
7891
8422
  }
7892
8423
  default:
7893
- return err7(404, `unknown usage view '${view ?? ""}'`);
8424
+ return err8(404, `unknown usage view '${view ?? ""}'`);
7894
8425
  }
7895
8426
  }
7896
8427
  function poolKeyLabels(cfg) {
@@ -7939,7 +8470,7 @@ async function handlePricingList(deps) {
7939
8470
  async function handlePricingUpsert(body, deps) {
7940
8471
  const input = parsePricingEntryInput(body);
7941
8472
  if (!input) {
7942
- return err7(400, "invalid pricing entry (providerId, modelId, finite numeric inputPricePer1m/outputPricePer1m required)");
8473
+ return err8(400, "invalid pricing entry (providerId, modelId, finite numeric inputPricePer1m/outputPricePer1m required)");
7943
8474
  }
7944
8475
  const entry = await deps.pricingEngine.upsertManual(input);
7945
8476
  return { status: 200, body: { entry } };
@@ -7948,7 +8479,7 @@ async function handlePricingDelete(query2, deps) {
7948
8479
  const providerId = query2.get("providerId")?.trim() ?? "";
7949
8480
  const modelId = query2.get("modelId")?.trim() ?? "";
7950
8481
  if (!providerId || !modelId) {
7951
- return err7(400, "delete requires providerId and modelId query params");
8482
+ return err8(400, "delete requires providerId and modelId query params");
7952
8483
  }
7953
8484
  const deleted = await deps.pricingStore.delete(providerId, modelId);
7954
8485
  if (deleted) await deps.pricingEngine.invalidateCache();
@@ -7968,13 +8499,13 @@ async function handlePricingFetchLatest(deps) {
7968
8499
  }
7969
8500
  };
7970
8501
  } catch (e) {
7971
- return err7(502, `pricing-source fetch failed: ${e instanceof Error ? e.message : String(e)}`);
8502
+ return err8(502, `pricing-source fetch failed: ${e instanceof Error ? e.message : String(e)}`);
7972
8503
  }
7973
8504
  }
7974
8505
  async function handlePricingResolveConflicts(body, deps) {
7975
8506
  const raw = body["resolutions"];
7976
8507
  if (!Array.isArray(raw)) {
7977
- return err7(400, "resolve-conflicts requires { resolutions: [...] }");
8508
+ return err8(400, "resolve-conflicts requires { resolutions: [...] }");
7978
8509
  }
7979
8510
  const currentRows = await deps.pricingStore.getAll();
7980
8511
  const userEditedKeys = new Set(
@@ -7984,21 +8515,21 @@ async function handlePricingResolveConflicts(body, deps) {
7984
8515
  const pendingIncoming = /* @__PURE__ */ new Map();
7985
8516
  let staleCount = 0;
7986
8517
  for (const item of raw) {
7987
- if (!item || typeof item !== "object") return err7(400, "invalid resolution entry");
8518
+ if (!item || typeof item !== "object") return err8(400, "invalid resolution entry");
7988
8519
  const r = item;
7989
8520
  const action = r["action"];
7990
8521
  if (action !== "overwrite" && action !== "skip") {
7991
- return err7(400, "resolution action must be 'overwrite' or 'skip'");
8522
+ return err8(400, "resolution action must be 'overwrite' or 'skip'");
7992
8523
  }
7993
8524
  const providerId = typeof r["providerId"] === "string" && r["providerId"].trim() ? r["providerId"].trim() : "";
7994
8525
  const modelId = typeof r["modelId"] === "string" && r["modelId"].trim() ? r["modelId"].trim() : "";
7995
8526
  if (!providerId || !modelId) {
7996
- return err7(400, "each resolution requires top-level providerId and modelId");
8527
+ return err8(400, "each resolution requires top-level providerId and modelId");
7997
8528
  }
7998
8529
  const incoming = parsePricingEntryInput(r["incoming"]);
7999
- if (!incoming) return err7(400, "each resolution must echo a valid incoming pricing entry");
8530
+ if (!incoming) return err8(400, "each resolution must echo a valid incoming pricing entry");
8000
8531
  if (incoming.providerId !== providerId || incoming.modelId !== modelId) {
8001
- return err7(400, "resolution providerId/modelId must match the echoed incoming entry");
8532
+ return err8(400, "resolution providerId/modelId must match the echoed incoming entry");
8002
8533
  }
8003
8534
  const key = `${providerId}::${modelId}`;
8004
8535
  if (action === "overwrite" && !userEditedKeys.has(key)) {
@@ -8043,7 +8574,7 @@ function query(req) {
8043
8574
  }
8044
8575
  function allowanceProvider(value) {
8045
8576
  if (!value) return void 0;
8046
- return value === "claude" || value === "codex" || value === "kimi" || value === "opencodego" || value === "grok" || value === "copilot" || value === "gemini" ? value : null;
8577
+ return value === "claude" || value === "codex" || value === "kimi" || value === "opencodego" || value === "grok" || value === "copilot" || value === "gemini" || value === "antigravity" ? value : null;
8047
8578
  }
8048
8579
  async function handleAccountAllowanceApi(req, res, method, rest, service) {
8049
8580
  if (!service) return writeError2(res, 501, "account allowance service is not available");
@@ -8120,6 +8651,16 @@ async function handleAccountAllowanceApi(req, res, method, rest, service) {
8120
8651
  }
8121
8652
  return writeJson3(res, 200, { allowances: allowances2 });
8122
8653
  }
8654
+ if (requestedProvider === "antigravity") {
8655
+ if (!service.refreshAntigravity) {
8656
+ return writeError2(res, 501, "antigravity allowance refresh is not available");
8657
+ }
8658
+ const allowances2 = await service.refreshAntigravity(accountId);
8659
+ if (accountId && allowances2.length === 0) {
8660
+ return writeError2(res, 404, `Antigravity account '${accountId}' not found`);
8661
+ }
8662
+ return writeJson3(res, 200, { allowances: allowances2 });
8663
+ }
8123
8664
  if (requestedProvider === "gemini") {
8124
8665
  if (!service.refreshGemini) {
8125
8666
  return writeError2(res, 501, "gemini allowance refresh is not available");
@@ -8277,7 +8818,7 @@ async function handleAdminApi(req, res, path2, deps) {
8277
8818
  case "server":
8278
8819
  return await handleServer(req, res, method, deps);
8279
8820
  case "images":
8280
- return await handleImages(res, method, rest, deps);
8821
+ return await handleImages(req, res, method, rest, deps);
8281
8822
  case "search":
8282
8823
  return await handleSearchAdmin(req, res, method, rest, deps);
8283
8824
  case "accounts":
@@ -8303,8 +8844,8 @@ async function handleAdminApi(req, res, path2, deps) {
8303
8844
  default:
8304
8845
  return writeJsonError(res, 404, `unknown admin resource '${resource}'`);
8305
8846
  }
8306
- } catch (err8) {
8307
- writeJsonError(res, 500, err8 instanceof Error ? err8.message : String(err8));
8847
+ } catch (err9) {
8848
+ writeJsonError(res, 500, err9 instanceof Error ? err9.message : String(err9));
8308
8849
  }
8309
8850
  }
8310
8851
  function requestQuery(req) {
@@ -8479,7 +9020,7 @@ async function handleDiscoverModels(res, id, cfg) {
8479
9020
  const headers = { Accept: "application/json" };
8480
9021
  if (resolvedKey) headers["Authorization"] = `Bearer ${resolvedKey}`;
8481
9022
  Object.assign(headers, expandRowExtraHeaders(row));
8482
- const response = await fetchUpstream8(url, { method: "GET", headers }, { providerId: "byo" });
9023
+ const response = await fetchUpstream10(url, { method: "GET", headers }, { providerId: "byo" });
8483
9024
  if (!response.ok) {
8484
9025
  const text = await response.text().catch(() => "");
8485
9026
  let message = text.slice(0, 300);
@@ -8496,8 +9037,8 @@ async function handleDiscoverModels(res, id, cfg) {
8496
9037
  const data = await response.json();
8497
9038
  const models = Array.isArray(data?.data) ? data.data.map((m) => typeof m?.id === "string" ? m.id : "").filter((m) => m.length > 0) : [];
8498
9039
  return writeJson4(res, 200, { models });
8499
- } catch (err8) {
8500
- const message = err8 instanceof Error ? err8.message : String(err8);
9040
+ } catch (err9) {
9041
+ const message = err9 instanceof Error ? err9.message : String(err9);
8501
9042
  return writeJson4(res, 200, { models: [], error: `discovery failed: ${message}` });
8502
9043
  }
8503
9044
  }
@@ -8539,7 +9080,7 @@ async function handleTestModel(req, res, id, cfg) {
8539
9080
  Object.assign(headers, expandRowExtraHeaders(row));
8540
9081
  const startedAt = Date.now();
8541
9082
  try {
8542
- const response = await fetchUpstream8(
9083
+ const response = await fetchUpstream10(
8543
9084
  url,
8544
9085
  { method: "POST", headers, body: JSON.stringify(payload) },
8545
9086
  { providerId: "byo" }
@@ -8561,8 +9102,8 @@ async function handleTestModel(req, res, id, cfg) {
8561
9102
  latencyMs,
8562
9103
  sample: extractSampleText(text, row.apiFormat)
8563
9104
  });
8564
- } catch (err8) {
8565
- const message = err8 instanceof Error ? err8.message : String(err8);
9105
+ } catch (err9) {
9106
+ const message = err9 instanceof Error ? err9.message : String(err9);
8566
9107
  return writeJson4(res, 200, { ok: false, latencyMs: Date.now() - startedAt, message });
8567
9108
  }
8568
9109
  }
@@ -9147,8 +9688,8 @@ function imageConfigurationAuditFields(previous, next) {
9147
9688
  const after = next ?? DEFAULT_IMAGES_SERVER_CONFIG;
9148
9689
  const fields = [];
9149
9690
  if (before.enabled !== after.enabled) fields.push("enablement");
9150
- if (before.provider !== after.provider) fields.push("provider");
9151
- if (before.defaultModel !== after.defaultModel || !sameConfigValue(before.modelAliases, after.modelAliases)) fields.push("model");
9691
+ if (!sameConfigValue(before.models, after.models)) fields.push("provider");
9692
+ if (before.defaultModel !== after.defaultModel || !sameConfigValue(before.aliases, after.aliases) || !sameConfigValue(before.codex, after.codex)) fields.push("model");
9152
9693
  if (!sameConfigValue(before.account, after.account)) fields.push("account");
9153
9694
  if (!sameConfigValue(before.queue, after.queue)) fields.push("queue");
9154
9695
  if (!sameConfigValue(before.temporary, after.temporary)) fields.push("temporary");
@@ -9352,6 +9893,12 @@ async function handleAccounts(req, res, method, rest, deps) {
9352
9893
  deps.accountAllowanceService
9353
9894
  );
9354
9895
  }
9896
+ if (method === "GET" && rest[0] === "antigravity" && rest[1] === "models") {
9897
+ const result = await handleAntigravityModelsRoute({
9898
+ resolveAntigravityAccessToken: deps.resolveAntigravityAccessToken ?? (async () => null)
9899
+ });
9900
+ return writeJson4(res, result.status, result.body);
9901
+ }
9355
9902
  if (method === "GET" && rest.length === 0) {
9356
9903
  const accounts = await deps.subscriptionAccounts.listAll();
9357
9904
  const providerAccounts = await deps.subscriptionTokenWriter.listSanitizedAccounts();
@@ -9377,12 +9924,12 @@ async function handleAccounts(req, res, method, rest, deps) {
9377
9924
  }
9378
9925
  return writeJson4(res, 200, { ok: true, affected: result.affected });
9379
9926
  }
9380
- if (method === "GET" && (rest[0] === "codex" || rest[0] === "kimi" || rest[0] === "grok" || rest[0] === "copilot") && rest[1] === "oauth" && rest[3] === "status") {
9381
- const result = rest[0] === "codex" ? handleCodexOAuthStatus(rest[2], deps) : rest[0] === "kimi" ? handleKimiOAuthStatus(rest[2], deps) : rest[0] === "grok" ? handleGrokOAuthStatus(rest[2], deps) : handleCopilotOAuthStatus(rest[2], deps);
9927
+ if (method === "GET" && (rest[0] === "codex" || rest[0] === "kimi" || rest[0] === "grok" || rest[0] === "copilot" || rest[0] === "antigravity") && rest[1] === "oauth" && rest[3] === "status") {
9928
+ const result = rest[0] === "codex" ? handleCodexOAuthStatus(rest[2], deps) : rest[0] === "kimi" ? handleKimiOAuthStatus(rest[2], deps) : rest[0] === "grok" ? handleGrokOAuthStatus(rest[2], deps) : rest[0] === "copilot" ? handleCopilotOAuthStatus(rest[2], deps) : handleAntigravityOAuthStatus(rest[2], deps);
9382
9929
  return writeJson4(res, result.status, result.body);
9383
9930
  }
9384
- if (method === "DELETE" && (rest[0] === "codex" || rest[0] === "kimi" || rest[0] === "grok" || rest[0] === "copilot") && rest[1] === "oauth" && rest[2]) {
9385
- const result = rest[0] === "codex" ? handleCodexOAuthCancel(rest[2], deps) : rest[0] === "kimi" ? handleKimiOAuthCancel(rest[2], deps) : rest[0] === "grok" ? handleGrokOAuthCancel(rest[2], deps) : handleCopilotOAuthCancel(rest[2], deps);
9931
+ if (method === "DELETE" && (rest[0] === "codex" || rest[0] === "kimi" || rest[0] === "grok" || rest[0] === "copilot" || rest[0] === "antigravity") && rest[1] === "oauth" && rest[2]) {
9932
+ const result = rest[0] === "codex" ? handleCodexOAuthCancel(rest[2], deps) : rest[0] === "kimi" ? handleKimiOAuthCancel(rest[2], deps) : rest[0] === "grok" ? handleGrokOAuthCancel(rest[2], deps) : rest[0] === "copilot" ? handleCopilotOAuthCancel(rest[2], deps) : handleAntigravityOAuthCancel(rest[2], deps);
9386
9933
  return writeJson4(res, result.status, result.body);
9387
9934
  }
9388
9935
  if (method === "GET" && rest.length === 3 && rest[2] === "diagnostics") {
@@ -9452,6 +9999,10 @@ async function handleAccounts(req, res, method, rest, deps) {
9452
9999
  const result2 = await handleCopilotOAuthStart(deps, body2["enterpriseUrl"]);
9453
10000
  return writeJson4(res, result2.status, result2.body);
9454
10001
  }
10002
+ if (providerId === "antigravity") {
10003
+ const result2 = handleAntigravityOAuthStart(deps);
10004
+ return writeJson4(res, result2.status, result2.body);
10005
+ }
9455
10006
  const result = handleOAuthStart(providerId, deps);
9456
10007
  return writeJson4(res, result.status, result.body);
9457
10008
  }
@@ -9814,7 +10365,41 @@ function imageEndpointUrls(base) {
9814
10365
  edits: `${base}/v1/images/edits`
9815
10366
  }) : null;
9816
10367
  }
9817
- async function handleImages(res, method, rest, deps) {
10368
+ function imageProviderEvidence(images, capabilities) {
10369
+ const evidenceAt = safeStatusTimestamp(capabilities?.oldestEvidenceAt);
10370
+ const resolvedAt = safeStatusTimestamp(capabilities?.resolvedAt);
10371
+ if (evidenceAt === void 0 || resolvedAt === void 0) return null;
10372
+ const expiresAt = evidenceAt <= Number.MAX_SAFE_INTEGER - images.evidenceTtlMs ? evidenceAt + images.evidenceTtlMs : void 0;
10373
+ return Object.freeze({
10374
+ verifiedAt: evidenceAt,
10375
+ ageMs: Math.max(0, resolvedAt - evidenceAt),
10376
+ ...expiresAt !== void 0 ? { expiresAt } : {}
10377
+ });
10378
+ }
10379
+ async function handleImagesVerifyLive(req, res, deps) {
10380
+ const verifier = deps.imageLiveVerifier;
10381
+ if (!verifier) {
10382
+ return writeJsonError(res, 501, "Images live verification is not available");
10383
+ }
10384
+ const serverConfig = await loadServerConfig3(deps.settingsStore);
10385
+ const images = serverConfig.images ?? DEFAULT_IMAGES_SERVER_CONFIG;
10386
+ req.resume();
10387
+ const controller = new AbortController();
10388
+ req.on("close", () => controller.abort());
10389
+ const result = await verifier.verifyLive(images, controller.signal);
10390
+ const antigravityRouted = Object.values(images.models).includes("antigravity-subscription");
10391
+ return writeJson4(res, 200, {
10392
+ ...result,
10393
+ ...antigravityRouted ? { antigravityDeferred: true } : {}
10394
+ });
10395
+ }
10396
+ async function handleImages(req, res, method, rest, deps) {
10397
+ if (rest.length === 1 && rest[0] === "verify-live") {
10398
+ if (method !== "POST") {
10399
+ return writeJsonError(res, 405, `method ${method} not allowed on Images verify-live`);
10400
+ }
10401
+ return handleImagesVerifyLive(req, res, deps);
10402
+ }
9818
10403
  if (rest.length !== 1 || rest[0] !== "capabilities") {
9819
10404
  return writeJsonError(res, 404, "unknown Images admin resource");
9820
10405
  }
@@ -9829,14 +10414,14 @@ async function handleImages(res, method, rest, deps) {
9829
10414
  const capability = await reader.inspectCapability(IMAGE_ADMIN_STATUS_TENANT);
9830
10415
  const resources = safeRuntimeResources(reader.resourceStatus());
9831
10416
  const outbound = deps.outboundApiServer.getStatus();
9832
- const evidenceAt = safeStatusTimestamp(capability.capabilities?.oldestEvidenceAt);
9833
- const resolvedAt = safeStatusTimestamp(capability.capabilities?.resolvedAt);
9834
- const expiresAt = evidenceAt !== void 0 && evidenceAt <= Number.MAX_SAFE_INTEGER - images.evidenceTtlMs ? evidenceAt + images.evidenceTtlMs : void 0;
9835
- const evidence = evidenceAt !== void 0 && resolvedAt !== void 0 ? Object.freeze({
9836
- verifiedAt: evidenceAt,
9837
- ageMs: Math.max(0, resolvedAt - evidenceAt),
9838
- ...expiresAt !== void 0 ? { expiresAt } : {}
9839
- }) : null;
10417
+ const evidence = imageProviderEvidence(images, capability.capabilities);
10418
+ const providers = (capability.providers ?? []).map((provider) => Object.freeze({
10419
+ providerId: provider.providerId,
10420
+ available: provider.available === true,
10421
+ reason: provider.available ? null : safeImageCapabilityReason(provider.reason),
10422
+ models: Object.freeze([...provider.models]),
10423
+ evidence: imageProviderEvidence(images, provider.capabilities)
10424
+ }));
9840
10425
  const draining = lifecycle.draining.map((generation) => Object.freeze({
9841
10426
  generationId: safeImageGenerationId(generation.generationId),
9842
10427
  enabled: generation.enabled,
@@ -9846,7 +10431,7 @@ async function handleImages(res, method, rest, deps) {
9846
10431
  return writeJson4(res, 200, {
9847
10432
  configured: {
9848
10433
  enabled: images.enabled,
9849
- provider: images.provider,
10434
+ provider: images.models[images.defaultModel] ?? "codex-subscription",
9850
10435
  model: images.defaultModel,
9851
10436
  remoteUrlsEnabled: images.remote.enabled,
9852
10437
  referenceTtlMs: images.references.ttlMs
@@ -9857,6 +10442,7 @@ async function handleImages(res, method, rest, deps) {
9857
10442
  evidence,
9858
10443
  features: safeCapabilityValues(capability.capabilities, images.defaultModel)
9859
10444
  },
10445
+ providers,
9860
10446
  runtime: {
9861
10447
  disposed: lifecycle.disposed,
9862
10448
  generationId: safeImageGenerationId(lifecycle.current.generationId),
@@ -9946,12 +10532,12 @@ async function handlePlayground(req, res, method, deps) {
9946
10532
  const payload = body["body"];
9947
10533
  const status = deps.outboundApiServer.getStatus();
9948
10534
  if (!status.running || !status.port) return writeJsonError(res, 503, "outbound server not running");
9949
- const path2 = resolvePlaygroundPath(endpoint, isRecord7(payload) ? payload : {});
10535
+ const path2 = resolvePlaygroundPath(endpoint, isRecord9(payload) ? payload : {});
9950
10536
  if (!path2) return writeJsonError(res, 400, `unknown endpoint '${endpoint}'`);
9951
10537
  const upstreamBody = typeof payload === "string" ? payload : JSON.stringify(payload ?? {});
9952
10538
  await proxyToOutbound(res, status.port, path2, key, upstreamBody);
9953
10539
  }
9954
- function isRecord7(v) {
10540
+ function isRecord9(v) {
9955
10541
  return !!v && typeof v === "object" && !Array.isArray(v);
9956
10542
  }
9957
10543
  function proxyToOutbound(res, outboundPort, path2, key, body) {
@@ -9980,8 +10566,8 @@ function proxyToOutbound(res, outboundPort, path2, key, body) {
9980
10566
  });
9981
10567
  }
9982
10568
  );
9983
- upstream.on("error", (err8) => {
9984
- if (!res.headersSent) writeJsonError(res, 502, `playground proxy failed: ${err8.message}`);
10569
+ upstream.on("error", (err9) => {
10570
+ if (!res.headersSent) writeJsonError(res, 502, `playground proxy failed: ${err9.message}`);
9985
10571
  else res.end();
9986
10572
  resolve11();
9987
10573
  });
@@ -10086,7 +10672,7 @@ async function handleUiStatic(req, res, urlPath, uiDist) {
10086
10672
  }
10087
10673
 
10088
10674
  // src/admin/version.ts
10089
- var DAEMON_VERSION = true ? "0.4.2" : "0.0.0-dev";
10675
+ var DAEMON_VERSION = true ? "0.4.4" : "0.0.0-dev";
10090
10676
 
10091
10677
  // src/admin/AdminServer.ts
10092
10678
  var LOOPBACK_ADDR = "127.0.0.1";
@@ -10129,13 +10715,13 @@ var AdminServer = class {
10129
10715
  const server = http2.createServer((req, res) => {
10130
10716
  this.onRequest(req, res);
10131
10717
  });
10132
- const onError = (err8) => {
10133
- if (err8.code === "EADDRINUSE" && port !== 0) {
10718
+ const onError = (err9) => {
10719
+ if (err9.code === "EADDRINUSE" && port !== 0) {
10134
10720
  server.removeListener("error", onError);
10135
10721
  this.listen(bindAddr, 0).then(resolve11, reject);
10136
10722
  return;
10137
10723
  }
10138
- reject(err8);
10724
+ reject(err9);
10139
10725
  };
10140
10726
  server.on("error", onError);
10141
10727
  server.listen(port, bindAddr, () => {
@@ -10153,8 +10739,8 @@ var AdminServer = class {
10153
10739
  }
10154
10740
  /** Per-request handler: auth gate (when a token is set) → routing. */
10155
10741
  onRequest(req, res) {
10156
- void this.dispatch(req, res).catch((err8) => {
10157
- const message = err8 instanceof Error ? err8.message : String(err8);
10742
+ void this.dispatch(req, res).catch((err9) => {
10743
+ const message = err9 instanceof Error ? err9.message : String(err9);
10158
10744
  this.deps.logger.error("[AdminServer] unhandled error:", message);
10159
10745
  if (!res.headersSent) {
10160
10746
  res.writeHead(500, { "Content-Type": "application/json" });
@@ -10377,7 +10963,10 @@ var HTML_HEADERS = {
10377
10963
  function pageHtml(message) {
10378
10964
  return `<!doctype html><meta charset="utf-8"><title>omnicross login</title><body style="font-family:sans-serif;padding:2rem"><h2>${message}</h2><p>You can close this window and return to the terminal.</p></body>`;
10379
10965
  }
10380
- function awaitLoopbackCode(expectedState, timeoutMs = DEFAULT_TIMEOUT_MS, signal) {
10966
+ function awaitLoopbackCode(expectedState, timeoutMs = DEFAULT_TIMEOUT_MS, signal, binding = {}) {
10967
+ const port = binding.port ?? LOOPBACK_PORT;
10968
+ const callbackPath = binding.path ?? CALLBACK_PATH;
10969
+ const label = binding.label ?? "codex";
10381
10970
  return new Promise((resolve11, reject) => {
10382
10971
  let settled = false;
10383
10972
  const finish = (server2, fn) => {
@@ -10388,8 +10977,8 @@ function awaitLoopbackCode(expectedState, timeoutMs = DEFAULT_TIMEOUT_MS, signal
10388
10977
  server2.close();
10389
10978
  };
10390
10979
  const server = createServer2((req, res) => {
10391
- const url = new URL(req.url ?? "", `http://${LOOPBACK_HOST}:${LOOPBACK_PORT}`);
10392
- if (url.pathname !== CALLBACK_PATH) {
10980
+ const url = new URL(req.url ?? "", `http://${LOOPBACK_HOST}:${port}`);
10981
+ if (url.pathname !== callbackPath) {
10393
10982
  res.writeHead(404, HTML_HEADERS);
10394
10983
  res.end(pageHtml("Not found"));
10395
10984
  return;
@@ -10418,25 +11007,25 @@ function awaitLoopbackCode(expectedState, timeoutMs = DEFAULT_TIMEOUT_MS, signal
10418
11007
  return;
10419
11008
  }
10420
11009
  signal?.addEventListener("abort", abort, { once: true });
10421
- server.on("error", (err8) => {
11010
+ server.on("error", (err9) => {
10422
11011
  if (settled) return;
10423
11012
  settled = true;
10424
11013
  clearTimeout(timer);
10425
- if (err8.code === "EADDRINUSE") {
11014
+ if (err9.code === "EADDRINUSE") {
10426
11015
  reject(
10427
11016
  new Error(
10428
- `login: cannot bind ${LOOPBACK_HOST}:${LOOPBACK_PORT} (address in use) \u2014 another codex login or process is holding the port`
11017
+ `login: cannot bind ${LOOPBACK_HOST}:${port} (address in use) \u2014 another ${label} login or process is holding the port`
10429
11018
  )
10430
11019
  );
10431
11020
  } else {
10432
- reject(err8);
11021
+ reject(err9);
10433
11022
  }
10434
11023
  });
10435
11024
  const timer = setTimeout(() => {
10436
11025
  finish(server, () => reject(new Error(`login: timed out after ${Math.round(timeoutMs / 1e3)}s waiting for the callback`)));
10437
11026
  }, timeoutMs);
10438
11027
  if (typeof timer.unref === "function") timer.unref();
10439
- server.listen(LOOPBACK_PORT, LOOPBACK_HOST);
11028
+ server.listen(port, LOOPBACK_HOST);
10440
11029
  });
10441
11030
  }
10442
11031
 
@@ -10506,7 +11095,7 @@ function createPoolKeysLoader(getProviderRow, autoDisabled) {
10506
11095
 
10507
11096
  // src/allowance/ProviderKeyQuotaService.ts
10508
11097
  import { mergeExtraHeaders as mergeExtraHeaders2 } from "@omnicross/core";
10509
- import { fetchUpstream as fetchUpstream9 } from "@omnicross/core/pipeline/upstreamFetch";
11098
+ import { fetchUpstream as fetchUpstream11 } from "@omnicross/core/pipeline/upstreamFetch";
10510
11099
 
10511
11100
  // src/allowance/ProviderKeyQuota.ts
10512
11101
  var MINUTE_MS3 = 6e4;
@@ -10535,11 +11124,11 @@ function isoInstant3(value) {
10535
11124
  }
10536
11125
  return void 0;
10537
11126
  }
10538
- function secondsUntil8(instant, now) {
11127
+ function secondsUntil9(instant, now) {
10539
11128
  if (!instant) return void 0;
10540
11129
  return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
10541
11130
  }
10542
- function isRecord8(value) {
11131
+ function isRecord10(value) {
10543
11132
  return !!value && typeof value === "object" && !Array.isArray(value);
10544
11133
  }
10545
11134
  function detectProviderKeyQuotaAdapter(baseUrl) {
@@ -10606,17 +11195,17 @@ function zaiWindowIdLabel(durationMs) {
10606
11195
  return { id: "quota", label: "Quota" };
10607
11196
  }
10608
11197
  function parseZaiQuotaPayload(payload, now) {
10609
- if (!isRecord8(payload)) return null;
10610
- const data = isRecord8(payload["data"]) ? payload["data"] : payload;
11198
+ if (!isRecord10(payload)) return null;
11199
+ const data = isRecord10(payload["data"]) ? payload["data"] : payload;
10611
11200
  if (payload["success"] === false) return null;
10612
11201
  const limits = Array.isArray(data["limits"]) ? data["limits"] : [];
10613
11202
  const byWindow = /* @__PURE__ */ new Map();
10614
11203
  for (const raw of limits) {
10615
- if (!isRecord8(raw)) continue;
11204
+ if (!isRecord10(raw)) continue;
10616
11205
  const item = raw;
10617
11206
  if (item.type === void 0) continue;
10618
11207
  const details = raw["usageDetails"];
10619
- if (Array.isArray(details) && details.some((d) => isRecord8(d) && d["modelCode"] === "zread")) {
11208
+ if (Array.isArray(details) && details.some((d) => isRecord10(d) && d["modelCode"] === "zread")) {
10620
11209
  continue;
10621
11210
  }
10622
11211
  const durationMs = zaiWindowDurationMs(item);
@@ -10635,7 +11224,7 @@ function parseZaiQuotaPayload(payload, now) {
10635
11224
  usedPercent,
10636
11225
  ...durationMs !== void 0 ? { windowMinutes: Math.round(durationMs / MINUTE_MS3) } : {},
10637
11226
  ...resetsAt !== void 0 ? { resetsAt } : {},
10638
- remainingSeconds: secondsUntil8(resetsAt, now),
11227
+ remainingSeconds: secondsUntil9(resetsAt, now),
10639
11228
  state: "fresh"
10640
11229
  };
10641
11230
  const existing = byWindow.get(id);
@@ -10649,7 +11238,7 @@ function parseZaiQuotaPayload(payload, now) {
10649
11238
  var MINIMAX_STATUS_EXHAUSTED = 2;
10650
11239
  var MINIMAX_SHARED_BUCKET = "general";
10651
11240
  function parseMiniMaxBucket(value) {
10652
- if (!isRecord8(value)) return null;
11241
+ if (!isRecord10(value)) return null;
10653
11242
  const modelName = typeof value["model_name"] === "string" ? value["model_name"].trim() : "";
10654
11243
  if (!modelName) return null;
10655
11244
  const instant = (v) => {
@@ -10676,14 +11265,14 @@ function minimaxWindow(id, label, windowMinutes, resetsAtMs, remainingPercent, s
10676
11265
  usedPercent,
10677
11266
  ...windowMinutes !== void 0 ? { windowMinutes } : {},
10678
11267
  ...resetsAt !== void 0 ? { resetsAt } : {},
10679
- remainingSeconds: secondsUntil8(resetsAt, now),
11268
+ remainingSeconds: secondsUntil9(resetsAt, now),
10680
11269
  state: usedPercent !== null ? "fresh" : "unavailable"
10681
11270
  };
10682
11271
  }
10683
11272
  function parseMiniMaxTokenPlanPayload(payload, now) {
10684
- if (!isRecord8(payload)) return null;
11273
+ if (!isRecord10(payload)) return null;
10685
11274
  const baseResp = payload["base_resp"];
10686
- if (!isRecord8(baseResp) || baseResp["status_code"] !== 0) return null;
11275
+ if (!isRecord10(baseResp) || baseResp["status_code"] !== 0) return null;
10687
11276
  const buckets = Array.isArray(payload["model_remains"]) ? payload["model_remains"] : [];
10688
11277
  let general = null;
10689
11278
  for (const raw of buckets) {
@@ -10716,11 +11305,11 @@ function parseMiniMaxTokenPlanPayload(payload, now) {
10716
11305
  ];
10717
11306
  }
10718
11307
  function parseUmansUsagePayload(payload, now) {
10719
- if (!isRecord8(payload)) return null;
10720
- const limits = isRecord8(payload["limits"]) ? payload["limits"] : void 0;
10721
- const requests = limits && isRecord8(limits["requests"]) ? limits["requests"] : void 0;
10722
- const usage = isRecord8(payload["usage"]) ? payload["usage"] : void 0;
10723
- const window = isRecord8(payload["window"]) ? payload["window"] : void 0;
11308
+ if (!isRecord10(payload)) return null;
11309
+ const limits = isRecord10(payload["limits"]) ? payload["limits"] : void 0;
11310
+ const requests = limits && isRecord10(limits["requests"]) ? limits["requests"] : void 0;
11311
+ const usage = isRecord10(payload["usage"]) ? payload["usage"] : void 0;
11312
+ const window = isRecord10(payload["window"]) ? payload["window"] : void 0;
10724
11313
  const hardCap = finiteNumber5(requests?.["hard_cap"]);
10725
11314
  const softLimit = finiteNumber5(requests?.["limit"]);
10726
11315
  const requestsInWindow = finiteNumber5(usage?.["requests_in_window"]);
@@ -10741,15 +11330,15 @@ function parseUmansUsagePayload(payload, now) {
10741
11330
  usedPercent,
10742
11331
  windowMinutes: 5 * 60,
10743
11332
  ...resetsAt !== void 0 ? { resetsAt } : {},
10744
- remainingSeconds: secondsUntil8(resetsAt, now),
11333
+ remainingSeconds: secondsUntil9(resetsAt, now),
10745
11334
  state: "fresh"
10746
11335
  }
10747
11336
  ];
10748
11337
  }
10749
11338
  function parseSyntheticQuotasPayload(payload, now) {
10750
- if (!isRecord8(payload)) return null;
10751
- const fiveHour = isRecord8(payload["rollingFiveHourLimit"]) ? payload["rollingFiveHourLimit"] : void 0;
10752
- const weekly = isRecord8(payload["weeklyTokenLimit"]) ? payload["weeklyTokenLimit"] : void 0;
11339
+ if (!isRecord10(payload)) return null;
11340
+ const fiveHour = isRecord10(payload["rollingFiveHourLimit"]) ? payload["rollingFiveHourLimit"] : void 0;
11341
+ const weekly = isRecord10(payload["weeklyTokenLimit"]) ? payload["weeklyTokenLimit"] : void 0;
10753
11342
  const windows = [];
10754
11343
  if (fiveHour) {
10755
11344
  const max = finiteNumber5(fiveHour["max"]);
@@ -10763,7 +11352,7 @@ function parseSyntheticQuotasPayload(payload, now) {
10763
11352
  usedPercent,
10764
11353
  windowMinutes: 5 * 60,
10765
11354
  ...resetsAt !== void 0 ? { resetsAt } : {},
10766
- remainingSeconds: secondsUntil8(resetsAt, now),
11355
+ remainingSeconds: secondsUntil9(resetsAt, now),
10767
11356
  state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
10768
11357
  });
10769
11358
  }
@@ -10778,7 +11367,7 @@ function parseSyntheticQuotasPayload(payload, now) {
10778
11367
  usedPercent,
10779
11368
  windowMinutes: 7 * 24 * 60,
10780
11369
  ...resetsAt !== void 0 ? { resetsAt } : {},
10781
- remainingSeconds: secondsUntil8(resetsAt, now),
11370
+ remainingSeconds: secondsUntil9(resetsAt, now),
10782
11371
  state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
10783
11372
  });
10784
11373
  }
@@ -10790,12 +11379,12 @@ var CLINE_WINDOW_CONFIG = {
10790
11379
  monthly: { id: "thirty-day", label: "30 days", minutes: 30 * 24 * 60 }
10791
11380
  };
10792
11381
  function parseClinePassUsageLimitsPayload(payload, now) {
10793
- if (!isRecord8(payload)) return null;
10794
- const data = isRecord8(payload["data"]) ? payload["data"] : payload;
11382
+ if (!isRecord10(payload)) return null;
11383
+ const data = isRecord10(payload["data"]) ? payload["data"] : payload;
10795
11384
  const limits = Array.isArray(data["limits"]) ? data["limits"] : [];
10796
11385
  const windows = [];
10797
11386
  for (const raw of limits) {
10798
- if (!isRecord8(raw)) continue;
11387
+ if (!isRecord10(raw)) continue;
10799
11388
  const config = CLINE_WINDOW_CONFIG[typeof raw["type"] === "string" ? raw["type"] : ""];
10800
11389
  if (!config) continue;
10801
11390
  const usedPercent = finitePercent4(raw["percentUsed"]);
@@ -10808,7 +11397,7 @@ function parseClinePassUsageLimitsPayload(payload, now) {
10808
11397
  usedPercent,
10809
11398
  windowMinutes: config.minutes,
10810
11399
  ...resetsAt !== void 0 ? { resetsAt } : {},
10811
- remainingSeconds: secondsUntil8(resetsAt, now),
11400
+ remainingSeconds: secondsUntil9(resetsAt, now),
10812
11401
  state: "fresh"
10813
11402
  });
10814
11403
  }
@@ -10847,7 +11436,7 @@ function rowKeyEntries(row) {
10847
11436
  return [];
10848
11437
  }
10849
11438
  var ProviderKeyQuotaService = class {
10850
- constructor(box, fetchImpl = (url, init) => fetchUpstream9(url, init, { redactBodies: true }), now = Date.now) {
11439
+ constructor(box, fetchImpl = (url, init) => fetchUpstream11(url, init, { redactBodies: true }), now = Date.now) {
10851
11440
  this.box = box;
10852
11441
  this.fetchImpl = fetchImpl;
10853
11442
  this.now = now;
@@ -11421,12 +12010,12 @@ function createImageDoctorService(options) {
11421
12010
  authStrategy: strategy,
11422
12011
  generationTimeoutMs: config.queue.generationTimeoutMs
11423
12012
  }));
11424
- const readAccount = async () => {
11425
- const codex = (await options.subscriptionAccounts.listAll()).find((entry) => entry.providerId === "codex");
12013
+ const readAccount = async (providerId) => {
12014
+ const entry = (await options.subscriptionAccounts.listAll()).find((candidate) => candidate.providerId === providerId);
11426
12015
  return Object.freeze({
11427
- present: codex !== void 0,
11428
- usable: codex?.credentialStatus.ok === true,
11429
- reason: codex === void 0 ? "missing" : codex.credentialStatus.ok ? "ready" : "unavailable"
12016
+ present: entry !== void 0,
12017
+ usable: entry?.credentialStatus.ok === true,
12018
+ reason: entry === void 0 ? "missing" : entry.credentialStatus.ok ? "ready" : "unavailable"
11430
12019
  });
11431
12020
  };
11432
12021
  const activePaths = () => options.storageCatalog.active().resolver;
@@ -11464,6 +12053,7 @@ function createImageDoctorService(options) {
11464
12053
  } catch {
11465
12054
  storesValid = false;
11466
12055
  }
12056
+ const antigravityAccount = await readAccount("antigravity");
11467
12057
  const rows = await options.keyDb.outboundApiKeysList();
11468
12058
  let legacyRows = 0;
11469
12059
  let invalidRows = 0;
@@ -11480,7 +12070,7 @@ function createImageDoctorService(options) {
11480
12070
  invalidRows += 1;
11481
12071
  }
11482
12072
  }
11483
- const account = await readAccount();
12073
+ const account = await readAccount("codex");
11484
12074
  let evidence;
11485
12075
  let evidenceStore;
11486
12076
  try {
@@ -11494,10 +12084,11 @@ function createImageDoctorService(options) {
11494
12084
  return Object.freeze({
11495
12085
  config: Object.freeze({
11496
12086
  enabled: config.enabled,
11497
- provider: config.provider,
12087
+ provider: config.models[config.defaultModel] ?? "codex-subscription",
11498
12088
  model: config.defaultModel,
11499
12089
  valid: configErrors.length === 0,
11500
- errorCount: configErrors.length
12090
+ errorCount: configErrors.length,
12091
+ routedProviders: Object.freeze([...new Set(Object.values(config.models))])
11501
12092
  }),
11502
12093
  roots: Object.freeze({
11503
12094
  valid: verifiedAreas === ROOT_AREAS.length,
@@ -11522,12 +12113,13 @@ function createImageDoctorService(options) {
11522
12113
  imagesAuthorizedRows
11523
12114
  }),
11524
12115
  account,
12116
+ antigravityAccount,
11525
12117
  evidence: Object.freeze(evidence)
11526
12118
  });
11527
12119
  },
11528
12120
  verifyLive: async (config, signal) => {
11529
12121
  if (!config.enabled) return Object.freeze({ ok: false, code: "images_disabled" });
11530
- const account = await readAccount();
12122
+ const account = await readAccount("codex");
11531
12123
  if (!account.usable) {
11532
12124
  return Object.freeze({ ok: false, code: "codex_account_unavailable" });
11533
12125
  }
@@ -11788,6 +12380,7 @@ import {
11788
12380
  validateImagesServerConfig as validateImagesServerConfig3
11789
12381
  } from "@omnicross/core/outbound-api";
11790
12382
  import {
12383
+ createAntigravitySubscriptionImageProvider,
11791
12384
  createCodexSubscriptionImageProvider
11792
12385
  } from "@omnicross/subscriptions";
11793
12386
 
@@ -11819,10 +12412,11 @@ function createTrustedImageApiRuntimeResolver(options) {
11819
12412
  throw new TypeError("enabled image remote loading requires a proven resolver");
11820
12413
  }
11821
12414
  const hmacKey = Buffer.from(options.hmacKey);
11822
- const modelAliases = new Map(Object.entries(options.config.modelAliases));
12415
+ const modelAliases = new Map(Object.entries(options.config.aliases));
12416
+ const modelRoutes = new Map(Object.entries(options.config.models));
11823
12417
  const limits = Object.freeze({ ...options.config.limits });
11824
- const providerId = options.config.provider;
11825
12418
  const defaultModel = options.config.defaultModel;
12419
+ const providerId = modelRoutes.get(defaultModel) ?? "codex-subscription";
11826
12420
  const referenceStore = options.referenceStore;
11827
12421
  const retention = Object.freeze({
11828
12422
  enabled: true,
@@ -11843,6 +12437,7 @@ function createTrustedImageApiRuntimeResolver(options) {
11843
12437
  providerId,
11844
12438
  defaultModel,
11845
12439
  modelAliases,
12440
+ modelRoutes,
11846
12441
  limits,
11847
12442
  ...preferredAccountId ? { preferredAccountId } : {},
11848
12443
  ...preferredAccountGroup ? { preferredAccountGroup } : {},
@@ -12247,7 +12842,9 @@ var GENERATION_ID = /^[A-Za-z0-9][A-Za-z0-9_.:-]{0,127}$/u;
12247
12842
  function snapshotConfig(config) {
12248
12843
  return {
12249
12844
  ...config,
12250
- modelAliases: { ...config.modelAliases },
12845
+ models: { ...config.models },
12846
+ aliases: { ...config.aliases },
12847
+ codex: { ...config.codex },
12251
12848
  account: { ...config.account },
12252
12849
  queue: { ...config.queue },
12253
12850
  temporary: { ...config.temporary },
@@ -12281,10 +12878,15 @@ function createImageRuntimeGeneration(options) {
12281
12878
  }
12282
12879
  });
12283
12880
  }
12284
- const authStrategy = options.subscriptionAccounts.getStrategy("codex");
12285
- if (!authStrategy || authStrategy.providerId !== "codex") {
12881
+ const routedProviders = [...new Set(Object.values(config.models))];
12882
+ const codexStrategy = routedProviders.includes("codex-subscription") ? options.subscriptionAccounts.getStrategy("codex") : void 0;
12883
+ if (routedProviders.includes("codex-subscription") && (!codexStrategy || codexStrategy.providerId !== "codex")) {
12286
12884
  throw new TypeError("enabled image runtime requires the Codex subscription strategy");
12287
12885
  }
12886
+ const antigravityStrategy = routedProviders.includes("antigravity-subscription") ? options.subscriptionAccounts.getStrategy("antigravity") : void 0;
12887
+ if (routedProviders.includes("antigravity-subscription") && (!antigravityStrategy || antigravityStrategy.providerId !== "antigravity")) {
12888
+ throw new TypeError("enabled image runtime requires the Antigravity subscription strategy");
12889
+ }
12288
12890
  const privateHmacKey = options.privateHmacKey ? Buffer.from(options.privateHmacKey) : loadOrCreateImageTenantHmacSalt(options.storage.paths, randomBytes6);
12289
12891
  if (privateHmacKey.byteLength !== 32) {
12290
12892
  privateHmacKey.fill(0);
@@ -12319,23 +12921,32 @@ function createImageRuntimeGeneration(options) {
12319
12921
  if (options.testOnlySyntheticVerifiedProvider && options.testOnlySyntheticVerifiedProvider.label !== "synthetic-verified-image-provider-test-only") {
12320
12922
  throw new TypeError("synthetic verified image provider test seam label is invalid");
12321
12923
  }
12322
- const provider = options.testOnlySyntheticVerifiedProvider ? options.testOnlySyntheticVerifiedProvider.createProvider({
12924
+ const providers = options.testOnlySyntheticVerifiedProvider ? [options.testOnlySyntheticVerifiedProvider.createProvider({
12323
12925
  generationId: options.generationId,
12324
12926
  scheduler,
12325
12927
  now: options.now ?? Date.now,
12326
12928
  referenceStore: options.storage.referenceStore,
12327
12929
  stateStore: options.storage.stateStore
12328
- }) : createCodexSubscriptionImageProvider({
12329
- authStrategy,
12930
+ })] : routedProviders.map((providerId) => providerId === "codex-subscription" ? createCodexSubscriptionImageProvider({
12931
+ authStrategy: codexStrategy,
12330
12932
  evidenceSource: generationEvidenceSource,
12331
12933
  executionScheduler: scheduler,
12332
12934
  generationTimeoutMs: config.queue.generationTimeoutMs,
12935
+ now: options.now,
12936
+ wire: {
12937
+ imageModel: config.codex.imageModel,
12938
+ carrierModel: config.codex.carrierModel
12939
+ }
12940
+ }) : createAntigravitySubscriptionImageProvider({
12941
+ authStrategy: antigravityStrategy,
12942
+ executionScheduler: scheduler,
12943
+ generationTimeoutMs: config.queue.generationTimeoutMs,
12333
12944
  now: options.now
12334
- });
12335
- if (provider.id !== config.provider) {
12945
+ }));
12946
+ if (providers.length === 1 && providers[0].id !== "codex-subscription") {
12336
12947
  throw new TypeError("synthetic verified image provider id must match configured provider");
12337
12948
  }
12338
- const providerRegistry = new ImageProviderRegistry([provider]);
12949
+ const providerRegistry = new ImageProviderRegistry(providers);
12339
12950
  const orchestrator = new ImageOrchestrator({
12340
12951
  registry: providerRegistry,
12341
12952
  referenceStore: options.storage.referenceStore,
@@ -12357,35 +12968,72 @@ function createImageRuntimeGeneration(options) {
12357
12968
  ...options.createCallId ? { createCallId: options.createCallId } : {},
12358
12969
  ...options.now ? { now: options.now } : {}
12359
12970
  });
12971
+ const defaultProviderId = config.models[config.defaultModel] ?? "codex-subscription";
12972
+ const inspectOneProvider = async (providerId, apiKeyId) => {
12973
+ const capabilities = await orchestrator.getCapabilities(providerId, {
12974
+ requestId: `${options.generationId}:capability-inspection`,
12975
+ tenantId: apiKeyId,
12976
+ signal: new AbortController().signal,
12977
+ sessionKey: `outbound:images:${apiKeyId}`,
12978
+ ...config.account.id ? { preferredAccountId: config.account.id } : {},
12979
+ ...config.account.group ? { preferredAccountGroup: config.account.group } : {},
12980
+ boundAccountFallbackPolicy: config.account.fallback
12981
+ });
12982
+ return capabilities;
12983
+ };
12360
12984
  const inspectCapability = async (apiKeyId) => {
12361
- try {
12362
- const capabilities = await orchestrator.getCapabilities(config.provider, {
12363
- requestId: `${options.generationId}:capability-inspection`,
12364
- tenantId: apiKeyId,
12365
- signal: new AbortController().signal,
12366
- sessionKey: `outbound:images:${apiKeyId}`,
12367
- ...config.account.id ? { preferredAccountId: config.account.id } : {},
12368
- ...config.account.group ? { preferredAccountGroup: config.account.group } : {},
12369
- boundAccountFallbackPolicy: config.account.fallback
12370
- });
12371
- const available = capabilities.available === true && capabilities.generate === true && capabilities.models.includes(config.defaultModel);
12372
- return Object.freeze({
12373
- enabled: true,
12374
- available,
12375
- providerId: config.provider,
12376
- model: config.defaultModel,
12377
- ...!available ? { reason: capabilities.reason ?? "runtime_unavailable" } : {},
12378
- capabilities
12379
- });
12380
- } catch (error) {
12985
+ const providerCapabilities = /* @__PURE__ */ new Map();
12986
+ let defaultProviderError;
12987
+ const providerRows = [];
12988
+ for (const providerId of [...new Set(Object.values(config.models))]) {
12989
+ try {
12990
+ const capabilities2 = await inspectOneProvider(providerId, apiKeyId);
12991
+ providerCapabilities.set(providerId, capabilities2);
12992
+ const affirmed = capabilities2.available === true && capabilities2.generate === true;
12993
+ providerRows.push({
12994
+ providerId,
12995
+ available: affirmed,
12996
+ ...!affirmed ? { reason: capabilities2.reason ?? "runtime_unavailable" } : {},
12997
+ models: affirmed ? Object.entries(config.models).filter(([model, modelProvider]) => modelProvider === providerId && capabilities2.models.includes(model)).map(([model]) => model) : [],
12998
+ capabilities: capabilities2
12999
+ });
13000
+ } catch (error) {
13001
+ if (providerId === defaultProviderId) defaultProviderError = error;
13002
+ providerRows.push({
13003
+ providerId,
13004
+ available: false,
13005
+ reason: error instanceof ImageGenerationError4 && (error.code === "upstream_auth_required" || error.code === "invalid_api_key") ? "account_unverified" : "runtime_unavailable",
13006
+ models: []
13007
+ });
13008
+ }
13009
+ }
13010
+ const providers2 = Object.freeze(providerRows);
13011
+ const routedModels = Object.freeze(
13012
+ providerRows.flatMap((row) => row.available ? row.models : [])
13013
+ );
13014
+ const capabilities = providerCapabilities.get(defaultProviderId);
13015
+ if (!capabilities) {
12381
13016
  return Object.freeze({
12382
13017
  enabled: true,
12383
13018
  available: false,
12384
- providerId: config.provider,
13019
+ providerId: defaultProviderId,
12385
13020
  model: config.defaultModel,
12386
- reason: error instanceof ImageGenerationError4 && (error.code === "upstream_auth_required" || error.code === "invalid_api_key") ? "account_unverified" : "runtime_unavailable"
13021
+ routedModels,
13022
+ providers: providers2,
13023
+ reason: defaultProviderError instanceof ImageGenerationError4 && (defaultProviderError.code === "upstream_auth_required" || defaultProviderError.code === "invalid_api_key") ? "account_unverified" : "runtime_unavailable"
12387
13024
  });
12388
13025
  }
13026
+ const available = capabilities.available === true && capabilities.generate === true && capabilities.models.includes(config.defaultModel);
13027
+ return Object.freeze({
13028
+ enabled: true,
13029
+ available,
13030
+ providerId: defaultProviderId,
13031
+ model: config.defaultModel,
13032
+ routedModels,
13033
+ providers: providers2,
13034
+ ...!available ? { reason: capabilities.reason ?? "runtime_unavailable" } : {},
13035
+ capabilities
13036
+ });
12389
13037
  };
12390
13038
  const resolverToDispose = runtimeResolver;
12391
13039
  const schedulerToDispose = scheduler;
@@ -12423,7 +13071,7 @@ function createImageRuntimeGeneration(options) {
12423
13071
  imageApi,
12424
13072
  hosted,
12425
13073
  hostedRuntime: Object.freeze({
12426
- providerId: config.provider,
13074
+ providerId: defaultProviderId,
12427
13075
  imageModel: config.defaultModel,
12428
13076
  referenceTtlMs: config.references.ttlMs,
12429
13077
  maxOutputBytes: config.limits.maxOutputBytes,
@@ -15420,6 +16068,9 @@ var ImageRuntimeManager = class {
15420
16068
  }
15421
16069
  async listAvailableModels(apiKeyId) {
15422
16070
  const inspection = await this.inspectCapability(apiKeyId);
16071
+ if (inspection.routedModels !== void 0) {
16072
+ return Object.freeze([...inspection.routedModels]);
16073
+ }
15423
16074
  return inspection.available && inspection.model === "gpt-image-2" ? Object.freeze([inspection.model]) : Object.freeze([]);
15424
16075
  }
15425
16076
  resourceStatus() {
@@ -17635,11 +18286,13 @@ var JsonVoucherDb = class {
17635
18286
  // src/ports/JsonSubscriptionCredentialStore.ts
17636
18287
  import { existsSync as existsSync24, mkdirSync as mkdirSync6, readFileSync as readFileSync20, renameSync as renameSync13 } from "fs";
17637
18288
  import { dirname as dirname15 } from "path";
18289
+ import { getAntigravityProjectResolver as getAntigravityProjectResolver2 } from "@omnicross/core/auth/GeminiCodeAssistProjectResolver";
17638
18290
  import { getSharedAccountHealth as getSharedAccountHealth2 } from "@omnicross/core/pipeline/SubscriptionAccountHealth";
17639
18291
  import { getSharedAccountAllowanceScheduling as getSharedAccountAllowanceScheduling3 } from "@omnicross/core/pipeline/AccountAllowanceScheduling";
17640
- import { fetchUpstream as fetchUpstream10 } from "@omnicross/core/pipeline/upstreamFetch";
18292
+ import { fetchUpstream as fetchUpstream12 } from "@omnicross/core/pipeline/upstreamFetch";
17641
18293
  import { getSharedIdentityStore as getSharedIdentityStore2 } from "@omnicross/core/provider-proxy/identity/SubscriptionIdentityStore";
17642
18294
  import {
18295
+ antigravityOAuth as antigravityOAuth2,
17643
18296
  claudeOAuth as claudeOAuth2,
17644
18297
  codexOAuth as codexOAuth2,
17645
18298
  geminiOAuth as geminiOAuth2,
@@ -17793,7 +18446,7 @@ var JsonSubscriptionCredentialStore = class {
17793
18446
  * a plaintext token pair into `upstream-trace.jsonl`.
17794
18447
  */
17795
18448
  buildRefreshFetch(providerId, accountId) {
17796
- return this.fetchImpl ?? ((url, init) => fetchUpstream10(url, init, { providerId, accountId, redactBodies: true }));
18449
+ return this.fetchImpl ?? ((url, init) => fetchUpstream12(url, init, { providerId, accountId, redactBodies: true }));
17797
18450
  }
17798
18451
  /**
17799
18452
  * In-flight refresh coalescing. OAuth refresh tokens are
@@ -17834,7 +18487,7 @@ var JsonSubscriptionCredentialStore = class {
17834
18487
  * other hot reads. Never returns token material.
17835
18488
  */
17836
18489
  getAccountProxy(providerId, accountId) {
17837
- if (providerId !== "claude" && providerId !== "codex" && providerId !== "gemini" && providerId !== "opencodego" && providerId !== "kimi" && providerId !== "grok" && providerId !== "copilot") {
18490
+ if (providerId !== "claude" && providerId !== "codex" && providerId !== "gemini" && providerId !== "opencodego" && providerId !== "kimi" && providerId !== "grok" && providerId !== "copilot" && providerId !== "antigravity") {
17838
18491
  return void 0;
17839
18492
  }
17840
18493
  return getAccountProxy(this.readConfig(), providerId, accountId);
@@ -17853,7 +18506,7 @@ var JsonSubscriptionCredentialStore = class {
17853
18506
  const fingerprintOn = identityStore.isEnabled();
17854
18507
  const now = Date.now();
17855
18508
  const out = {};
17856
- for (const provider of ["claude", "codex", "gemini", "opencodego", "kimi", "grok", "copilot"]) {
18509
+ for (const provider of ["claude", "codex", "gemini", "opencodego", "kimi", "grok", "copilot", "antigravity"]) {
17857
18510
  const sanitized = sanitizeAccounts(config, provider);
17858
18511
  if (sanitized.length === 0) continue;
17859
18512
  for (const account of sanitized) {
@@ -18112,6 +18765,76 @@ var JsonSubscriptionCredentialStore = class {
18112
18765
  return false;
18113
18766
  });
18114
18767
  }
18768
+ /**
18769
+ * Refresh the Antigravity (Google) OAuth access token. Like gemini, the
18770
+ * Google token endpoint does NOT return a refresh_token on refresh, so this
18771
+ * writes ONLY access+expiresAt (+status/lastRefreshedAt) and DELIBERATELY
18772
+ * preserves the stored `refreshToken` — plus the account's `projectId`
18773
+ * (a handshake product; the post-refresh re-validation is the refresh
18774
+ * scheduler's hook, not this write) and `email`. HONEST `false` when no
18775
+ * refresh_token.
18776
+ */
18777
+ async refreshAntigravityToken() {
18778
+ return this.coalesce("antigravity:active", async () => {
18779
+ const config = this.readConfig();
18780
+ const active = getActiveAccount(config, "antigravity");
18781
+ const antigravity = active?.tokens;
18782
+ if (!active || !antigravity?.refreshToken) return false;
18783
+ const capturedId = active.id;
18784
+ this.materializeMigration(config);
18785
+ const refreshFetch = this.buildRefreshFetch("antigravity", capturedId);
18786
+ try {
18787
+ const result = await antigravityOAuth2.refreshAccessToken(antigravity.refreshToken, refreshFetch);
18788
+ const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
18789
+ const next = {
18790
+ ...antigravity,
18791
+ // KEEP the existing refreshToken/projectId/email.
18792
+ accessToken: result.accessToken,
18793
+ expiresAt,
18794
+ status: "authorized",
18795
+ lastRefreshedAt: (/* @__PURE__ */ new Date()).toISOString(),
18796
+ errorMessage: void 0
18797
+ };
18798
+ this.writeBackById("antigravity", capturedId, next);
18799
+ await this.revalidateAntigravityProject(capturedId);
18800
+ return true;
18801
+ } catch (error) {
18802
+ this.markExpiredById("antigravity", capturedId, antigravity, error);
18803
+ return false;
18804
+ }
18805
+ });
18806
+ }
18807
+ /**
18808
+ * Post-refresh project re-validation hook (antigravity design D8): after a
18809
+ * successful antigravity token refresh, re-run the Code Assist project
18810
+ * handshake and write the (possibly rotated) `projectId` back to the account.
18811
+ * A handshake FAILURE keeps the stored projectId untouched (logged) so the
18812
+ * account keeps serving with the last-known-good project until a later
18813
+ * refresh succeeds. Returns whether the handshake produced a project.
18814
+ */
18815
+ async revalidateAntigravityProject(accountId) {
18816
+ const before = getAccountById(this.readConfig(), "antigravity", accountId);
18817
+ const accessToken = before?.tokens?.accessToken;
18818
+ if (!accessToken) return false;
18819
+ try {
18820
+ const projectId = await getAntigravityProjectResolver2().resolveProject(accessToken);
18821
+ if (projectId !== void 0) {
18822
+ const config = this.readConfig();
18823
+ const account = getAccountById(config, "antigravity", accountId);
18824
+ const tokens = account?.tokens;
18825
+ if (account && tokens?.accessToken === accessToken && tokens.projectId !== projectId) {
18826
+ this.writeBackById("antigravity", accountId, { ...tokens, projectId });
18827
+ }
18828
+ return true;
18829
+ }
18830
+ return false;
18831
+ } catch (error) {
18832
+ console.warn(
18833
+ `[JsonSubscriptionCredentialStore] antigravity project re-validation failed for account ${accountId}: ` + (error instanceof Error ? error.message : String(error))
18834
+ );
18835
+ return false;
18836
+ }
18837
+ }
18115
18838
  /**
18116
18839
  * Refresh a SPECIFIC managed account by id (background scheduler sweep and
18117
18840
  * account-pool resolution). It uses only that account's stored refresh
@@ -18140,6 +18863,7 @@ var JsonSubscriptionCredentialStore = class {
18140
18863
  };
18141
18864
  if (refreshed.idToken) next.idToken = refreshed.idToken;
18142
18865
  this.writeBackById(provider, id, next);
18866
+ if (provider === "antigravity") await this.revalidateAntigravityProject(id);
18143
18867
  return true;
18144
18868
  } catch (error) {
18145
18869
  this.markExpiredById(provider, id, captured, error);
@@ -18164,7 +18888,7 @@ var JsonSubscriptionCredentialStore = class {
18164
18888
  }
18165
18889
  const oauth = account.tokens;
18166
18890
  if (!oauth.accessToken) return null;
18167
- if (providerId === "codex" || providerId === "gemini" || providerId === "kimi" || providerId === "grok" || providerId === "copilot") {
18891
+ if (providerId === "codex" || providerId === "gemini" || providerId === "kimi" || providerId === "grok" || providerId === "copilot" || providerId === "antigravity") {
18168
18892
  const expiresAtMs = oauth.expiresAt ? Date.parse(oauth.expiresAt) : 0;
18169
18893
  const expiringSoon = expiresAtMs > 0 && Date.now() >= expiresAtMs - ACCOUNT_REFRESH_LEAD_MS;
18170
18894
  if (expiringSoon && oauth.refreshToken) {
@@ -18280,6 +19004,13 @@ var JsonSubscriptionCredentialStore = class {
18280
19004
  if (provider === "copilot") {
18281
19005
  throw new Error("GitHub Copilot tokens cannot be refreshed \u2014 re-authenticate the account");
18282
19006
  }
19007
+ if (provider === "antigravity") {
19008
+ const r2 = await antigravityOAuth2.refreshAccessToken(refreshToken, refreshFetch);
19009
+ return {
19010
+ accessToken: r2.accessToken,
19011
+ expiresAt: new Date(Date.now() + r2.expiresIn * 1e3).toISOString()
19012
+ };
19013
+ }
18283
19014
  const flow = provider === "claude" ? claudeOAuth2 : provider === "codex" ? codexOAuth2 : geminiOAuth2;
18284
19015
  const r = await flow.refreshAccessToken(refreshToken, refreshFetch);
18285
19016
  return {
@@ -18523,7 +19254,7 @@ var JsonSubscriptionCredentialStore = class {
18523
19254
  };
18524
19255
 
18525
19256
  // src/AccountHealthProbeScheduler.ts
18526
- import { fetchUpstream as fetchUpstream11 } from "@omnicross/core/pipeline/upstreamFetch";
19257
+ import { fetchUpstream as fetchUpstream13 } from "@omnicross/core/pipeline/upstreamFetch";
18527
19258
 
18528
19259
  // src/probe/CodexGenerationProbe.ts
18529
19260
  import {
@@ -18678,7 +19409,11 @@ var PROVIDER_PROBE_PLANS = {
18678
19409
  // The Copilot quota endpoint (copilot_internal/user) is a verified FREE
18679
19410
  // authed GET but lives on api.github.com with its own auth dialect and a
18680
19411
  // monthly-only window — the allowance collector owns the health surface.
18681
- copilot: { kind: "local" }
19412
+ copilot: { kind: "local" },
19413
+ // Antigravity's quota endpoints are POST RPCs on daily-cloudcode-pa (not a
19414
+ // cheap GET) and need the antigravity/hub UA — the allowance collector owns
19415
+ // the health surface; the probe stays local.
19416
+ antigravity: { kind: "local" }
18682
19417
  };
18683
19418
  function probePlanFor(providerId) {
18684
19419
  return PROVIDER_PROBE_PLANS[providerId] ?? { kind: "local" };
@@ -18700,7 +19435,7 @@ var AccountHealthProbeScheduler = class {
18700
19435
  this.logger = logger;
18701
19436
  this.config = config;
18702
19437
  this.now = opts.now ?? Date.now;
18703
- this.fetchImpl = opts.fetchImpl ?? fetchUpstream11;
19438
+ this.fetchImpl = opts.fetchImpl ?? fetchUpstream13;
18704
19439
  this.sleep = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
18705
19440
  this.planFor = opts.planFor ?? probePlanFor;
18706
19441
  }
@@ -19863,7 +20598,7 @@ var AuditWriter = class {
19863
20598
  import { appendFileSync as appendFileSync3, mkdirSync as mkdirSync8 } from "fs";
19864
20599
  import { createHmac as createHmac5 } from "crypto";
19865
20600
  import { join as join27 } from "path";
19866
- import { fetchUpstream as fetchUpstream12 } from "@omnicross/core/pipeline/upstreamFetch";
20601
+ import { fetchUpstream as fetchUpstream14 } from "@omnicross/core/pipeline/upstreamFetch";
19867
20602
 
19868
20603
  // src/billing/billingFiles.ts
19869
20604
  var BILLING_FILE_RE = /^billing-(\d{4})-(\d{2})-(\d{2})\.jsonl$/;
@@ -19886,7 +20621,7 @@ var BillingPublisher = class {
19886
20621
  constructor(billingDir, logger, opts = {}) {
19887
20622
  this.billingDir = billingDir;
19888
20623
  this.logger = logger;
19889
- this.fetchImpl = opts.fetchImpl ?? ((url, init) => fetchUpstream12(url, init));
20624
+ this.fetchImpl = opts.fetchImpl ?? ((url, init) => fetchUpstream14(url, init));
19890
20625
  this.defer = opts.defer ?? ((fn) => setTimeout(fn, 0));
19891
20626
  this.timeoutMs = opts.timeoutMs ?? BILLING_POST_TIMEOUT_MS;
19892
20627
  this.now = opts.now ?? Date.now;
@@ -20136,7 +20871,7 @@ var BillingRetrySweeper = class {
20136
20871
  // src/TokenRefreshScheduler.ts
20137
20872
  var REFRESH_LEAD_MS2 = 5 * 6e4;
20138
20873
  var SWEEP_INTERVAL_MS5 = 6e4;
20139
- var OAUTH_PROVIDERS2 = ["claude", "codex", "gemini", "kimi", "grok", "copilot"];
20874
+ var OAUTH_PROVIDERS2 = ["claude", "codex", "gemini", "kimi", "grok", "copilot", "antigravity"];
20140
20875
  var TokenRefreshScheduler = class {
20141
20876
  constructor(store, logger, intervalMs = SWEEP_INTERVAL_MS5, leadMs = REFRESH_LEAD_MS2) {
20142
20877
  this.store = store;
@@ -20227,6 +20962,8 @@ var TokenRefreshScheduler = class {
20227
20962
  // never reaches this — the branch exists for union totality.
20228
20963
  case "copilot":
20229
20964
  return this.store.refreshCopilotToken();
20965
+ case "antigravity":
20966
+ return this.store.refreshAntigravityToken();
20230
20967
  }
20231
20968
  }
20232
20969
  };
@@ -20305,7 +21042,7 @@ function createRouteLeaseSubscriptionPreflight(credentials) {
20305
21042
 
20306
21043
  // src/webhook/WebhookDispatcher.ts
20307
21044
  import { createHmac as createHmac6 } from "crypto";
20308
- import { fetchUpstream as fetchUpstream13 } from "@omnicross/core/pipeline/upstreamFetch";
21045
+ import { fetchUpstream as fetchUpstream15 } from "@omnicross/core/pipeline/upstreamFetch";
20309
21046
  var WEBHOOK_MAX_ATTEMPTS = 3;
20310
21047
  var WEBHOOK_QUEUE_MAX = 1e3;
20311
21048
  var WEBHOOK_SEND_TIMEOUT_MS = 1e4;
@@ -20325,7 +21062,7 @@ var WebhookDispatcher = class {
20325
21062
  sleep;
20326
21063
  now;
20327
21064
  constructor(opts = {}) {
20328
- this.fetchImpl = opts.fetchImpl ?? ((url, init) => fetchUpstream13(url, init));
21065
+ this.fetchImpl = opts.fetchImpl ?? ((url, init) => fetchUpstream15(url, init));
20329
21066
  this.logger = opts.logger;
20330
21067
  this.maxAttempts = opts.maxAttempts ?? WEBHOOK_MAX_ATTEMPTS;
20331
21068
  this.queueMax = opts.queueMax ?? WEBHOOK_QUEUE_MAX;
@@ -20411,8 +21148,8 @@ var WebhookDispatcher = class {
20411
21148
  signal: AbortSignal.timeout(this.timeoutMs)
20412
21149
  });
20413
21150
  return res.ok ? { ok: true, status: res.status } : { ok: false, status: res.status };
20414
- } catch (err8) {
20415
- return { ok: false, error: err8 instanceof Error ? err8.message : String(err8) };
21151
+ } catch (err9) {
21152
+ return { ok: false, error: err9 instanceof Error ? err9.message : String(err9) };
20416
21153
  }
20417
21154
  }
20418
21155
  /**
@@ -20549,7 +21286,7 @@ function buildDaemon(config, paths) {
20549
21286
  setSecretBox(secretBox3);
20550
21287
  setSecretBox2(secretBox3);
20551
21288
  const decryptedConfig = decryptConfigSecrets(config, secretBox3);
20552
- const accountAllowanceStore = new AccountAllowanceStore9(
21289
+ const accountAllowanceStore = new AccountAllowanceStore10(
20553
21290
  Date.now,
20554
21291
  void 0,
20555
21292
  new JsonAccountAllowancePersistence(defaultAccountAllowancePath(paths.configPath))
@@ -20593,6 +21330,8 @@ function buildDaemon(config, paths) {
20593
21330
  })
20594
21331
  );
20595
21332
  setGeminiCodeAssistResolver(getGeminiCodeAssistProjectResolver2());
21333
+ setAntigravitySandboxFailover(decryptedConfig.antigravity?.sandboxFailover === true);
21334
+ setOpenCodeGoUserAgent(decryptedConfig.opencodego?.userAgent ?? null);
20596
21335
  const autoDisableStore = new AutoDisableStore();
20597
21336
  const providerKeyQuotaService = new ProviderKeyQuotaService(secretBox3);
20598
21337
  const apiKeyPool = new ApiKeyPoolService(
@@ -20611,7 +21350,7 @@ function buildDaemon(config, paths) {
20611
21350
  const pricingEngine = new PricingEngine(pricingStore, logger, {
20612
21351
  // Catalog egress follows the same global/env proxy policy as every other
20613
21352
  // daemon upstream call; no provider/account override applies here.
20614
- fetchImpl: ((input, init) => fetchUpstream14(String(input), init ?? {}))
21353
+ fetchImpl: ((input, init) => fetchUpstream16(String(input), init ?? {}))
20615
21354
  });
20616
21355
  const pricingRefreshScheduler = new PricingRefreshScheduler(
20617
21356
  pricingEngine,
@@ -20853,6 +21592,7 @@ function buildDaemon(config, paths) {
20853
21592
  outboundApiServer,
20854
21593
  imageRuntimeConfig,
20855
21594
  imageRuntimeStatus: paths.imageRuntimeStatus ?? imageRuntimeManager,
21595
+ imageLiveVerifier: paths.imageLiveVerifier ?? imageDoctor,
20856
21596
  imageConfigAudit: paths.imageConfigAudit ?? ((record) => {
20857
21597
  imageObservability.recordConfigurationAudit(record);
20858
21598
  }),
@@ -20896,7 +21636,7 @@ function buildDaemon(config, paths) {
20896
21636
  // — `server.proxy.byProvider[...]` was silently skipped — and the call was
20897
21637
  // excluded from the upstream trace, so a failing login left no evidence.
20898
21638
  // `redactBodies` keeps the code/verifier + minted token out of that trace.
20899
- oauthExchangeFetch: paths.oauthExchangeFetch ? () => paths.oauthExchangeFetch : (providerId) => (url, init) => fetchUpstream14(url, init, { providerId, redactBodies: true }),
21639
+ oauthExchangeFetch: paths.oauthExchangeFetch ? () => paths.oauthExchangeFetch : (providerId) => (url, init) => fetchUpstream16(url, init, { providerId, redactBodies: true }),
20900
21640
  subscriptionAccountAppender: credentialStore,
20901
21641
  // Codex interactive OAuth (app-parity-2 child 5) — the async loopback flow store
20902
21642
  // + the one-shot 127.0.0.1:1455 listener. Token captured + persisted daemon-side;
@@ -20911,6 +21651,21 @@ function buildDaemon(config, paths) {
20911
21651
  // Grok interactive OAuth — the same async DEVICE-CODE shape as kimi.
20912
21652
  grokSessions: new CodexOAuthSessionStore(),
20913
21653
  copilotSessions: new CodexOAuthSessionStore(),
21654
+ // Antigravity interactive OAuth — the async LOOPBACK flow store + the
21655
+ // one-shot 127.0.0.1:51121 listener (same shape as codex; test seam below).
21656
+ antigravitySessions: new CodexOAuthSessionStore(),
21657
+ antigravityAwaitLoopback: paths.antigravityAwaitLoopback ?? ((state, timeoutMs, signal) => awaitLoopbackCode(state, timeoutMs, signal, {
21658
+ port: 51121,
21659
+ path: "/oauth-callback",
21660
+ label: "antigravity"
21661
+ })),
21662
+ // The dynamic model-catalog probe's token source (the ACTIVE antigravity
21663
+ // account; refreshed by the by-id near-expiry seam inside the lookup).
21664
+ resolveAntigravityAccessToken: async () => {
21665
+ const config2 = await credentialStore.getFullConfig();
21666
+ const activeId = config2.activeAntigravityAccountId ?? config2.antigravityAccounts?.[0]?.id;
21667
+ return activeId ? credentialStore.getAccessTokenForAccount("antigravity", activeId) : null;
21668
+ },
20914
21669
  // Migration pack (app-parity child 6, design D2/D3) — the concrete credential
20915
21670
  // store provides BOTH the full DECRYPTED read (`getFullConfig`, export) and
20916
21671
  // the multi-account append (`appendProviderAccount`, import re-encrypts at-
@@ -20969,7 +21724,7 @@ function buildDaemon(config, paths) {
20969
21724
  });
20970
21725
  const webhookDispatcher = new WebhookDispatcher({
20971
21726
  logger,
20972
- fetchImpl: (url, init) => fetchUpstream14(url, init)
21727
+ fetchImpl: (url, init) => fetchUpstream16(url, init)
20973
21728
  });
20974
21729
  setWebhookRuntime(webhookDispatcher, getSharedAccountHealth4());
20975
21730
  const auditWriter = new AuditWriter(auditDir, logger);
@@ -21104,15 +21859,59 @@ function buildClaudeDoctorChecks(config) {
21104
21859
  });
21105
21860
  return checks;
21106
21861
  }
21862
+ function buildAntigravityDoctorChecks(snapshot) {
21863
+ const checks = [];
21864
+ checks.push({
21865
+ name: "antigravity credential",
21866
+ ok: snapshot.accountCount > 0 && snapshot.hasAccessToken,
21867
+ detail: snapshot.accountCount === 0 ? "no antigravity account stored \u2014 run `omnicross login antigravity`" : `${snapshot.accountCount} account(s)${snapshot.activeEmail ? `, active: ${snapshot.activeEmail}` : ""}${snapshot.hasAccessToken ? "" : " \u2014 the active account has no access token"}`
21868
+ });
21869
+ const expiresAtMs = snapshot.expiresAt ? Date.parse(snapshot.expiresAt) : 0;
21870
+ const expired = snapshot.expired || expiresAtMs > 0 && Date.now() >= expiresAtMs;
21871
+ const expiringSoon = expiresAtMs > 0 && Date.now() >= expiresAtMs - 10 * 6e4;
21872
+ checks.push({
21873
+ name: "token freshness",
21874
+ ok: !expired,
21875
+ warn: !expired && expiringSoon,
21876
+ detail: expired ? "the active account is expired (its last refresh failed \u2014 re-login or fix the refresh path)" : snapshot.expiresAt ? `expires at ${snapshot.expiresAt}${expiringSoon ? " (inside the refresh lead window)" : ""}` : "no expiry recorded (refresh scheduler treats it as non-expiring)"
21877
+ });
21878
+ return checks;
21879
+ }
21880
+ function hasFreshAntigravityQuota(snapshot, now = Date.now()) {
21881
+ if (!snapshot || snapshot.lastErrorCode) return false;
21882
+ if (snapshot.expiresAt && !(Date.parse(snapshot.expiresAt) > now)) return false;
21883
+ return snapshot.windows.some(
21884
+ (window) => window.state === "fresh" && (!window.resetsAt || Date.parse(window.resetsAt) > now) && (window.disabled === true || typeof window.usedPercent === "number" && Number.isFinite(window.usedPercent))
21885
+ );
21886
+ }
21887
+ function buildAntigravityLiveChecks(result) {
21888
+ return [
21889
+ {
21890
+ name: "token refresh (--live)",
21891
+ ok: result.refreshOk,
21892
+ detail: result.refreshOk ? "the active account refreshed successfully" : "refresh failed (see the daemon log)"
21893
+ },
21894
+ {
21895
+ name: "quota collection (--live)",
21896
+ ok: result.quotaOk,
21897
+ detail: result.quotaOk ? "quotaSummary windows collected" : result.detail
21898
+ }
21899
+ ];
21900
+ }
21107
21901
  function buildImagesDoctorChecks(snapshot) {
21108
21902
  const enabled = snapshot.config.enabled;
21109
- const accountOk = !enabled || snapshot.account.usable;
21903
+ const routed = snapshot.config.routedProviders ?? ["codex-subscription"];
21904
+ const codexRouted = routed.includes("codex-subscription");
21905
+ const antigravityRouted = routed.includes("antigravity-subscription");
21906
+ const antigravity = snapshot.antigravityAccount ?? { present: false, usable: false, reason: "missing" };
21907
+ const accountOk = !enabled || !codexRouted || snapshot.account.usable;
21908
+ const antigravityOk = !enabled || !antigravityRouted || antigravity.usable;
21110
21909
  const evidenceOk = !enabled || snapshot.evidence.valid && snapshot.evidence.freshEntries > 0;
21111
21910
  return [
21112
21911
  {
21113
21912
  name: "normalized Images config",
21114
21913
  ok: snapshot.config.valid,
21115
- detail: snapshot.config.valid ? `enabled=${enabled}, provider=${snapshot.config.provider}, model=${snapshot.config.model}` : `invalid normalized configuration (${snapshot.config.errorCount} issue(s))`
21914
+ detail: snapshot.config.valid ? `enabled=${enabled}, providers=${routed.join("+")}, default=${snapshot.config.model} (${snapshot.config.provider})` : `invalid normalized configuration (${snapshot.config.errorCount} issue(s))`
21116
21915
  },
21117
21916
  {
21118
21917
  name: "private roots",
@@ -21133,8 +21932,14 @@ function buildImagesDoctorChecks(snapshot) {
21133
21932
  {
21134
21933
  name: "Codex account",
21135
21934
  ok: accountOk,
21136
- warn: !snapshot.account.usable,
21137
- detail: snapshot.account.usable ? "eligible local credential is present" : `${snapshot.account.reason}; Images live verification is unavailable`
21935
+ warn: enabled && codexRouted && !snapshot.account.usable,
21936
+ detail: !codexRouted ? "not routed by the current model table (no credential required)" : snapshot.account.usable ? "eligible local credential is present" : `${snapshot.account.reason}; codex-routed image models and live verification are unavailable`
21937
+ },
21938
+ {
21939
+ name: "Antigravity account",
21940
+ ok: antigravityOk,
21941
+ warn: enabled && antigravityRouted && !antigravity.usable,
21942
+ detail: !antigravityRouted ? "not routed by the current model table (no credential required)" : antigravity.usable ? "eligible local credential is present (protocol evidence still unverified)" : `${antigravity.reason}; antigravity-routed image models are unavailable`
21138
21943
  },
21139
21944
  {
21140
21945
  name: "cached capability evidence",
@@ -21149,6 +21954,12 @@ async function runImagesLiveDoctor(config, doctor, signal = new AbortController(
21149
21954
  " [\u26A0] live Images verification may consume subscription quota; one minimal low-quality PNG request will be sent"
21150
21955
  );
21151
21956
  const result = await doctor.verifyLive(config.images ?? DEFAULT_IMAGES_SERVER_CONFIG2, signal);
21957
+ const antigravityRouted = Object.values(config.images?.models ?? {}).includes("antigravity-subscription");
21958
+ if (antigravityRouted) {
21959
+ console.info(
21960
+ " [i] live verification covers the Codex wire only; the Antigravity provider has no independent verifier in v1 (its first real request bootstraps)"
21961
+ );
21962
+ }
21152
21963
  if (!result.ok) {
21153
21964
  console.info(` [\u2717] live Images verification: ${result.code}`);
21154
21965
  return false;
@@ -21283,14 +22094,49 @@ async function runLiveProbe(url, key, fetchImpl = fetch) {
21283
22094
  status: res.status,
21284
22095
  estimateHeader: res.headers.get("x-omnicross-count-estimate")
21285
22096
  };
21286
- } catch (err8) {
22097
+ } catch (err9) {
21287
22098
  return {
21288
22099
  status: null,
21289
22100
  estimateHeader: null,
21290
- error: err8 instanceof Error ? err8.message : String(err8)
22101
+ error: err9 instanceof Error ? err9.message : String(err9)
21291
22102
  };
21292
22103
  }
21293
22104
  }
22105
+ async function runAntigravityDoctor(daemon, live) {
22106
+ const config = await daemon.credentialStore.getFullConfig();
22107
+ const accounts = config.antigravityAccounts ?? [];
22108
+ const activeId = config.activeAntigravityAccountId ?? accounts[0]?.id;
22109
+ const active = accounts.find((account) => account.id === activeId);
22110
+ const snapshot = {
22111
+ accountCount: accounts.length,
22112
+ ...active?.tokens.email ? { activeEmail: active.tokens.email } : {},
22113
+ hasAccessToken: Boolean(active?.tokens.accessToken),
22114
+ expired: active?.tokens.status === "expired",
22115
+ ...active?.tokens.expiresAt ? { expiresAt: active.tokens.expiresAt } : {}
22116
+ };
22117
+ const checks = buildAntigravityDoctorChecks(snapshot);
22118
+ if (live && active) {
22119
+ const refreshOk = await daemon.credentialStore.refreshAntigravityToken();
22120
+ let quotaOk = false;
22121
+ let detail = "quotaSummary collection produced no usable windows";
22122
+ try {
22123
+ const snapshots = await daemon.accountAllowanceService.refreshAntigravity(active.id);
22124
+ quotaOk = hasFreshAntigravityQuota(snapshots.find((entry) => entry.accountId === active.id));
22125
+ if (!quotaOk) detail = snapshots[0]?.lastErrorCode ?? detail;
22126
+ } catch (error) {
22127
+ detail = error instanceof Error ? error.message : String(error);
22128
+ }
22129
+ checks.push(...buildAntigravityLiveChecks({ refreshOk, quotaOk, detail }));
22130
+ }
22131
+ console.info("omnicross doctor antigravity \u2014 subscription credential health");
22132
+ let hardFailure = false;
22133
+ for (const check of checks) {
22134
+ const mark = check.ok ? check.warn ? "\u26A0" : "\u2713" : "\u2717";
22135
+ if (!check.ok) hardFailure = true;
22136
+ console.info(` [${mark}] ${check.name}: ${check.detail}`);
22137
+ }
22138
+ return hardFailure ? 1 : 0;
22139
+ }
21294
22140
  async function runDoctor(argv, fetchImpl = fetch) {
21295
22141
  const { values, positionals } = parseArgs2({
21296
22142
  args: argv,
@@ -21304,8 +22150,8 @@ async function runDoctor(argv, fetchImpl = fetch) {
21304
22150
  allowPositionals: true
21305
22151
  });
21306
22152
  const subject = positionals[0] ?? "claude";
21307
- if (subject !== "claude" && subject !== "images" && subject !== "search") {
21308
- throw new Error(`doctor: unknown subject '${subject}' (supported: 'claude', 'images', 'search')`);
22153
+ if (subject !== "claude" && subject !== "images" && subject !== "search" && subject !== "antigravity") {
22154
+ throw new Error(`doctor: unknown subject '${subject}' (supported: 'claude', 'images', 'search', 'antigravity')`);
21309
22155
  }
21310
22156
  const configPath = values.config;
21311
22157
  if (!configPath) {
@@ -21328,6 +22174,9 @@ async function runDoctor(argv, fetchImpl = fetch) {
21328
22174
  runtime: daemon.searchRuntime
21329
22175
  });
21330
22176
  }
22177
+ if (subject === "antigravity") {
22178
+ return await runAntigravityDoctor(daemon, values.live === true);
22179
+ }
21331
22180
  const checks = subject === "images" ? buildImagesDoctorChecks(await daemon.imageDoctor.inspectLocal(
21332
22181
  serverConfig.images ?? DEFAULT_IMAGES_SERVER_CONFIG2
21333
22182
  )) : buildClaudeDoctorChecks(serverConfig);
@@ -21697,9 +22546,9 @@ async function runLaunch(argv, deps) {
21697
22546
  await daemon.llmConfig.ready();
21698
22547
  await daemon.migrateUsageStore();
21699
22548
  await daemon.providerProxy.start();
21700
- } catch (err8) {
22549
+ } catch (err9) {
21701
22550
  await shutdownLaunchDaemon(daemon);
21702
- throw err8;
22551
+ throw err9;
21703
22552
  }
21704
22553
  let launch;
21705
22554
  try {
@@ -21707,9 +22556,9 @@ async function runLaunch(argv, deps) {
21707
22556
  providerId: values.provider,
21708
22557
  model: values.model
21709
22558
  });
21710
- } catch (err8) {
22559
+ } catch (err9) {
21711
22560
  await shutdownLaunchDaemon(daemon);
21712
- throw err8;
22561
+ throw err9;
21713
22562
  }
21714
22563
  try {
21715
22564
  const plan = buildCliSpawnPlan({
@@ -21814,9 +22663,9 @@ function spawnCliInherit(plan) {
21814
22663
  process.removeListener("SIGINT", onSignal);
21815
22664
  process.removeListener("SIGTERM", onSignal);
21816
22665
  };
21817
- child.on("error", (err8) => {
22666
+ child.on("error", (err9) => {
21818
22667
  detach();
21819
- if (err8.code === "ENOENT") {
22668
+ if (err9.code === "ENOENT") {
21820
22669
  reject(
21821
22670
  new Error(
21822
22671
  `launch: "${plan.command}" not found on PATH \u2014 install the CLI first.`
@@ -21824,7 +22673,7 @@ function spawnCliInherit(plan) {
21824
22673
  );
21825
22674
  return;
21826
22675
  }
21827
- reject(err8);
22676
+ reject(err9);
21828
22677
  });
21829
22678
  child.on("exit", (code, signal) => {
21830
22679
  detach();
@@ -21837,8 +22686,10 @@ function spawnCliInherit(plan) {
21837
22686
  import { spawn as spawn3 } from "child_process";
21838
22687
  import { createInterface as createInterface2 } from "readline";
21839
22688
  import { parseArgs as parseArgs7 } from "util";
21840
- import { fetchUpstream as fetchUpstream15, setUpstreamProxyResolver as setUpstreamProxyResolver2 } from "@omnicross/core/pipeline/upstreamFetch";
22689
+ import { getAntigravityProjectResolver as getAntigravityProjectResolver3 } from "@omnicross/core/auth/GeminiCodeAssistProjectResolver";
22690
+ import { fetchUpstream as fetchUpstream17, setUpstreamProxyResolver as setUpstreamProxyResolver2 } from "@omnicross/core/pipeline/upstreamFetch";
21841
22691
  import {
22692
+ antigravityOAuth as antigravityOAuth3,
21842
22693
  claudeOAuth as claudeOAuth3,
21843
22694
  codexOAuth as codexOAuth3,
21844
22695
  copilotOAuth as copilotOAuth3,
@@ -21846,7 +22697,7 @@ import {
21846
22697
  grokOAuth as grokOAuth3,
21847
22698
  kimiOAuth as kimiOAuth3
21848
22699
  } from "@omnicross/subscriptions";
21849
- var PROVIDERS2 = ["claude", "codex", "gemini", "kimi", "grok", "copilot"];
22700
+ var PROVIDERS2 = ["claude", "codex", "gemini", "kimi", "grok", "copilot", "antigravity"];
21850
22701
  async function runLogin(argv, deps) {
21851
22702
  const { values, positionals } = parseArgs7({
21852
22703
  args: argv,
@@ -21877,7 +22728,7 @@ async function runLogin(argv, deps) {
21877
22728
  const resolved = {
21878
22729
  openBrowser: deps?.openBrowser ?? openBrowser,
21879
22730
  promptPaste: deps?.promptPaste ?? promptPaste,
21880
- awaitLoopback: deps?.awaitLoopback ?? ((state) => awaitLoopbackCode(state)),
22731
+ awaitLoopback: deps?.awaitLoopback ?? ((state, timeoutMs, signal, binding) => awaitLoopbackCode(state, timeoutMs, signal, binding)),
21881
22732
  awaitKimiDevice: deps?.awaitKimiDevice ?? ((fetchImpl) => runKimiDeviceFlow(fetchImpl, resolvedOpenBrowser)),
21882
22733
  awaitGrokDevice: deps?.awaitGrokDevice ?? ((fetchImpl) => runGrokDeviceFlow(fetchImpl, resolvedOpenBrowser)),
21883
22734
  awaitCopilotDevice: deps?.awaitCopilotDevice ?? ((fetchImpl, enterpriseUrl) => runCopilotDeviceFlow(fetchImpl, resolvedOpenBrowser, enterpriseUrl)),
@@ -21889,7 +22740,7 @@ async function runLogin(argv, deps) {
21889
22740
  setUpstreamProxyResolver2(createUpstreamProxyResolver());
21890
22741
  try {
21891
22742
  const tokensPath = defaultTokensPath(values.config);
21892
- const exchangeFetch = resolved.tokensFetch ?? ((url, init) => fetchUpstream15(url, init, { providerId: provider, redactBodies: true }));
22743
+ const exchangeFetch = resolved.tokensFetch ?? ((url, init) => fetchUpstream17(url, init, { providerId: provider, redactBodies: true }));
21893
22744
  const store = new JsonSubscriptionCredentialStore(tokensPath, box, exchangeFetch);
21894
22745
  const expiresAt = await runProviderLogin(
21895
22746
  provider,
@@ -21912,6 +22763,7 @@ async function runProviderLogin(provider, store, deps, exchangeFetch, label, ent
21912
22763
  if (provider === "kimi") return loginKimi(store, deps, exchangeFetch, label);
21913
22764
  if (provider === "grok") return loginGrok(store, deps, exchangeFetch, label);
21914
22765
  if (provider === "copilot") return loginCopilot(store, deps, exchangeFetch, label, enterpriseUrl);
22766
+ if (provider === "antigravity") return loginAntigravity(store, deps, exchangeFetch, label);
21915
22767
  return loginGemini(store, deps, exchangeFetch, label);
21916
22768
  }
21917
22769
  async function loginCodex(store, deps, exchangeFetch, label) {
@@ -22105,6 +22957,70 @@ async function loginCopilot(store, deps, exchangeFetch, label, enterpriseUrl) {
22105
22957
  logMasked("copilot", result.accessToken);
22106
22958
  return expiresAt;
22107
22959
  }
22960
+ async function loginAntigravity(store, deps, exchangeFetch, label) {
22961
+ const { authUrl, state } = antigravityOAuth3.generateAuthParams();
22962
+ await presentUrl(authUrl, deps);
22963
+ const code = await captureAntigravityCode(deps, state);
22964
+ const result = await antigravityOAuth3.exchangeCodeForTokens(code, exchangeFetch);
22965
+ const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
22966
+ const email = await antigravityOAuth3.fetchUserEmail(result.accessToken, exchangeFetch);
22967
+ console.info("Resolving the Antigravity Cloud Code Assist project...");
22968
+ const projectId = await getAntigravityProjectResolver3().resolveProject(result.accessToken);
22969
+ const block = {
22970
+ authMethod: "oauth",
22971
+ status: "authorized",
22972
+ accessToken: result.accessToken,
22973
+ refreshToken: result.refreshToken,
22974
+ expiresAt,
22975
+ ...email ? { email } : {},
22976
+ ...projectId ? { projectId } : {},
22977
+ lastRefreshedAt: (/* @__PURE__ */ new Date()).toISOString()
22978
+ };
22979
+ await store.appendProviderAccount("antigravity", block, label);
22980
+ logMasked("antigravity", result.accessToken);
22981
+ return expiresAt;
22982
+ }
22983
+ async function captureAntigravityCode(deps, state) {
22984
+ try {
22985
+ return await deps.awaitLoopback(state, void 0, void 0, {
22986
+ port: 51121,
22987
+ path: "/oauth-callback",
22988
+ label: "antigravity"
22989
+ });
22990
+ } catch (loopbackError) {
22991
+ const reason = loopbackError instanceof Error ? loopbackError.message : String(loopbackError);
22992
+ console.warn(`(loopback capture unavailable: ${reason})`);
22993
+ console.info(
22994
+ "Paste fallback: after authorizing, copy the failing redirect URL (or just its code parameter) here."
22995
+ );
22996
+ const pasted = (await deps.promptPaste("Paste the authorization code (or redirect URL): ")).trim();
22997
+ if (!pasted) throw new Error("login: no authorization code was pasted");
22998
+ const { code, state: pastedState } = parseAntigravityPaste(pasted);
22999
+ if (!code) throw new Error("login: the pasted value carried no authorization code");
23000
+ if (pastedState && pastedState !== state) {
23001
+ throw new Error("login: pasted state did not match (possible CSRF) \u2014 aborting");
23002
+ }
23003
+ return code;
23004
+ }
23005
+ }
23006
+ function parseAntigravityPaste(pasted) {
23007
+ if (pasted.includes("://")) {
23008
+ try {
23009
+ const url = new URL(pasted);
23010
+ const code = url.searchParams.get("code") ?? "";
23011
+ const state = url.searchParams.get("state") ?? void 0;
23012
+ return { code, ...state ? { state } : {} };
23013
+ } catch {
23014
+ }
23015
+ }
23016
+ if (/^[?]?code=/.test(pasted)) {
23017
+ const params = new URLSearchParams(pasted.replace(/^\?/, ""));
23018
+ const code = params.get("code") ?? "";
23019
+ const state = params.get("state") ?? void 0;
23020
+ return { code, ...state ? { state } : {} };
23021
+ }
23022
+ return { code: pasted };
23023
+ }
22108
23024
  function isLoginProvider(value) {
22109
23025
  return PROVIDERS2.includes(value);
22110
23026
  }
@@ -22526,7 +23442,11 @@ var TOKEN_FIELDS2 = {
22526
23442
  claude: ["accessToken", "refreshToken"],
22527
23443
  codex: ["accessToken", "refreshToken", "idToken"],
22528
23444
  gemini: ["accessToken", "refreshToken"],
22529
- opencodego: ["apiKey"]
23445
+ opencodego: ["apiKey"],
23446
+ kimi: ["accessToken", "refreshToken"],
23447
+ grok: ["accessToken", "refreshToken"],
23448
+ copilot: ["accessToken", "refreshToken"],
23449
+ antigravity: ["accessToken", "refreshToken"]
22530
23450
  };
22531
23451
  function walkTokens(raw, fn) {
22532
23452
  const next = { ...raw };
@@ -22810,7 +23730,7 @@ async function main() {
22810
23730
  process.exitCode = 1;
22811
23731
  }
22812
23732
  }
22813
- main().catch((err8) => {
22814
- console.error(err8 instanceof Error ? err8.message : String(err8));
23733
+ main().catch((err9) => {
23734
+ console.error(err9 instanceof Error ? err9.message : String(err9));
22815
23735
  process.exitCode = 1;
22816
23736
  });