@omnicross/daemon 0.4.1 → 0.4.3

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");
@@ -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
  }
@@ -9846,7 +10397,7 @@ async function handleImages(res, method, rest, deps) {
9846
10397
  return writeJson4(res, 200, {
9847
10398
  configured: {
9848
10399
  enabled: images.enabled,
9849
- provider: images.provider,
10400
+ provider: images.models[images.defaultModel] ?? "codex-subscription",
9850
10401
  model: images.defaultModel,
9851
10402
  remoteUrlsEnabled: images.remote.enabled,
9852
10403
  referenceTtlMs: images.references.ttlMs
@@ -9946,12 +10497,12 @@ async function handlePlayground(req, res, method, deps) {
9946
10497
  const payload = body["body"];
9947
10498
  const status = deps.outboundApiServer.getStatus();
9948
10499
  if (!status.running || !status.port) return writeJsonError(res, 503, "outbound server not running");
9949
- const path2 = resolvePlaygroundPath(endpoint, isRecord7(payload) ? payload : {});
10500
+ const path2 = resolvePlaygroundPath(endpoint, isRecord9(payload) ? payload : {});
9950
10501
  if (!path2) return writeJsonError(res, 400, `unknown endpoint '${endpoint}'`);
9951
10502
  const upstreamBody = typeof payload === "string" ? payload : JSON.stringify(payload ?? {});
9952
10503
  await proxyToOutbound(res, status.port, path2, key, upstreamBody);
9953
10504
  }
9954
- function isRecord7(v) {
10505
+ function isRecord9(v) {
9955
10506
  return !!v && typeof v === "object" && !Array.isArray(v);
9956
10507
  }
9957
10508
  function proxyToOutbound(res, outboundPort, path2, key, body) {
@@ -9980,8 +10531,8 @@ function proxyToOutbound(res, outboundPort, path2, key, body) {
9980
10531
  });
9981
10532
  }
9982
10533
  );
9983
- upstream.on("error", (err8) => {
9984
- if (!res.headersSent) writeJsonError(res, 502, `playground proxy failed: ${err8.message}`);
10534
+ upstream.on("error", (err9) => {
10535
+ if (!res.headersSent) writeJsonError(res, 502, `playground proxy failed: ${err9.message}`);
9985
10536
  else res.end();
9986
10537
  resolve11();
9987
10538
  });
@@ -10086,7 +10637,7 @@ async function handleUiStatic(req, res, urlPath, uiDist) {
10086
10637
  }
10087
10638
 
10088
10639
  // src/admin/version.ts
10089
- var DAEMON_VERSION = true ? "0.4.1" : "0.0.0-dev";
10640
+ var DAEMON_VERSION = true ? "0.4.3" : "0.0.0-dev";
10090
10641
 
10091
10642
  // src/admin/AdminServer.ts
10092
10643
  var LOOPBACK_ADDR = "127.0.0.1";
@@ -10129,13 +10680,13 @@ var AdminServer = class {
10129
10680
  const server = http2.createServer((req, res) => {
10130
10681
  this.onRequest(req, res);
10131
10682
  });
10132
- const onError = (err8) => {
10133
- if (err8.code === "EADDRINUSE" && port !== 0) {
10683
+ const onError = (err9) => {
10684
+ if (err9.code === "EADDRINUSE" && port !== 0) {
10134
10685
  server.removeListener("error", onError);
10135
10686
  this.listen(bindAddr, 0).then(resolve11, reject);
10136
10687
  return;
10137
10688
  }
10138
- reject(err8);
10689
+ reject(err9);
10139
10690
  };
10140
10691
  server.on("error", onError);
10141
10692
  server.listen(port, bindAddr, () => {
@@ -10153,8 +10704,8 @@ var AdminServer = class {
10153
10704
  }
10154
10705
  /** Per-request handler: auth gate (when a token is set) → routing. */
10155
10706
  onRequest(req, res) {
10156
- void this.dispatch(req, res).catch((err8) => {
10157
- const message = err8 instanceof Error ? err8.message : String(err8);
10707
+ void this.dispatch(req, res).catch((err9) => {
10708
+ const message = err9 instanceof Error ? err9.message : String(err9);
10158
10709
  this.deps.logger.error("[AdminServer] unhandled error:", message);
10159
10710
  if (!res.headersSent) {
10160
10711
  res.writeHead(500, { "Content-Type": "application/json" });
@@ -10377,7 +10928,10 @@ var HTML_HEADERS = {
10377
10928
  function pageHtml(message) {
10378
10929
  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
10930
  }
10380
- function awaitLoopbackCode(expectedState, timeoutMs = DEFAULT_TIMEOUT_MS, signal) {
10931
+ function awaitLoopbackCode(expectedState, timeoutMs = DEFAULT_TIMEOUT_MS, signal, binding = {}) {
10932
+ const port = binding.port ?? LOOPBACK_PORT;
10933
+ const callbackPath = binding.path ?? CALLBACK_PATH;
10934
+ const label = binding.label ?? "codex";
10381
10935
  return new Promise((resolve11, reject) => {
10382
10936
  let settled = false;
10383
10937
  const finish = (server2, fn) => {
@@ -10388,8 +10942,8 @@ function awaitLoopbackCode(expectedState, timeoutMs = DEFAULT_TIMEOUT_MS, signal
10388
10942
  server2.close();
10389
10943
  };
10390
10944
  const server = createServer2((req, res) => {
10391
- const url = new URL(req.url ?? "", `http://${LOOPBACK_HOST}:${LOOPBACK_PORT}`);
10392
- if (url.pathname !== CALLBACK_PATH) {
10945
+ const url = new URL(req.url ?? "", `http://${LOOPBACK_HOST}:${port}`);
10946
+ if (url.pathname !== callbackPath) {
10393
10947
  res.writeHead(404, HTML_HEADERS);
10394
10948
  res.end(pageHtml("Not found"));
10395
10949
  return;
@@ -10418,25 +10972,25 @@ function awaitLoopbackCode(expectedState, timeoutMs = DEFAULT_TIMEOUT_MS, signal
10418
10972
  return;
10419
10973
  }
10420
10974
  signal?.addEventListener("abort", abort, { once: true });
10421
- server.on("error", (err8) => {
10975
+ server.on("error", (err9) => {
10422
10976
  if (settled) return;
10423
10977
  settled = true;
10424
10978
  clearTimeout(timer);
10425
- if (err8.code === "EADDRINUSE") {
10979
+ if (err9.code === "EADDRINUSE") {
10426
10980
  reject(
10427
10981
  new Error(
10428
- `login: cannot bind ${LOOPBACK_HOST}:${LOOPBACK_PORT} (address in use) \u2014 another codex login or process is holding the port`
10982
+ `login: cannot bind ${LOOPBACK_HOST}:${port} (address in use) \u2014 another ${label} login or process is holding the port`
10429
10983
  )
10430
10984
  );
10431
10985
  } else {
10432
- reject(err8);
10986
+ reject(err9);
10433
10987
  }
10434
10988
  });
10435
10989
  const timer = setTimeout(() => {
10436
10990
  finish(server, () => reject(new Error(`login: timed out after ${Math.round(timeoutMs / 1e3)}s waiting for the callback`)));
10437
10991
  }, timeoutMs);
10438
10992
  if (typeof timer.unref === "function") timer.unref();
10439
- server.listen(LOOPBACK_PORT, LOOPBACK_HOST);
10993
+ server.listen(port, LOOPBACK_HOST);
10440
10994
  });
10441
10995
  }
10442
10996
 
@@ -10506,7 +11060,7 @@ function createPoolKeysLoader(getProviderRow, autoDisabled) {
10506
11060
 
10507
11061
  // src/allowance/ProviderKeyQuotaService.ts
10508
11062
  import { mergeExtraHeaders as mergeExtraHeaders2 } from "@omnicross/core";
10509
- import { fetchUpstream as fetchUpstream9 } from "@omnicross/core/pipeline/upstreamFetch";
11063
+ import { fetchUpstream as fetchUpstream11 } from "@omnicross/core/pipeline/upstreamFetch";
10510
11064
 
10511
11065
  // src/allowance/ProviderKeyQuota.ts
10512
11066
  var MINUTE_MS3 = 6e4;
@@ -10535,11 +11089,11 @@ function isoInstant3(value) {
10535
11089
  }
10536
11090
  return void 0;
10537
11091
  }
10538
- function secondsUntil8(instant, now) {
11092
+ function secondsUntil9(instant, now) {
10539
11093
  if (!instant) return void 0;
10540
11094
  return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
10541
11095
  }
10542
- function isRecord8(value) {
11096
+ function isRecord10(value) {
10543
11097
  return !!value && typeof value === "object" && !Array.isArray(value);
10544
11098
  }
10545
11099
  function detectProviderKeyQuotaAdapter(baseUrl) {
@@ -10606,17 +11160,17 @@ function zaiWindowIdLabel(durationMs) {
10606
11160
  return { id: "quota", label: "Quota" };
10607
11161
  }
10608
11162
  function parseZaiQuotaPayload(payload, now) {
10609
- if (!isRecord8(payload)) return null;
10610
- const data = isRecord8(payload["data"]) ? payload["data"] : payload;
11163
+ if (!isRecord10(payload)) return null;
11164
+ const data = isRecord10(payload["data"]) ? payload["data"] : payload;
10611
11165
  if (payload["success"] === false) return null;
10612
11166
  const limits = Array.isArray(data["limits"]) ? data["limits"] : [];
10613
11167
  const byWindow = /* @__PURE__ */ new Map();
10614
11168
  for (const raw of limits) {
10615
- if (!isRecord8(raw)) continue;
11169
+ if (!isRecord10(raw)) continue;
10616
11170
  const item = raw;
10617
11171
  if (item.type === void 0) continue;
10618
11172
  const details = raw["usageDetails"];
10619
- if (Array.isArray(details) && details.some((d) => isRecord8(d) && d["modelCode"] === "zread")) {
11173
+ if (Array.isArray(details) && details.some((d) => isRecord10(d) && d["modelCode"] === "zread")) {
10620
11174
  continue;
10621
11175
  }
10622
11176
  const durationMs = zaiWindowDurationMs(item);
@@ -10635,7 +11189,7 @@ function parseZaiQuotaPayload(payload, now) {
10635
11189
  usedPercent,
10636
11190
  ...durationMs !== void 0 ? { windowMinutes: Math.round(durationMs / MINUTE_MS3) } : {},
10637
11191
  ...resetsAt !== void 0 ? { resetsAt } : {},
10638
- remainingSeconds: secondsUntil8(resetsAt, now),
11192
+ remainingSeconds: secondsUntil9(resetsAt, now),
10639
11193
  state: "fresh"
10640
11194
  };
10641
11195
  const existing = byWindow.get(id);
@@ -10649,7 +11203,7 @@ function parseZaiQuotaPayload(payload, now) {
10649
11203
  var MINIMAX_STATUS_EXHAUSTED = 2;
10650
11204
  var MINIMAX_SHARED_BUCKET = "general";
10651
11205
  function parseMiniMaxBucket(value) {
10652
- if (!isRecord8(value)) return null;
11206
+ if (!isRecord10(value)) return null;
10653
11207
  const modelName = typeof value["model_name"] === "string" ? value["model_name"].trim() : "";
10654
11208
  if (!modelName) return null;
10655
11209
  const instant = (v) => {
@@ -10676,14 +11230,14 @@ function minimaxWindow(id, label, windowMinutes, resetsAtMs, remainingPercent, s
10676
11230
  usedPercent,
10677
11231
  ...windowMinutes !== void 0 ? { windowMinutes } : {},
10678
11232
  ...resetsAt !== void 0 ? { resetsAt } : {},
10679
- remainingSeconds: secondsUntil8(resetsAt, now),
11233
+ remainingSeconds: secondsUntil9(resetsAt, now),
10680
11234
  state: usedPercent !== null ? "fresh" : "unavailable"
10681
11235
  };
10682
11236
  }
10683
11237
  function parseMiniMaxTokenPlanPayload(payload, now) {
10684
- if (!isRecord8(payload)) return null;
11238
+ if (!isRecord10(payload)) return null;
10685
11239
  const baseResp = payload["base_resp"];
10686
- if (!isRecord8(baseResp) || baseResp["status_code"] !== 0) return null;
11240
+ if (!isRecord10(baseResp) || baseResp["status_code"] !== 0) return null;
10687
11241
  const buckets = Array.isArray(payload["model_remains"]) ? payload["model_remains"] : [];
10688
11242
  let general = null;
10689
11243
  for (const raw of buckets) {
@@ -10716,11 +11270,11 @@ function parseMiniMaxTokenPlanPayload(payload, now) {
10716
11270
  ];
10717
11271
  }
10718
11272
  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;
11273
+ if (!isRecord10(payload)) return null;
11274
+ const limits = isRecord10(payload["limits"]) ? payload["limits"] : void 0;
11275
+ const requests = limits && isRecord10(limits["requests"]) ? limits["requests"] : void 0;
11276
+ const usage = isRecord10(payload["usage"]) ? payload["usage"] : void 0;
11277
+ const window = isRecord10(payload["window"]) ? payload["window"] : void 0;
10724
11278
  const hardCap = finiteNumber5(requests?.["hard_cap"]);
10725
11279
  const softLimit = finiteNumber5(requests?.["limit"]);
10726
11280
  const requestsInWindow = finiteNumber5(usage?.["requests_in_window"]);
@@ -10741,15 +11295,15 @@ function parseUmansUsagePayload(payload, now) {
10741
11295
  usedPercent,
10742
11296
  windowMinutes: 5 * 60,
10743
11297
  ...resetsAt !== void 0 ? { resetsAt } : {},
10744
- remainingSeconds: secondsUntil8(resetsAt, now),
11298
+ remainingSeconds: secondsUntil9(resetsAt, now),
10745
11299
  state: "fresh"
10746
11300
  }
10747
11301
  ];
10748
11302
  }
10749
11303
  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;
11304
+ if (!isRecord10(payload)) return null;
11305
+ const fiveHour = isRecord10(payload["rollingFiveHourLimit"]) ? payload["rollingFiveHourLimit"] : void 0;
11306
+ const weekly = isRecord10(payload["weeklyTokenLimit"]) ? payload["weeklyTokenLimit"] : void 0;
10753
11307
  const windows = [];
10754
11308
  if (fiveHour) {
10755
11309
  const max = finiteNumber5(fiveHour["max"]);
@@ -10763,7 +11317,7 @@ function parseSyntheticQuotasPayload(payload, now) {
10763
11317
  usedPercent,
10764
11318
  windowMinutes: 5 * 60,
10765
11319
  ...resetsAt !== void 0 ? { resetsAt } : {},
10766
- remainingSeconds: secondsUntil8(resetsAt, now),
11320
+ remainingSeconds: secondsUntil9(resetsAt, now),
10767
11321
  state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
10768
11322
  });
10769
11323
  }
@@ -10778,7 +11332,7 @@ function parseSyntheticQuotasPayload(payload, now) {
10778
11332
  usedPercent,
10779
11333
  windowMinutes: 7 * 24 * 60,
10780
11334
  ...resetsAt !== void 0 ? { resetsAt } : {},
10781
- remainingSeconds: secondsUntil8(resetsAt, now),
11335
+ remainingSeconds: secondsUntil9(resetsAt, now),
10782
11336
  state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
10783
11337
  });
10784
11338
  }
@@ -10790,12 +11344,12 @@ var CLINE_WINDOW_CONFIG = {
10790
11344
  monthly: { id: "thirty-day", label: "30 days", minutes: 30 * 24 * 60 }
10791
11345
  };
10792
11346
  function parseClinePassUsageLimitsPayload(payload, now) {
10793
- if (!isRecord8(payload)) return null;
10794
- const data = isRecord8(payload["data"]) ? payload["data"] : payload;
11347
+ if (!isRecord10(payload)) return null;
11348
+ const data = isRecord10(payload["data"]) ? payload["data"] : payload;
10795
11349
  const limits = Array.isArray(data["limits"]) ? data["limits"] : [];
10796
11350
  const windows = [];
10797
11351
  for (const raw of limits) {
10798
- if (!isRecord8(raw)) continue;
11352
+ if (!isRecord10(raw)) continue;
10799
11353
  const config = CLINE_WINDOW_CONFIG[typeof raw["type"] === "string" ? raw["type"] : ""];
10800
11354
  if (!config) continue;
10801
11355
  const usedPercent = finitePercent4(raw["percentUsed"]);
@@ -10808,7 +11362,7 @@ function parseClinePassUsageLimitsPayload(payload, now) {
10808
11362
  usedPercent,
10809
11363
  windowMinutes: config.minutes,
10810
11364
  ...resetsAt !== void 0 ? { resetsAt } : {},
10811
- remainingSeconds: secondsUntil8(resetsAt, now),
11365
+ remainingSeconds: secondsUntil9(resetsAt, now),
10812
11366
  state: "fresh"
10813
11367
  });
10814
11368
  }
@@ -10847,7 +11401,7 @@ function rowKeyEntries(row) {
10847
11401
  return [];
10848
11402
  }
10849
11403
  var ProviderKeyQuotaService = class {
10850
- constructor(box, fetchImpl = (url, init) => fetchUpstream9(url, init, { redactBodies: true }), now = Date.now) {
11404
+ constructor(box, fetchImpl = (url, init) => fetchUpstream11(url, init, { redactBodies: true }), now = Date.now) {
10851
11405
  this.box = box;
10852
11406
  this.fetchImpl = fetchImpl;
10853
11407
  this.now = now;
@@ -11421,12 +11975,12 @@ function createImageDoctorService(options) {
11421
11975
  authStrategy: strategy,
11422
11976
  generationTimeoutMs: config.queue.generationTimeoutMs
11423
11977
  }));
11424
- const readAccount = async () => {
11425
- const codex = (await options.subscriptionAccounts.listAll()).find((entry) => entry.providerId === "codex");
11978
+ const readAccount = async (providerId) => {
11979
+ const entry = (await options.subscriptionAccounts.listAll()).find((candidate) => candidate.providerId === providerId);
11426
11980
  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"
11981
+ present: entry !== void 0,
11982
+ usable: entry?.credentialStatus.ok === true,
11983
+ reason: entry === void 0 ? "missing" : entry.credentialStatus.ok ? "ready" : "unavailable"
11430
11984
  });
11431
11985
  };
11432
11986
  const activePaths = () => options.storageCatalog.active().resolver;
@@ -11464,6 +12018,7 @@ function createImageDoctorService(options) {
11464
12018
  } catch {
11465
12019
  storesValid = false;
11466
12020
  }
12021
+ const antigravityAccount = await readAccount("antigravity");
11467
12022
  const rows = await options.keyDb.outboundApiKeysList();
11468
12023
  let legacyRows = 0;
11469
12024
  let invalidRows = 0;
@@ -11480,7 +12035,7 @@ function createImageDoctorService(options) {
11480
12035
  invalidRows += 1;
11481
12036
  }
11482
12037
  }
11483
- const account = await readAccount();
12038
+ const account = await readAccount("codex");
11484
12039
  let evidence;
11485
12040
  let evidenceStore;
11486
12041
  try {
@@ -11494,10 +12049,11 @@ function createImageDoctorService(options) {
11494
12049
  return Object.freeze({
11495
12050
  config: Object.freeze({
11496
12051
  enabled: config.enabled,
11497
- provider: config.provider,
12052
+ provider: config.models[config.defaultModel] ?? "codex-subscription",
11498
12053
  model: config.defaultModel,
11499
12054
  valid: configErrors.length === 0,
11500
- errorCount: configErrors.length
12055
+ errorCount: configErrors.length,
12056
+ routedProviders: Object.freeze([...new Set(Object.values(config.models))])
11501
12057
  }),
11502
12058
  roots: Object.freeze({
11503
12059
  valid: verifiedAreas === ROOT_AREAS.length,
@@ -11522,12 +12078,13 @@ function createImageDoctorService(options) {
11522
12078
  imagesAuthorizedRows
11523
12079
  }),
11524
12080
  account,
12081
+ antigravityAccount,
11525
12082
  evidence: Object.freeze(evidence)
11526
12083
  });
11527
12084
  },
11528
12085
  verifyLive: async (config, signal) => {
11529
12086
  if (!config.enabled) return Object.freeze({ ok: false, code: "images_disabled" });
11530
- const account = await readAccount();
12087
+ const account = await readAccount("codex");
11531
12088
  if (!account.usable) {
11532
12089
  return Object.freeze({ ok: false, code: "codex_account_unavailable" });
11533
12090
  }
@@ -11788,6 +12345,7 @@ import {
11788
12345
  validateImagesServerConfig as validateImagesServerConfig3
11789
12346
  } from "@omnicross/core/outbound-api";
11790
12347
  import {
12348
+ createAntigravitySubscriptionImageProvider,
11791
12349
  createCodexSubscriptionImageProvider
11792
12350
  } from "@omnicross/subscriptions";
11793
12351
 
@@ -11819,10 +12377,11 @@ function createTrustedImageApiRuntimeResolver(options) {
11819
12377
  throw new TypeError("enabled image remote loading requires a proven resolver");
11820
12378
  }
11821
12379
  const hmacKey = Buffer.from(options.hmacKey);
11822
- const modelAliases = new Map(Object.entries(options.config.modelAliases));
12380
+ const modelAliases = new Map(Object.entries(options.config.aliases));
12381
+ const modelRoutes = new Map(Object.entries(options.config.models));
11823
12382
  const limits = Object.freeze({ ...options.config.limits });
11824
- const providerId = options.config.provider;
11825
12383
  const defaultModel = options.config.defaultModel;
12384
+ const providerId = modelRoutes.get(defaultModel) ?? "codex-subscription";
11826
12385
  const referenceStore = options.referenceStore;
11827
12386
  const retention = Object.freeze({
11828
12387
  enabled: true,
@@ -11843,6 +12402,7 @@ function createTrustedImageApiRuntimeResolver(options) {
11843
12402
  providerId,
11844
12403
  defaultModel,
11845
12404
  modelAliases,
12405
+ modelRoutes,
11846
12406
  limits,
11847
12407
  ...preferredAccountId ? { preferredAccountId } : {},
11848
12408
  ...preferredAccountGroup ? { preferredAccountGroup } : {},
@@ -12247,7 +12807,9 @@ var GENERATION_ID = /^[A-Za-z0-9][A-Za-z0-9_.:-]{0,127}$/u;
12247
12807
  function snapshotConfig(config) {
12248
12808
  return {
12249
12809
  ...config,
12250
- modelAliases: { ...config.modelAliases },
12810
+ models: { ...config.models },
12811
+ aliases: { ...config.aliases },
12812
+ codex: { ...config.codex },
12251
12813
  account: { ...config.account },
12252
12814
  queue: { ...config.queue },
12253
12815
  temporary: { ...config.temporary },
@@ -12281,10 +12843,15 @@ function createImageRuntimeGeneration(options) {
12281
12843
  }
12282
12844
  });
12283
12845
  }
12284
- const authStrategy = options.subscriptionAccounts.getStrategy("codex");
12285
- if (!authStrategy || authStrategy.providerId !== "codex") {
12846
+ const routedProviders = [...new Set(Object.values(config.models))];
12847
+ const codexStrategy = routedProviders.includes("codex-subscription") ? options.subscriptionAccounts.getStrategy("codex") : void 0;
12848
+ if (routedProviders.includes("codex-subscription") && (!codexStrategy || codexStrategy.providerId !== "codex")) {
12286
12849
  throw new TypeError("enabled image runtime requires the Codex subscription strategy");
12287
12850
  }
12851
+ const antigravityStrategy = routedProviders.includes("antigravity-subscription") ? options.subscriptionAccounts.getStrategy("antigravity") : void 0;
12852
+ if (routedProviders.includes("antigravity-subscription") && (!antigravityStrategy || antigravityStrategy.providerId !== "antigravity")) {
12853
+ throw new TypeError("enabled image runtime requires the Antigravity subscription strategy");
12854
+ }
12288
12855
  const privateHmacKey = options.privateHmacKey ? Buffer.from(options.privateHmacKey) : loadOrCreateImageTenantHmacSalt(options.storage.paths, randomBytes6);
12289
12856
  if (privateHmacKey.byteLength !== 32) {
12290
12857
  privateHmacKey.fill(0);
@@ -12319,23 +12886,32 @@ function createImageRuntimeGeneration(options) {
12319
12886
  if (options.testOnlySyntheticVerifiedProvider && options.testOnlySyntheticVerifiedProvider.label !== "synthetic-verified-image-provider-test-only") {
12320
12887
  throw new TypeError("synthetic verified image provider test seam label is invalid");
12321
12888
  }
12322
- const provider = options.testOnlySyntheticVerifiedProvider ? options.testOnlySyntheticVerifiedProvider.createProvider({
12889
+ const providers = options.testOnlySyntheticVerifiedProvider ? [options.testOnlySyntheticVerifiedProvider.createProvider({
12323
12890
  generationId: options.generationId,
12324
12891
  scheduler,
12325
12892
  now: options.now ?? Date.now,
12326
12893
  referenceStore: options.storage.referenceStore,
12327
12894
  stateStore: options.storage.stateStore
12328
- }) : createCodexSubscriptionImageProvider({
12329
- authStrategy,
12895
+ })] : routedProviders.map((providerId) => providerId === "codex-subscription" ? createCodexSubscriptionImageProvider({
12896
+ authStrategy: codexStrategy,
12330
12897
  evidenceSource: generationEvidenceSource,
12331
12898
  executionScheduler: scheduler,
12332
12899
  generationTimeoutMs: config.queue.generationTimeoutMs,
12900
+ now: options.now,
12901
+ wire: {
12902
+ imageModel: config.codex.imageModel,
12903
+ carrierModel: config.codex.carrierModel
12904
+ }
12905
+ }) : createAntigravitySubscriptionImageProvider({
12906
+ authStrategy: antigravityStrategy,
12907
+ executionScheduler: scheduler,
12908
+ generationTimeoutMs: config.queue.generationTimeoutMs,
12333
12909
  now: options.now
12334
- });
12335
- if (provider.id !== config.provider) {
12910
+ }));
12911
+ if (providers.length === 1 && providers[0].id !== "codex-subscription") {
12336
12912
  throw new TypeError("synthetic verified image provider id must match configured provider");
12337
12913
  }
12338
- const providerRegistry = new ImageProviderRegistry([provider]);
12914
+ const providerRegistry = new ImageProviderRegistry(providers);
12339
12915
  const orchestrator = new ImageOrchestrator({
12340
12916
  registry: providerRegistry,
12341
12917
  referenceStore: options.storage.referenceStore,
@@ -12357,35 +12933,53 @@ function createImageRuntimeGeneration(options) {
12357
12933
  ...options.createCallId ? { createCallId: options.createCallId } : {},
12358
12934
  ...options.now ? { now: options.now } : {}
12359
12935
  });
12936
+ const defaultProviderId = config.models[config.defaultModel] ?? "codex-subscription";
12937
+ const inspectOneProvider = async (providerId, apiKeyId) => {
12938
+ const capabilities = await orchestrator.getCapabilities(providerId, {
12939
+ requestId: `${options.generationId}:capability-inspection`,
12940
+ tenantId: apiKeyId,
12941
+ signal: new AbortController().signal,
12942
+ sessionKey: `outbound:images:${apiKeyId}`,
12943
+ ...config.account.id ? { preferredAccountId: config.account.id } : {},
12944
+ ...config.account.group ? { preferredAccountGroup: config.account.group } : {},
12945
+ boundAccountFallbackPolicy: config.account.fallback
12946
+ });
12947
+ return capabilities;
12948
+ };
12360
12949
  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) {
12950
+ const providerCapabilities = /* @__PURE__ */ new Map();
12951
+ let defaultProviderError;
12952
+ for (const providerId of [...new Set(Object.values(config.models))]) {
12953
+ try {
12954
+ providerCapabilities.set(providerId, await inspectOneProvider(providerId, apiKeyId));
12955
+ } catch (error) {
12956
+ if (providerId === defaultProviderId) defaultProviderError = error;
12957
+ }
12958
+ }
12959
+ const routedModels = Object.freeze(
12960
+ [...providerCapabilities.entries()].flatMap(([providerId, capabilities2]) => capabilities2.available === true && capabilities2.generate === true ? Object.entries(config.models).filter(([model, modelProvider]) => modelProvider === providerId && capabilities2.models.includes(model)).map(([model]) => model) : [])
12961
+ );
12962
+ const capabilities = providerCapabilities.get(defaultProviderId);
12963
+ if (!capabilities) {
12381
12964
  return Object.freeze({
12382
12965
  enabled: true,
12383
12966
  available: false,
12384
- providerId: config.provider,
12967
+ providerId: defaultProviderId,
12385
12968
  model: config.defaultModel,
12386
- reason: error instanceof ImageGenerationError4 && (error.code === "upstream_auth_required" || error.code === "invalid_api_key") ? "account_unverified" : "runtime_unavailable"
12969
+ routedModels,
12970
+ reason: defaultProviderError instanceof ImageGenerationError4 && (defaultProviderError.code === "upstream_auth_required" || defaultProviderError.code === "invalid_api_key") ? "account_unverified" : "runtime_unavailable"
12387
12971
  });
12388
12972
  }
12973
+ const available = capabilities.available === true && capabilities.generate === true && capabilities.models.includes(config.defaultModel);
12974
+ return Object.freeze({
12975
+ enabled: true,
12976
+ available,
12977
+ providerId: defaultProviderId,
12978
+ model: config.defaultModel,
12979
+ routedModels,
12980
+ ...!available ? { reason: capabilities.reason ?? "runtime_unavailable" } : {},
12981
+ capabilities
12982
+ });
12389
12983
  };
12390
12984
  const resolverToDispose = runtimeResolver;
12391
12985
  const schedulerToDispose = scheduler;
@@ -12423,7 +13017,7 @@ function createImageRuntimeGeneration(options) {
12423
13017
  imageApi,
12424
13018
  hosted,
12425
13019
  hostedRuntime: Object.freeze({
12426
- providerId: config.provider,
13020
+ providerId: defaultProviderId,
12427
13021
  imageModel: config.defaultModel,
12428
13022
  referenceTtlMs: config.references.ttlMs,
12429
13023
  maxOutputBytes: config.limits.maxOutputBytes,
@@ -15420,6 +16014,9 @@ var ImageRuntimeManager = class {
15420
16014
  }
15421
16015
  async listAvailableModels(apiKeyId) {
15422
16016
  const inspection = await this.inspectCapability(apiKeyId);
16017
+ if (inspection.routedModels !== void 0) {
16018
+ return Object.freeze([...inspection.routedModels]);
16019
+ }
15423
16020
  return inspection.available && inspection.model === "gpt-image-2" ? Object.freeze([inspection.model]) : Object.freeze([]);
15424
16021
  }
15425
16022
  resourceStatus() {
@@ -17635,11 +18232,13 @@ var JsonVoucherDb = class {
17635
18232
  // src/ports/JsonSubscriptionCredentialStore.ts
17636
18233
  import { existsSync as existsSync24, mkdirSync as mkdirSync6, readFileSync as readFileSync20, renameSync as renameSync13 } from "fs";
17637
18234
  import { dirname as dirname15 } from "path";
18235
+ import { getAntigravityProjectResolver as getAntigravityProjectResolver2 } from "@omnicross/core/auth/GeminiCodeAssistProjectResolver";
17638
18236
  import { getSharedAccountHealth as getSharedAccountHealth2 } from "@omnicross/core/pipeline/SubscriptionAccountHealth";
17639
18237
  import { getSharedAccountAllowanceScheduling as getSharedAccountAllowanceScheduling3 } from "@omnicross/core/pipeline/AccountAllowanceScheduling";
17640
- import { fetchUpstream as fetchUpstream10 } from "@omnicross/core/pipeline/upstreamFetch";
18238
+ import { fetchUpstream as fetchUpstream12 } from "@omnicross/core/pipeline/upstreamFetch";
17641
18239
  import { getSharedIdentityStore as getSharedIdentityStore2 } from "@omnicross/core/provider-proxy/identity/SubscriptionIdentityStore";
17642
18240
  import {
18241
+ antigravityOAuth as antigravityOAuth2,
17643
18242
  claudeOAuth as claudeOAuth2,
17644
18243
  codexOAuth as codexOAuth2,
17645
18244
  geminiOAuth as geminiOAuth2,
@@ -17793,7 +18392,7 @@ var JsonSubscriptionCredentialStore = class {
17793
18392
  * a plaintext token pair into `upstream-trace.jsonl`.
17794
18393
  */
17795
18394
  buildRefreshFetch(providerId, accountId) {
17796
- return this.fetchImpl ?? ((url, init) => fetchUpstream10(url, init, { providerId, accountId, redactBodies: true }));
18395
+ return this.fetchImpl ?? ((url, init) => fetchUpstream12(url, init, { providerId, accountId, redactBodies: true }));
17797
18396
  }
17798
18397
  /**
17799
18398
  * In-flight refresh coalescing. OAuth refresh tokens are
@@ -17834,7 +18433,7 @@ var JsonSubscriptionCredentialStore = class {
17834
18433
  * other hot reads. Never returns token material.
17835
18434
  */
17836
18435
  getAccountProxy(providerId, accountId) {
17837
- if (providerId !== "claude" && providerId !== "codex" && providerId !== "gemini" && providerId !== "opencodego" && providerId !== "kimi" && providerId !== "grok" && providerId !== "copilot") {
18436
+ if (providerId !== "claude" && providerId !== "codex" && providerId !== "gemini" && providerId !== "opencodego" && providerId !== "kimi" && providerId !== "grok" && providerId !== "copilot" && providerId !== "antigravity") {
17838
18437
  return void 0;
17839
18438
  }
17840
18439
  return getAccountProxy(this.readConfig(), providerId, accountId);
@@ -17853,7 +18452,7 @@ var JsonSubscriptionCredentialStore = class {
17853
18452
  const fingerprintOn = identityStore.isEnabled();
17854
18453
  const now = Date.now();
17855
18454
  const out = {};
17856
- for (const provider of ["claude", "codex", "gemini", "opencodego", "kimi", "grok", "copilot"]) {
18455
+ for (const provider of ["claude", "codex", "gemini", "opencodego", "kimi", "grok", "copilot", "antigravity"]) {
17857
18456
  const sanitized = sanitizeAccounts(config, provider);
17858
18457
  if (sanitized.length === 0) continue;
17859
18458
  for (const account of sanitized) {
@@ -18112,6 +18711,76 @@ var JsonSubscriptionCredentialStore = class {
18112
18711
  return false;
18113
18712
  });
18114
18713
  }
18714
+ /**
18715
+ * Refresh the Antigravity (Google) OAuth access token. Like gemini, the
18716
+ * Google token endpoint does NOT return a refresh_token on refresh, so this
18717
+ * writes ONLY access+expiresAt (+status/lastRefreshedAt) and DELIBERATELY
18718
+ * preserves the stored `refreshToken` — plus the account's `projectId`
18719
+ * (a handshake product; the post-refresh re-validation is the refresh
18720
+ * scheduler's hook, not this write) and `email`. HONEST `false` when no
18721
+ * refresh_token.
18722
+ */
18723
+ async refreshAntigravityToken() {
18724
+ return this.coalesce("antigravity:active", async () => {
18725
+ const config = this.readConfig();
18726
+ const active = getActiveAccount(config, "antigravity");
18727
+ const antigravity = active?.tokens;
18728
+ if (!active || !antigravity?.refreshToken) return false;
18729
+ const capturedId = active.id;
18730
+ this.materializeMigration(config);
18731
+ const refreshFetch = this.buildRefreshFetch("antigravity", capturedId);
18732
+ try {
18733
+ const result = await antigravityOAuth2.refreshAccessToken(antigravity.refreshToken, refreshFetch);
18734
+ const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
18735
+ const next = {
18736
+ ...antigravity,
18737
+ // KEEP the existing refreshToken/projectId/email.
18738
+ accessToken: result.accessToken,
18739
+ expiresAt,
18740
+ status: "authorized",
18741
+ lastRefreshedAt: (/* @__PURE__ */ new Date()).toISOString(),
18742
+ errorMessage: void 0
18743
+ };
18744
+ this.writeBackById("antigravity", capturedId, next);
18745
+ await this.revalidateAntigravityProject(capturedId);
18746
+ return true;
18747
+ } catch (error) {
18748
+ this.markExpiredById("antigravity", capturedId, antigravity, error);
18749
+ return false;
18750
+ }
18751
+ });
18752
+ }
18753
+ /**
18754
+ * Post-refresh project re-validation hook (antigravity design D8): after a
18755
+ * successful antigravity token refresh, re-run the Code Assist project
18756
+ * handshake and write the (possibly rotated) `projectId` back to the account.
18757
+ * A handshake FAILURE keeps the stored projectId untouched (logged) so the
18758
+ * account keeps serving with the last-known-good project until a later
18759
+ * refresh succeeds. Returns whether the handshake produced a project.
18760
+ */
18761
+ async revalidateAntigravityProject(accountId) {
18762
+ const before = getAccountById(this.readConfig(), "antigravity", accountId);
18763
+ const accessToken = before?.tokens?.accessToken;
18764
+ if (!accessToken) return false;
18765
+ try {
18766
+ const projectId = await getAntigravityProjectResolver2().resolveProject(accessToken);
18767
+ if (projectId !== void 0) {
18768
+ const config = this.readConfig();
18769
+ const account = getAccountById(config, "antigravity", accountId);
18770
+ const tokens = account?.tokens;
18771
+ if (account && tokens?.accessToken === accessToken && tokens.projectId !== projectId) {
18772
+ this.writeBackById("antigravity", accountId, { ...tokens, projectId });
18773
+ }
18774
+ return true;
18775
+ }
18776
+ return false;
18777
+ } catch (error) {
18778
+ console.warn(
18779
+ `[JsonSubscriptionCredentialStore] antigravity project re-validation failed for account ${accountId}: ` + (error instanceof Error ? error.message : String(error))
18780
+ );
18781
+ return false;
18782
+ }
18783
+ }
18115
18784
  /**
18116
18785
  * Refresh a SPECIFIC managed account by id (background scheduler sweep and
18117
18786
  * account-pool resolution). It uses only that account's stored refresh
@@ -18140,6 +18809,7 @@ var JsonSubscriptionCredentialStore = class {
18140
18809
  };
18141
18810
  if (refreshed.idToken) next.idToken = refreshed.idToken;
18142
18811
  this.writeBackById(provider, id, next);
18812
+ if (provider === "antigravity") await this.revalidateAntigravityProject(id);
18143
18813
  return true;
18144
18814
  } catch (error) {
18145
18815
  this.markExpiredById(provider, id, captured, error);
@@ -18164,7 +18834,7 @@ var JsonSubscriptionCredentialStore = class {
18164
18834
  }
18165
18835
  const oauth = account.tokens;
18166
18836
  if (!oauth.accessToken) return null;
18167
- if (providerId === "codex" || providerId === "gemini" || providerId === "kimi" || providerId === "grok" || providerId === "copilot") {
18837
+ if (providerId === "codex" || providerId === "gemini" || providerId === "kimi" || providerId === "grok" || providerId === "copilot" || providerId === "antigravity") {
18168
18838
  const expiresAtMs = oauth.expiresAt ? Date.parse(oauth.expiresAt) : 0;
18169
18839
  const expiringSoon = expiresAtMs > 0 && Date.now() >= expiresAtMs - ACCOUNT_REFRESH_LEAD_MS;
18170
18840
  if (expiringSoon && oauth.refreshToken) {
@@ -18280,6 +18950,13 @@ var JsonSubscriptionCredentialStore = class {
18280
18950
  if (provider === "copilot") {
18281
18951
  throw new Error("GitHub Copilot tokens cannot be refreshed \u2014 re-authenticate the account");
18282
18952
  }
18953
+ if (provider === "antigravity") {
18954
+ const r2 = await antigravityOAuth2.refreshAccessToken(refreshToken, refreshFetch);
18955
+ return {
18956
+ accessToken: r2.accessToken,
18957
+ expiresAt: new Date(Date.now() + r2.expiresIn * 1e3).toISOString()
18958
+ };
18959
+ }
18283
18960
  const flow = provider === "claude" ? claudeOAuth2 : provider === "codex" ? codexOAuth2 : geminiOAuth2;
18284
18961
  const r = await flow.refreshAccessToken(refreshToken, refreshFetch);
18285
18962
  return {
@@ -18523,7 +19200,7 @@ var JsonSubscriptionCredentialStore = class {
18523
19200
  };
18524
19201
 
18525
19202
  // src/AccountHealthProbeScheduler.ts
18526
- import { fetchUpstream as fetchUpstream11 } from "@omnicross/core/pipeline/upstreamFetch";
19203
+ import { fetchUpstream as fetchUpstream13 } from "@omnicross/core/pipeline/upstreamFetch";
18527
19204
 
18528
19205
  // src/probe/CodexGenerationProbe.ts
18529
19206
  import {
@@ -18678,7 +19355,11 @@ var PROVIDER_PROBE_PLANS = {
18678
19355
  // The Copilot quota endpoint (copilot_internal/user) is a verified FREE
18679
19356
  // authed GET but lives on api.github.com with its own auth dialect and a
18680
19357
  // monthly-only window — the allowance collector owns the health surface.
18681
- copilot: { kind: "local" }
19358
+ copilot: { kind: "local" },
19359
+ // Antigravity's quota endpoints are POST RPCs on daily-cloudcode-pa (not a
19360
+ // cheap GET) and need the antigravity/hub UA — the allowance collector owns
19361
+ // the health surface; the probe stays local.
19362
+ antigravity: { kind: "local" }
18682
19363
  };
18683
19364
  function probePlanFor(providerId) {
18684
19365
  return PROVIDER_PROBE_PLANS[providerId] ?? { kind: "local" };
@@ -18700,7 +19381,7 @@ var AccountHealthProbeScheduler = class {
18700
19381
  this.logger = logger;
18701
19382
  this.config = config;
18702
19383
  this.now = opts.now ?? Date.now;
18703
- this.fetchImpl = opts.fetchImpl ?? fetchUpstream11;
19384
+ this.fetchImpl = opts.fetchImpl ?? fetchUpstream13;
18704
19385
  this.sleep = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
18705
19386
  this.planFor = opts.planFor ?? probePlanFor;
18706
19387
  }
@@ -19863,7 +20544,7 @@ var AuditWriter = class {
19863
20544
  import { appendFileSync as appendFileSync3, mkdirSync as mkdirSync8 } from "fs";
19864
20545
  import { createHmac as createHmac5 } from "crypto";
19865
20546
  import { join as join27 } from "path";
19866
- import { fetchUpstream as fetchUpstream12 } from "@omnicross/core/pipeline/upstreamFetch";
20547
+ import { fetchUpstream as fetchUpstream14 } from "@omnicross/core/pipeline/upstreamFetch";
19867
20548
 
19868
20549
  // src/billing/billingFiles.ts
19869
20550
  var BILLING_FILE_RE = /^billing-(\d{4})-(\d{2})-(\d{2})\.jsonl$/;
@@ -19886,7 +20567,7 @@ var BillingPublisher = class {
19886
20567
  constructor(billingDir, logger, opts = {}) {
19887
20568
  this.billingDir = billingDir;
19888
20569
  this.logger = logger;
19889
- this.fetchImpl = opts.fetchImpl ?? ((url, init) => fetchUpstream12(url, init));
20570
+ this.fetchImpl = opts.fetchImpl ?? ((url, init) => fetchUpstream14(url, init));
19890
20571
  this.defer = opts.defer ?? ((fn) => setTimeout(fn, 0));
19891
20572
  this.timeoutMs = opts.timeoutMs ?? BILLING_POST_TIMEOUT_MS;
19892
20573
  this.now = opts.now ?? Date.now;
@@ -20136,7 +20817,7 @@ var BillingRetrySweeper = class {
20136
20817
  // src/TokenRefreshScheduler.ts
20137
20818
  var REFRESH_LEAD_MS2 = 5 * 6e4;
20138
20819
  var SWEEP_INTERVAL_MS5 = 6e4;
20139
- var OAUTH_PROVIDERS2 = ["claude", "codex", "gemini", "kimi", "grok", "copilot"];
20820
+ var OAUTH_PROVIDERS2 = ["claude", "codex", "gemini", "kimi", "grok", "copilot", "antigravity"];
20140
20821
  var TokenRefreshScheduler = class {
20141
20822
  constructor(store, logger, intervalMs = SWEEP_INTERVAL_MS5, leadMs = REFRESH_LEAD_MS2) {
20142
20823
  this.store = store;
@@ -20227,6 +20908,8 @@ var TokenRefreshScheduler = class {
20227
20908
  // never reaches this — the branch exists for union totality.
20228
20909
  case "copilot":
20229
20910
  return this.store.refreshCopilotToken();
20911
+ case "antigravity":
20912
+ return this.store.refreshAntigravityToken();
20230
20913
  }
20231
20914
  }
20232
20915
  };
@@ -20305,7 +20988,7 @@ function createRouteLeaseSubscriptionPreflight(credentials) {
20305
20988
 
20306
20989
  // src/webhook/WebhookDispatcher.ts
20307
20990
  import { createHmac as createHmac6 } from "crypto";
20308
- import { fetchUpstream as fetchUpstream13 } from "@omnicross/core/pipeline/upstreamFetch";
20991
+ import { fetchUpstream as fetchUpstream15 } from "@omnicross/core/pipeline/upstreamFetch";
20309
20992
  var WEBHOOK_MAX_ATTEMPTS = 3;
20310
20993
  var WEBHOOK_QUEUE_MAX = 1e3;
20311
20994
  var WEBHOOK_SEND_TIMEOUT_MS = 1e4;
@@ -20325,7 +21008,7 @@ var WebhookDispatcher = class {
20325
21008
  sleep;
20326
21009
  now;
20327
21010
  constructor(opts = {}) {
20328
- this.fetchImpl = opts.fetchImpl ?? ((url, init) => fetchUpstream13(url, init));
21011
+ this.fetchImpl = opts.fetchImpl ?? ((url, init) => fetchUpstream15(url, init));
20329
21012
  this.logger = opts.logger;
20330
21013
  this.maxAttempts = opts.maxAttempts ?? WEBHOOK_MAX_ATTEMPTS;
20331
21014
  this.queueMax = opts.queueMax ?? WEBHOOK_QUEUE_MAX;
@@ -20411,8 +21094,8 @@ var WebhookDispatcher = class {
20411
21094
  signal: AbortSignal.timeout(this.timeoutMs)
20412
21095
  });
20413
21096
  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) };
21097
+ } catch (err9) {
21098
+ return { ok: false, error: err9 instanceof Error ? err9.message : String(err9) };
20416
21099
  }
20417
21100
  }
20418
21101
  /**
@@ -20549,7 +21232,7 @@ function buildDaemon(config, paths) {
20549
21232
  setSecretBox(secretBox3);
20550
21233
  setSecretBox2(secretBox3);
20551
21234
  const decryptedConfig = decryptConfigSecrets(config, secretBox3);
20552
- const accountAllowanceStore = new AccountAllowanceStore9(
21235
+ const accountAllowanceStore = new AccountAllowanceStore10(
20553
21236
  Date.now,
20554
21237
  void 0,
20555
21238
  new JsonAccountAllowancePersistence(defaultAccountAllowancePath(paths.configPath))
@@ -20593,6 +21276,8 @@ function buildDaemon(config, paths) {
20593
21276
  })
20594
21277
  );
20595
21278
  setGeminiCodeAssistResolver(getGeminiCodeAssistProjectResolver2());
21279
+ setAntigravitySandboxFailover(decryptedConfig.antigravity?.sandboxFailover === true);
21280
+ setOpenCodeGoUserAgent(decryptedConfig.opencodego?.userAgent ?? null);
20596
21281
  const autoDisableStore = new AutoDisableStore();
20597
21282
  const providerKeyQuotaService = new ProviderKeyQuotaService(secretBox3);
20598
21283
  const apiKeyPool = new ApiKeyPoolService(
@@ -20611,7 +21296,7 @@ function buildDaemon(config, paths) {
20611
21296
  const pricingEngine = new PricingEngine(pricingStore, logger, {
20612
21297
  // Catalog egress follows the same global/env proxy policy as every other
20613
21298
  // daemon upstream call; no provider/account override applies here.
20614
- fetchImpl: ((input, init) => fetchUpstream14(String(input), init ?? {}))
21299
+ fetchImpl: ((input, init) => fetchUpstream16(String(input), init ?? {}))
20615
21300
  });
20616
21301
  const pricingRefreshScheduler = new PricingRefreshScheduler(
20617
21302
  pricingEngine,
@@ -20896,7 +21581,7 @@ function buildDaemon(config, paths) {
20896
21581
  // — `server.proxy.byProvider[...]` was silently skipped — and the call was
20897
21582
  // excluded from the upstream trace, so a failing login left no evidence.
20898
21583
  // `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 }),
21584
+ oauthExchangeFetch: paths.oauthExchangeFetch ? () => paths.oauthExchangeFetch : (providerId) => (url, init) => fetchUpstream16(url, init, { providerId, redactBodies: true }),
20900
21585
  subscriptionAccountAppender: credentialStore,
20901
21586
  // Codex interactive OAuth (app-parity-2 child 5) — the async loopback flow store
20902
21587
  // + the one-shot 127.0.0.1:1455 listener. Token captured + persisted daemon-side;
@@ -20911,6 +21596,21 @@ function buildDaemon(config, paths) {
20911
21596
  // Grok interactive OAuth — the same async DEVICE-CODE shape as kimi.
20912
21597
  grokSessions: new CodexOAuthSessionStore(),
20913
21598
  copilotSessions: new CodexOAuthSessionStore(),
21599
+ // Antigravity interactive OAuth — the async LOOPBACK flow store + the
21600
+ // one-shot 127.0.0.1:51121 listener (same shape as codex; test seam below).
21601
+ antigravitySessions: new CodexOAuthSessionStore(),
21602
+ antigravityAwaitLoopback: paths.antigravityAwaitLoopback ?? ((state, timeoutMs, signal) => awaitLoopbackCode(state, timeoutMs, signal, {
21603
+ port: 51121,
21604
+ path: "/oauth-callback",
21605
+ label: "antigravity"
21606
+ })),
21607
+ // The dynamic model-catalog probe's token source (the ACTIVE antigravity
21608
+ // account; refreshed by the by-id near-expiry seam inside the lookup).
21609
+ resolveAntigravityAccessToken: async () => {
21610
+ const config2 = await credentialStore.getFullConfig();
21611
+ const activeId = config2.activeAntigravityAccountId ?? config2.antigravityAccounts?.[0]?.id;
21612
+ return activeId ? credentialStore.getAccessTokenForAccount("antigravity", activeId) : null;
21613
+ },
20914
21614
  // Migration pack (app-parity child 6, design D2/D3) — the concrete credential
20915
21615
  // store provides BOTH the full DECRYPTED read (`getFullConfig`, export) and
20916
21616
  // the multi-account append (`appendProviderAccount`, import re-encrypts at-
@@ -20969,7 +21669,7 @@ function buildDaemon(config, paths) {
20969
21669
  });
20970
21670
  const webhookDispatcher = new WebhookDispatcher({
20971
21671
  logger,
20972
- fetchImpl: (url, init) => fetchUpstream14(url, init)
21672
+ fetchImpl: (url, init) => fetchUpstream16(url, init)
20973
21673
  });
20974
21674
  setWebhookRuntime(webhookDispatcher, getSharedAccountHealth4());
20975
21675
  const auditWriter = new AuditWriter(auditDir, logger);
@@ -21104,15 +21804,59 @@ function buildClaudeDoctorChecks(config) {
21104
21804
  });
21105
21805
  return checks;
21106
21806
  }
21807
+ function buildAntigravityDoctorChecks(snapshot) {
21808
+ const checks = [];
21809
+ checks.push({
21810
+ name: "antigravity credential",
21811
+ ok: snapshot.accountCount > 0 && snapshot.hasAccessToken,
21812
+ 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"}`
21813
+ });
21814
+ const expiresAtMs = snapshot.expiresAt ? Date.parse(snapshot.expiresAt) : 0;
21815
+ const expired = snapshot.expired || expiresAtMs > 0 && Date.now() >= expiresAtMs;
21816
+ const expiringSoon = expiresAtMs > 0 && Date.now() >= expiresAtMs - 10 * 6e4;
21817
+ checks.push({
21818
+ name: "token freshness",
21819
+ ok: !expired,
21820
+ warn: !expired && expiringSoon,
21821
+ 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)"
21822
+ });
21823
+ return checks;
21824
+ }
21825
+ function hasFreshAntigravityQuota(snapshot, now = Date.now()) {
21826
+ if (!snapshot || snapshot.lastErrorCode) return false;
21827
+ if (snapshot.expiresAt && !(Date.parse(snapshot.expiresAt) > now)) return false;
21828
+ return snapshot.windows.some(
21829
+ (window) => window.state === "fresh" && (!window.resetsAt || Date.parse(window.resetsAt) > now) && (window.disabled === true || typeof window.usedPercent === "number" && Number.isFinite(window.usedPercent))
21830
+ );
21831
+ }
21832
+ function buildAntigravityLiveChecks(result) {
21833
+ return [
21834
+ {
21835
+ name: "token refresh (--live)",
21836
+ ok: result.refreshOk,
21837
+ detail: result.refreshOk ? "the active account refreshed successfully" : "refresh failed (see the daemon log)"
21838
+ },
21839
+ {
21840
+ name: "quota collection (--live)",
21841
+ ok: result.quotaOk,
21842
+ detail: result.quotaOk ? "quotaSummary windows collected" : result.detail
21843
+ }
21844
+ ];
21845
+ }
21107
21846
  function buildImagesDoctorChecks(snapshot) {
21108
21847
  const enabled = snapshot.config.enabled;
21109
- const accountOk = !enabled || snapshot.account.usable;
21848
+ const routed = snapshot.config.routedProviders ?? ["codex-subscription"];
21849
+ const codexRouted = routed.includes("codex-subscription");
21850
+ const antigravityRouted = routed.includes("antigravity-subscription");
21851
+ const antigravity = snapshot.antigravityAccount ?? { present: false, usable: false, reason: "missing" };
21852
+ const accountOk = !enabled || !codexRouted || snapshot.account.usable;
21853
+ const antigravityOk = !enabled || !antigravityRouted || antigravity.usable;
21110
21854
  const evidenceOk = !enabled || snapshot.evidence.valid && snapshot.evidence.freshEntries > 0;
21111
21855
  return [
21112
21856
  {
21113
21857
  name: "normalized Images config",
21114
21858
  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))`
21859
+ 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
21860
  },
21117
21861
  {
21118
21862
  name: "private roots",
@@ -21133,8 +21877,14 @@ function buildImagesDoctorChecks(snapshot) {
21133
21877
  {
21134
21878
  name: "Codex account",
21135
21879
  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`
21880
+ warn: enabled && codexRouted && !snapshot.account.usable,
21881
+ 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`
21882
+ },
21883
+ {
21884
+ name: "Antigravity account",
21885
+ ok: antigravityOk,
21886
+ warn: enabled && antigravityRouted && !antigravity.usable,
21887
+ 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
21888
  },
21139
21889
  {
21140
21890
  name: "cached capability evidence",
@@ -21149,6 +21899,12 @@ async function runImagesLiveDoctor(config, doctor, signal = new AbortController(
21149
21899
  " [\u26A0] live Images verification may consume subscription quota; one minimal low-quality PNG request will be sent"
21150
21900
  );
21151
21901
  const result = await doctor.verifyLive(config.images ?? DEFAULT_IMAGES_SERVER_CONFIG2, signal);
21902
+ const antigravityRouted = Object.values(config.images?.models ?? {}).includes("antigravity-subscription");
21903
+ if (antigravityRouted) {
21904
+ console.info(
21905
+ " [i] live verification covers the Codex wire only; the Antigravity provider has no independent verifier in v1 (its first real request bootstraps)"
21906
+ );
21907
+ }
21152
21908
  if (!result.ok) {
21153
21909
  console.info(` [\u2717] live Images verification: ${result.code}`);
21154
21910
  return false;
@@ -21283,14 +22039,49 @@ async function runLiveProbe(url, key, fetchImpl = fetch) {
21283
22039
  status: res.status,
21284
22040
  estimateHeader: res.headers.get("x-omnicross-count-estimate")
21285
22041
  };
21286
- } catch (err8) {
22042
+ } catch (err9) {
21287
22043
  return {
21288
22044
  status: null,
21289
22045
  estimateHeader: null,
21290
- error: err8 instanceof Error ? err8.message : String(err8)
22046
+ error: err9 instanceof Error ? err9.message : String(err9)
21291
22047
  };
21292
22048
  }
21293
22049
  }
22050
+ async function runAntigravityDoctor(daemon, live) {
22051
+ const config = await daemon.credentialStore.getFullConfig();
22052
+ const accounts = config.antigravityAccounts ?? [];
22053
+ const activeId = config.activeAntigravityAccountId ?? accounts[0]?.id;
22054
+ const active = accounts.find((account) => account.id === activeId);
22055
+ const snapshot = {
22056
+ accountCount: accounts.length,
22057
+ ...active?.tokens.email ? { activeEmail: active.tokens.email } : {},
22058
+ hasAccessToken: Boolean(active?.tokens.accessToken),
22059
+ expired: active?.tokens.status === "expired",
22060
+ ...active?.tokens.expiresAt ? { expiresAt: active.tokens.expiresAt } : {}
22061
+ };
22062
+ const checks = buildAntigravityDoctorChecks(snapshot);
22063
+ if (live && active) {
22064
+ const refreshOk = await daemon.credentialStore.refreshAntigravityToken();
22065
+ let quotaOk = false;
22066
+ let detail = "quotaSummary collection produced no usable windows";
22067
+ try {
22068
+ const snapshots = await daemon.accountAllowanceService.refreshAntigravity(active.id);
22069
+ quotaOk = hasFreshAntigravityQuota(snapshots.find((entry) => entry.accountId === active.id));
22070
+ if (!quotaOk) detail = snapshots[0]?.lastErrorCode ?? detail;
22071
+ } catch (error) {
22072
+ detail = error instanceof Error ? error.message : String(error);
22073
+ }
22074
+ checks.push(...buildAntigravityLiveChecks({ refreshOk, quotaOk, detail }));
22075
+ }
22076
+ console.info("omnicross doctor antigravity \u2014 subscription credential health");
22077
+ let hardFailure = false;
22078
+ for (const check of checks) {
22079
+ const mark = check.ok ? check.warn ? "\u26A0" : "\u2713" : "\u2717";
22080
+ if (!check.ok) hardFailure = true;
22081
+ console.info(` [${mark}] ${check.name}: ${check.detail}`);
22082
+ }
22083
+ return hardFailure ? 1 : 0;
22084
+ }
21294
22085
  async function runDoctor(argv, fetchImpl = fetch) {
21295
22086
  const { values, positionals } = parseArgs2({
21296
22087
  args: argv,
@@ -21304,8 +22095,8 @@ async function runDoctor(argv, fetchImpl = fetch) {
21304
22095
  allowPositionals: true
21305
22096
  });
21306
22097
  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')`);
22098
+ if (subject !== "claude" && subject !== "images" && subject !== "search" && subject !== "antigravity") {
22099
+ throw new Error(`doctor: unknown subject '${subject}' (supported: 'claude', 'images', 'search', 'antigravity')`);
21309
22100
  }
21310
22101
  const configPath = values.config;
21311
22102
  if (!configPath) {
@@ -21328,6 +22119,9 @@ async function runDoctor(argv, fetchImpl = fetch) {
21328
22119
  runtime: daemon.searchRuntime
21329
22120
  });
21330
22121
  }
22122
+ if (subject === "antigravity") {
22123
+ return await runAntigravityDoctor(daemon, values.live === true);
22124
+ }
21331
22125
  const checks = subject === "images" ? buildImagesDoctorChecks(await daemon.imageDoctor.inspectLocal(
21332
22126
  serverConfig.images ?? DEFAULT_IMAGES_SERVER_CONFIG2
21333
22127
  )) : buildClaudeDoctorChecks(serverConfig);
@@ -21697,9 +22491,9 @@ async function runLaunch(argv, deps) {
21697
22491
  await daemon.llmConfig.ready();
21698
22492
  await daemon.migrateUsageStore();
21699
22493
  await daemon.providerProxy.start();
21700
- } catch (err8) {
22494
+ } catch (err9) {
21701
22495
  await shutdownLaunchDaemon(daemon);
21702
- throw err8;
22496
+ throw err9;
21703
22497
  }
21704
22498
  let launch;
21705
22499
  try {
@@ -21707,9 +22501,9 @@ async function runLaunch(argv, deps) {
21707
22501
  providerId: values.provider,
21708
22502
  model: values.model
21709
22503
  });
21710
- } catch (err8) {
22504
+ } catch (err9) {
21711
22505
  await shutdownLaunchDaemon(daemon);
21712
- throw err8;
22506
+ throw err9;
21713
22507
  }
21714
22508
  try {
21715
22509
  const plan = buildCliSpawnPlan({
@@ -21814,9 +22608,9 @@ function spawnCliInherit(plan) {
21814
22608
  process.removeListener("SIGINT", onSignal);
21815
22609
  process.removeListener("SIGTERM", onSignal);
21816
22610
  };
21817
- child.on("error", (err8) => {
22611
+ child.on("error", (err9) => {
21818
22612
  detach();
21819
- if (err8.code === "ENOENT") {
22613
+ if (err9.code === "ENOENT") {
21820
22614
  reject(
21821
22615
  new Error(
21822
22616
  `launch: "${plan.command}" not found on PATH \u2014 install the CLI first.`
@@ -21824,7 +22618,7 @@ function spawnCliInherit(plan) {
21824
22618
  );
21825
22619
  return;
21826
22620
  }
21827
- reject(err8);
22621
+ reject(err9);
21828
22622
  });
21829
22623
  child.on("exit", (code, signal) => {
21830
22624
  detach();
@@ -21837,8 +22631,10 @@ function spawnCliInherit(plan) {
21837
22631
  import { spawn as spawn3 } from "child_process";
21838
22632
  import { createInterface as createInterface2 } from "readline";
21839
22633
  import { parseArgs as parseArgs7 } from "util";
21840
- import { fetchUpstream as fetchUpstream15, setUpstreamProxyResolver as setUpstreamProxyResolver2 } from "@omnicross/core/pipeline/upstreamFetch";
22634
+ import { getAntigravityProjectResolver as getAntigravityProjectResolver3 } from "@omnicross/core/auth/GeminiCodeAssistProjectResolver";
22635
+ import { fetchUpstream as fetchUpstream17, setUpstreamProxyResolver as setUpstreamProxyResolver2 } from "@omnicross/core/pipeline/upstreamFetch";
21841
22636
  import {
22637
+ antigravityOAuth as antigravityOAuth3,
21842
22638
  claudeOAuth as claudeOAuth3,
21843
22639
  codexOAuth as codexOAuth3,
21844
22640
  copilotOAuth as copilotOAuth3,
@@ -21846,7 +22642,7 @@ import {
21846
22642
  grokOAuth as grokOAuth3,
21847
22643
  kimiOAuth as kimiOAuth3
21848
22644
  } from "@omnicross/subscriptions";
21849
- var PROVIDERS2 = ["claude", "codex", "gemini", "kimi", "grok", "copilot"];
22645
+ var PROVIDERS2 = ["claude", "codex", "gemini", "kimi", "grok", "copilot", "antigravity"];
21850
22646
  async function runLogin(argv, deps) {
21851
22647
  const { values, positionals } = parseArgs7({
21852
22648
  args: argv,
@@ -21877,7 +22673,7 @@ async function runLogin(argv, deps) {
21877
22673
  const resolved = {
21878
22674
  openBrowser: deps?.openBrowser ?? openBrowser,
21879
22675
  promptPaste: deps?.promptPaste ?? promptPaste,
21880
- awaitLoopback: deps?.awaitLoopback ?? ((state) => awaitLoopbackCode(state)),
22676
+ awaitLoopback: deps?.awaitLoopback ?? ((state, timeoutMs, signal, binding) => awaitLoopbackCode(state, timeoutMs, signal, binding)),
21881
22677
  awaitKimiDevice: deps?.awaitKimiDevice ?? ((fetchImpl) => runKimiDeviceFlow(fetchImpl, resolvedOpenBrowser)),
21882
22678
  awaitGrokDevice: deps?.awaitGrokDevice ?? ((fetchImpl) => runGrokDeviceFlow(fetchImpl, resolvedOpenBrowser)),
21883
22679
  awaitCopilotDevice: deps?.awaitCopilotDevice ?? ((fetchImpl, enterpriseUrl) => runCopilotDeviceFlow(fetchImpl, resolvedOpenBrowser, enterpriseUrl)),
@@ -21889,7 +22685,7 @@ async function runLogin(argv, deps) {
21889
22685
  setUpstreamProxyResolver2(createUpstreamProxyResolver());
21890
22686
  try {
21891
22687
  const tokensPath = defaultTokensPath(values.config);
21892
- const exchangeFetch = resolved.tokensFetch ?? ((url, init) => fetchUpstream15(url, init, { providerId: provider, redactBodies: true }));
22688
+ const exchangeFetch = resolved.tokensFetch ?? ((url, init) => fetchUpstream17(url, init, { providerId: provider, redactBodies: true }));
21893
22689
  const store = new JsonSubscriptionCredentialStore(tokensPath, box, exchangeFetch);
21894
22690
  const expiresAt = await runProviderLogin(
21895
22691
  provider,
@@ -21912,6 +22708,7 @@ async function runProviderLogin(provider, store, deps, exchangeFetch, label, ent
21912
22708
  if (provider === "kimi") return loginKimi(store, deps, exchangeFetch, label);
21913
22709
  if (provider === "grok") return loginGrok(store, deps, exchangeFetch, label);
21914
22710
  if (provider === "copilot") return loginCopilot(store, deps, exchangeFetch, label, enterpriseUrl);
22711
+ if (provider === "antigravity") return loginAntigravity(store, deps, exchangeFetch, label);
21915
22712
  return loginGemini(store, deps, exchangeFetch, label);
21916
22713
  }
21917
22714
  async function loginCodex(store, deps, exchangeFetch, label) {
@@ -22105,6 +22902,70 @@ async function loginCopilot(store, deps, exchangeFetch, label, enterpriseUrl) {
22105
22902
  logMasked("copilot", result.accessToken);
22106
22903
  return expiresAt;
22107
22904
  }
22905
+ async function loginAntigravity(store, deps, exchangeFetch, label) {
22906
+ const { authUrl, state } = antigravityOAuth3.generateAuthParams();
22907
+ await presentUrl(authUrl, deps);
22908
+ const code = await captureAntigravityCode(deps, state);
22909
+ const result = await antigravityOAuth3.exchangeCodeForTokens(code, exchangeFetch);
22910
+ const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
22911
+ const email = await antigravityOAuth3.fetchUserEmail(result.accessToken, exchangeFetch);
22912
+ console.info("Resolving the Antigravity Cloud Code Assist project...");
22913
+ const projectId = await getAntigravityProjectResolver3().resolveProject(result.accessToken);
22914
+ const block = {
22915
+ authMethod: "oauth",
22916
+ status: "authorized",
22917
+ accessToken: result.accessToken,
22918
+ refreshToken: result.refreshToken,
22919
+ expiresAt,
22920
+ ...email ? { email } : {},
22921
+ ...projectId ? { projectId } : {},
22922
+ lastRefreshedAt: (/* @__PURE__ */ new Date()).toISOString()
22923
+ };
22924
+ await store.appendProviderAccount("antigravity", block, label);
22925
+ logMasked("antigravity", result.accessToken);
22926
+ return expiresAt;
22927
+ }
22928
+ async function captureAntigravityCode(deps, state) {
22929
+ try {
22930
+ return await deps.awaitLoopback(state, void 0, void 0, {
22931
+ port: 51121,
22932
+ path: "/oauth-callback",
22933
+ label: "antigravity"
22934
+ });
22935
+ } catch (loopbackError) {
22936
+ const reason = loopbackError instanceof Error ? loopbackError.message : String(loopbackError);
22937
+ console.warn(`(loopback capture unavailable: ${reason})`);
22938
+ console.info(
22939
+ "Paste fallback: after authorizing, copy the failing redirect URL (or just its code parameter) here."
22940
+ );
22941
+ const pasted = (await deps.promptPaste("Paste the authorization code (or redirect URL): ")).trim();
22942
+ if (!pasted) throw new Error("login: no authorization code was pasted");
22943
+ const { code, state: pastedState } = parseAntigravityPaste(pasted);
22944
+ if (!code) throw new Error("login: the pasted value carried no authorization code");
22945
+ if (pastedState && pastedState !== state) {
22946
+ throw new Error("login: pasted state did not match (possible CSRF) \u2014 aborting");
22947
+ }
22948
+ return code;
22949
+ }
22950
+ }
22951
+ function parseAntigravityPaste(pasted) {
22952
+ if (pasted.includes("://")) {
22953
+ try {
22954
+ const url = new URL(pasted);
22955
+ const code = url.searchParams.get("code") ?? "";
22956
+ const state = url.searchParams.get("state") ?? void 0;
22957
+ return { code, ...state ? { state } : {} };
22958
+ } catch {
22959
+ }
22960
+ }
22961
+ if (/^[?]?code=/.test(pasted)) {
22962
+ const params = new URLSearchParams(pasted.replace(/^\?/, ""));
22963
+ const code = params.get("code") ?? "";
22964
+ const state = params.get("state") ?? void 0;
22965
+ return { code, ...state ? { state } : {} };
22966
+ }
22967
+ return { code: pasted };
22968
+ }
22108
22969
  function isLoginProvider(value) {
22109
22970
  return PROVIDERS2.includes(value);
22110
22971
  }
@@ -22526,7 +23387,11 @@ var TOKEN_FIELDS2 = {
22526
23387
  claude: ["accessToken", "refreshToken"],
22527
23388
  codex: ["accessToken", "refreshToken", "idToken"],
22528
23389
  gemini: ["accessToken", "refreshToken"],
22529
- opencodego: ["apiKey"]
23390
+ opencodego: ["apiKey"],
23391
+ kimi: ["accessToken", "refreshToken"],
23392
+ grok: ["accessToken", "refreshToken"],
23393
+ copilot: ["accessToken", "refreshToken"],
23394
+ antigravity: ["accessToken", "refreshToken"]
22530
23395
  };
22531
23396
  function walkTokens(raw, fn) {
22532
23397
  const next = { ...raw };
@@ -22810,7 +23675,7 @@ async function main() {
22810
23675
  process.exitCode = 1;
22811
23676
  }
22812
23677
  }
22813
- main().catch((err8) => {
22814
- console.error(err8 instanceof Error ? err8.message : String(err8));
23678
+ main().catch((err9) => {
23679
+ console.error(err9 instanceof Error ? err9.message : String(err9));
22815
23680
  process.exitCode = 1;
22816
23681
  });