@omnicross/daemon 0.4.2 → 0.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.cjs CHANGED
@@ -953,7 +953,11 @@ var TOKEN_FIELDS = {
953
953
  claude: ["accessToken", "refreshToken"],
954
954
  codex: ["accessToken", "refreshToken", "idToken"],
955
955
  gemini: ["accessToken", "refreshToken"],
956
- opencodego: ["apiKey"]
956
+ opencodego: ["apiKey"],
957
+ kimi: ["accessToken", "refreshToken"],
958
+ grok: ["accessToken", "refreshToken"],
959
+ copilot: ["accessToken", "refreshToken"],
960
+ antigravity: ["accessToken", "refreshToken"]
957
961
  };
958
962
  function transformTokenBlock(block, fields, fn) {
959
963
  const next = { ...block };
@@ -1171,21 +1175,23 @@ var import_node_path36 = require("path");
1171
1175
  var import_audit_types = require("@omnicross/contracts/audit-types");
1172
1176
  var import_billing_types = require("@omnicross/contracts/billing-types");
1173
1177
  var import_core7 = require("@omnicross/core");
1174
- var import_GeminiCodeAssistProjectResolver2 = require("@omnicross/core/auth/GeminiCodeAssistProjectResolver");
1178
+ var import_GeminiCodeAssistProjectResolver6 = require("@omnicross/core/auth/GeminiCodeAssistProjectResolver");
1175
1179
  var import_ApiKeyPoolService = require("@omnicross/core/completion/ApiKeyPoolService");
1176
1180
  var import_outbound_api10 = require("@omnicross/core/outbound-api");
1177
1181
  var import_subscriptionRegistryPort = require("@omnicross/core/outbound-api/subscriptionRegistryPort");
1178
1182
  var import_SubscriptionAccountHealth4 = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
1179
- var import_AccountAllowanceStore10 = require("@omnicross/core/pipeline/AccountAllowanceStore");
1183
+ var import_AccountAllowanceStore11 = require("@omnicross/core/pipeline/AccountAllowanceStore");
1180
1184
  var import_AccountAllowanceScheduling5 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
1181
- var import_upstreamFetch16 = require("@omnicross/core/pipeline/upstreamFetch");
1185
+ var import_upstreamFetch18 = require("@omnicross/core/pipeline/upstreamFetch");
1182
1186
  var import_SubscriptionIdentityStore3 = require("@omnicross/core/provider-proxy/identity/SubscriptionIdentityStore");
1183
1187
  var import_gemini_code_assist_resolver = require("@omnicross/core/ports/gemini-code-assist-resolver");
1188
+ var import_antigravityFailover = require("@omnicross/core/transformer/transformers/antigravityFailover");
1189
+ var import_openCodeGoHeaders2 = require("@omnicross/core/provider-proxy/identity/openCodeGoHeaders");
1184
1190
  var import_provider_proxy4 = require("@omnicross/core/provider-proxy");
1185
1191
  var import_cli_launcher2 = require("@omnicross/cli-launcher");
1186
1192
  var import_outbound_api11 = require("@omnicross/core/outbound-api");
1187
1193
  var import_usage2 = require("@omnicross/core/usage");
1188
- var import_subscriptions12 = require("@omnicross/subscriptions");
1194
+ var import_subscriptions13 = require("@omnicross/subscriptions");
1189
1195
 
1190
1196
  // src/admin/accountsCodexOAuth.ts
1191
1197
  var import_node_crypto3 = __toESM(require("crypto"), 1);
@@ -1547,7 +1553,7 @@ function handleCopilotOAuthStatus(sessionId, deps) {
1547
1553
  }
1548
1554
 
1549
1555
  // src/allowance/AccountAllowanceService.ts
1550
- var import_AccountAllowanceStore8 = require("@omnicross/core/pipeline/AccountAllowanceStore");
1556
+ var import_AccountAllowanceStore9 = require("@omnicross/core/pipeline/AccountAllowanceStore");
1551
1557
  var import_AccountAllowanceScheduling = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
1552
1558
 
1553
1559
  // src/allowance/ClaudeAllowanceCollector.ts
@@ -2917,9 +2923,321 @@ var GeminiAllowanceCollector = class {
2917
2923
  }
2918
2924
  };
2919
2925
 
2920
- // src/allowance/OpenCodeGoAllowanceCollector.ts
2926
+ // src/allowance/AntigravityAllowanceCollector.ts
2927
+ var import_GeminiCodeAssistProjectResolver2 = require("@omnicross/core/auth/GeminiCodeAssistProjectResolver");
2928
+ var import_antigravityQuotaFamily = require("@omnicross/core/pipeline/antigravityQuotaFamily");
2921
2929
  var import_AccountAllowanceStore7 = require("@omnicross/core/pipeline/AccountAllowanceStore");
2922
2930
  var import_upstreamFetch7 = require("@omnicross/core/pipeline/upstreamFetch");
2931
+ var import_antigravityIdentity = require("@omnicross/core/transformer/transformers/antigravityIdentity");
2932
+ var ANTIGRAVITY_ALLOWANCE_CACHE_MS = 5 * 6e4;
2933
+ var RETRIEVE_USER_QUOTA_SUMMARY_PATH = "/v1internal:retrieveUserQuotaSummary";
2934
+ var FETCH_AVAILABLE_MODELS_PATH = "/v1internal:fetchAvailableModels";
2935
+ var ANTIGRAVITY_DISCOVERY_DENYLIST = /* @__PURE__ */ new Set([
2936
+ "chat_20706",
2937
+ "chat_23310",
2938
+ "gemini-2.5-pro"
2939
+ ]);
2940
+ function isRecord5(value) {
2941
+ return !!value && typeof value === "object" && !Array.isArray(value);
2942
+ }
2943
+ function secondsUntil7(instant, now) {
2944
+ if (!instant) return void 0;
2945
+ return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
2946
+ }
2947
+ var WINDOW_LABELS = {
2948
+ "five-hour": "5 Hour",
2949
+ weekly: "Weekly",
2950
+ daily: "Daily"
2951
+ };
2952
+ function classifyWindowId(...sources) {
2953
+ for (const source of sources) {
2954
+ if (!source) continue;
2955
+ const text = source.toLowerCase();
2956
+ if (text.includes("week") || text.includes("7d") || /7[\s_-]*day/.test(text)) return "weekly";
2957
+ if (text.includes("5h") || text.includes("five hour") || /5[\s_-]*hour/.test(text)) return "five-hour";
2958
+ if (text.includes("day") || text.includes("daily") || text.includes("24h")) return "daily";
2959
+ }
2960
+ return void 0;
2961
+ }
2962
+ function inferWindowFromReset(resetsAt, now) {
2963
+ if (resetsAt !== void 0 && Date.parse(resetsAt) - now > 24 * 60 * 60 * 1e3) return "weekly";
2964
+ return "daily";
2965
+ }
2966
+ function clampFraction(value) {
2967
+ if (value === void 0 || !Number.isFinite(value)) return void 0;
2968
+ return Math.min(1, Math.max(0, value));
2969
+ }
2970
+ function usedPercentFromFraction(fraction) {
2971
+ const clamped = clampFraction(fraction);
2972
+ if (clamped === void 0) return null;
2973
+ return Math.round((1 - clamped) * 1e3) / 10;
2974
+ }
2975
+ function toResetsAt(resetTime) {
2976
+ if (!resetTime || !Number.isFinite(Date.parse(resetTime))) return void 0;
2977
+ return new Date(Date.parse(resetTime)).toISOString();
2978
+ }
2979
+ function parseAntigravityQuotaSummary(payload, now) {
2980
+ if (!isRecord5(payload)) return null;
2981
+ const groups = Array.isArray(payload["groups"]) ? payload["groups"] : [];
2982
+ const topBuckets = Array.isArray(payload["buckets"]) ? payload["buckets"] : [];
2983
+ const hasGrouped = groups.some((group) => Array.isArray(group.buckets) && group.buckets.length > 0);
2984
+ if (!hasGrouped && topBuckets.length === 0) return null;
2985
+ const windows = /* @__PURE__ */ new Map();
2986
+ const addBucket = (bucket, groupName) => {
2987
+ const families = (0, import_antigravityQuotaFamily.antigravityCounterFamiliesForBucketId)(bucket.bucketId, groupName);
2988
+ if (families.length === 0) return;
2989
+ const resetsAt = toResetsAt(bucket.resetTime);
2990
+ const windowId = classifyWindowId(bucket.window, bucket.displayName, bucket.bucketId) ?? (resetsAt !== void 0 ? inferWindowFromReset(resetsAt, now) : void 0);
2991
+ if (windowId === void 0) return;
2992
+ const usedPercent = usedPercentFromFraction(bucket.remainingFraction) ?? (bucket.disabled === true || bucket.resetTime ? bucket.disabled === true ? 100 : null : null);
2993
+ for (const family of families) {
2994
+ const id = `antigravity:${family}:${windowId}`;
2995
+ const candidate = {
2996
+ id,
2997
+ label: `${WINDOW_LABELS[windowId]} (${family})`,
2998
+ scope: "model-family",
2999
+ // The window carries the MODEL family (gemini/claude/gpt-oss) — the
3000
+ // scheduling gate compares it against the requested model's family.
3001
+ modelFamily: import_antigravityQuotaFamily.ANTIGRAVITY_COUNTER_TO_MODEL_FAMILY[family],
3002
+ usedPercent,
3003
+ ...resetsAt !== void 0 ? { resetsAt } : {},
3004
+ remainingSeconds: secondsUntil7(resetsAt, now),
3005
+ state: "fresh",
3006
+ ...bucket.disabled === true ? { disabled: true } : {}
3007
+ };
3008
+ const existing = windows.get(id);
3009
+ if (!existing || candidate.disabled === true || existing.disabled !== true && (candidate.usedPercent ?? -1) > (existing.usedPercent ?? -1)) {
3010
+ windows.set(id, candidate);
3011
+ }
3012
+ }
3013
+ };
3014
+ if (hasGrouped) {
3015
+ for (const group of groups) {
3016
+ for (const bucket of group.buckets ?? []) addBucket(bucket, group.displayName);
3017
+ }
3018
+ } else {
3019
+ for (const bucket of topBuckets) addBucket(bucket);
3020
+ }
3021
+ const result = [...windows.values()];
3022
+ return result.length > 0 ? result : null;
3023
+ }
3024
+ function legacyQuotaInfos(model) {
3025
+ const out = [];
3026
+ const source = {
3027
+ ...model.apiProvider ? { apiProvider: model.apiProvider } : {},
3028
+ ...model.modelProvider ? { modelProvider: model.modelProvider } : {}
3029
+ };
3030
+ const add = (value, windowDefault) => {
3031
+ if (!value) return;
3032
+ const list = Array.isArray(value) ? value : [value];
3033
+ for (const info of list) {
3034
+ out.push({ ...source, ...windowDefault ? { windowId: windowDefault } : {}, ...info });
3035
+ }
3036
+ };
3037
+ add(model.quotaInfo);
3038
+ add(model.quotaInfos);
3039
+ add(model.dailyQuotaInfo, "daily");
3040
+ add(model.dailyQuotaInfos, "daily");
3041
+ add(model.weeklyQuotaInfo, "weekly");
3042
+ add(model.weeklyQuotaInfos, "weekly");
3043
+ return out;
3044
+ }
3045
+ function legacyCounterFamily(info) {
3046
+ switch (info.modelProvider ?? info.apiProvider) {
3047
+ case "MODEL_PROVIDER_ANTHROPIC":
3048
+ case "API_PROVIDER_ANTHROPIC_VERTEX":
3049
+ return "anthropic";
3050
+ case "MODEL_PROVIDER_GOOGLE":
3051
+ case "API_PROVIDER_GOOGLE_GEMINI":
3052
+ return "google";
3053
+ case "MODEL_PROVIDER_OPENAI":
3054
+ case "API_PROVIDER_OPENAI_VERTEX":
3055
+ return "openai";
3056
+ default:
3057
+ return void 0;
3058
+ }
3059
+ }
3060
+ function parseAntigravityLegacyQuota(payload, now) {
3061
+ if (!isRecord5(payload)) return null;
3062
+ const models = payload["models"];
3063
+ if (!isRecord5(models)) return null;
3064
+ const windows = /* @__PURE__ */ new Map();
3065
+ for (const info of Object.values(models).flatMap(legacyQuotaInfos)) {
3066
+ const family = legacyCounterFamily(info);
3067
+ if (!family) continue;
3068
+ const resetsAt = toResetsAt(info.resetTime);
3069
+ const windowId = classifyWindowId(info.windowId, info.windowLabel) ?? (resetsAt !== void 0 ? inferWindowFromReset(resetsAt, now) : void 0);
3070
+ if (windowId === void 0) continue;
3071
+ const id = `antigravity:${family}:${windowId}`;
3072
+ const candidate = {
3073
+ id,
3074
+ label: `${WINDOW_LABELS[windowId]} (${family})`,
3075
+ scope: "model-family",
3076
+ modelFamily: import_antigravityQuotaFamily.ANTIGRAVITY_COUNTER_TO_MODEL_FAMILY[family],
3077
+ usedPercent: usedPercentFromFraction(info.remainingFraction),
3078
+ ...resetsAt !== void 0 ? { resetsAt } : {},
3079
+ remainingSeconds: secondsUntil7(resetsAt, now),
3080
+ state: "fresh"
3081
+ };
3082
+ const existing = windows.get(id);
3083
+ if (!existing || (candidate.usedPercent ?? -1) > (existing.usedPercent ?? -1)) {
3084
+ windows.set(id, candidate);
3085
+ }
3086
+ }
3087
+ const result = [...windows.values()];
3088
+ return result.length > 0 ? result : null;
3089
+ }
3090
+ var AntigravityAllowanceCollector = class {
3091
+ constructor(credentials, store = (0, import_AccountAllowanceStore7.getSharedAccountAllowanceStore)(), fetchImpl = (url, init, accountId) => (0, import_upstreamFetch7.fetchUpstream)(url, init, { providerId: "antigravity", accountId, redactBodies: true }), now = Date.now) {
3092
+ this.credentials = credentials;
3093
+ this.store = store;
3094
+ this.fetchImpl = fetchImpl;
3095
+ this.now = now;
3096
+ }
3097
+ credentials;
3098
+ store;
3099
+ fetchImpl;
3100
+ now;
3101
+ inFlight = /* @__PURE__ */ new Map();
3102
+ async collectMany(accounts, options = {}) {
3103
+ const settled = await Promise.allSettled(
3104
+ accounts.map((account) => this.collect(account, options))
3105
+ );
3106
+ return settled.flatMap((result) => result.status === "fulfilled" ? [result.value] : []);
3107
+ }
3108
+ collect(account, options = {}) {
3109
+ const now = this.now();
3110
+ if (account.tokens.authMethod !== "oauth") {
3111
+ const existing = this.store.get("antigravity", account.id, now);
3112
+ if (existing?.windows.every((window) => window.state === "unsupported")) {
3113
+ return Promise.resolve(existing);
3114
+ }
3115
+ const snapshot = this.unsupportedSnapshot(account.id, now);
3116
+ this.store.set(snapshot);
3117
+ return Promise.resolve(snapshot);
3118
+ }
3119
+ const cached = this.store.get("antigravity", account.id, now);
3120
+ if (!options.force && cached && this.isCacheValid(cached, now, options.refreshAheadMs)) {
3121
+ return Promise.resolve(cached);
3122
+ }
3123
+ const running = this.inFlight.get(account.id);
3124
+ if (running) return running;
3125
+ const promise = this.fetchAccount(account.id).catch(() => this.failureSnapshot(account.id, "antigravity_usage_request_failed", this.now())).finally(() => this.inFlight.delete(account.id));
3126
+ this.inFlight.set(account.id, promise);
3127
+ return promise;
3128
+ }
3129
+ isCacheValid(snapshot, now, refreshAheadMs) {
3130
+ if (snapshot.windows.every((window) => window.state === "unsupported")) return true;
3131
+ const expiresAt = snapshot.expiresAt ? Date.parse(snapshot.expiresAt) : 0;
3132
+ const ahead = typeof refreshAheadMs === "number" && Number.isFinite(refreshAheadMs) ? Math.max(0, refreshAheadMs) : 0;
3133
+ return Number.isFinite(expiresAt) && expiresAt > now + ahead;
3134
+ }
3135
+ async fetchAccount(accountId) {
3136
+ let accessToken = await this.credentials.getAccessTokenForAccount("antigravity", accountId);
3137
+ if (!accessToken) return this.failureSnapshot(accountId, "antigravity_usage_token_unavailable", this.now());
3138
+ let response = await this.request(accountId, accessToken, RETRIEVE_USER_QUOTA_SUMMARY_PATH, {
3139
+ project: void 0
3140
+ });
3141
+ if (response.status === 401 || response.status === 403) {
3142
+ const refreshed = await this.credentials.refreshAccountToken("antigravity", accountId);
3143
+ if (!refreshed) return this.failureSnapshot(accountId, "antigravity_usage_unauthorized", this.now());
3144
+ accessToken = await this.credentials.getAccessTokenForAccount("antigravity", accountId);
3145
+ if (!accessToken) return this.failureSnapshot(accountId, "antigravity_usage_token_unavailable", this.now());
3146
+ response = await this.request(accountId, accessToken, RETRIEVE_USER_QUOTA_SUMMARY_PATH, {
3147
+ project: void 0
3148
+ });
3149
+ if (response.status === 401 || response.status === 403) {
3150
+ return this.failureSnapshot(accountId, "antigravity_usage_unauthorized", this.now());
3151
+ }
3152
+ }
3153
+ if (response.ok) {
3154
+ const payload = await response.json().catch(() => null);
3155
+ const windows = parseAntigravityQuotaSummary(payload, this.now());
3156
+ if (windows) {
3157
+ const snapshot2 = this.snapshot(accountId, windows);
3158
+ this.store.set(snapshot2);
3159
+ return snapshot2;
3160
+ }
3161
+ }
3162
+ const legacy = await this.request(accountId, accessToken, FETCH_AVAILABLE_MODELS_PATH, {});
3163
+ if (!legacy.ok) {
3164
+ return this.failureSnapshot(accountId, "antigravity_usage_http_error", this.now());
3165
+ }
3166
+ const legacyPayload = await legacy.json().catch(() => null);
3167
+ const legacyWindows = parseAntigravityLegacyQuota(legacyPayload, this.now());
3168
+ if (!legacyWindows) {
3169
+ return this.failureSnapshot(accountId, "antigravity_usage_invalid_response", this.now());
3170
+ }
3171
+ const snapshot = this.snapshot(accountId, legacyWindows);
3172
+ this.store.set(snapshot);
3173
+ return snapshot;
3174
+ }
3175
+ /** One upstream round-trip with the antigravity/hub masquerade UA. */
3176
+ request(accountId, accessToken, path2, body) {
3177
+ return this.fetchImpl(`${import_GeminiCodeAssistProjectResolver2.ANTIGRAVITY_CODE_ASSIST_ENDPOINT}${path2}`, {
3178
+ method: "POST",
3179
+ headers: {
3180
+ Authorization: `Bearer ${accessToken}`,
3181
+ Accept: "application/json",
3182
+ "Content-Type": "application/json",
3183
+ "User-Agent": (0, import_antigravityIdentity.getAntigravityUserAgent)()
3184
+ },
3185
+ body: JSON.stringify(body),
3186
+ signal: AbortSignal.timeout(15e3)
3187
+ }, accountId);
3188
+ }
3189
+ snapshot(accountId, windows, now = this.now()) {
3190
+ return {
3191
+ providerId: "antigravity",
3192
+ accountId,
3193
+ source: "oauth-usage-api",
3194
+ observedAt: new Date(now).toISOString(),
3195
+ expiresAt: new Date(now + ANTIGRAVITY_ALLOWANCE_CACHE_MS).toISOString(),
3196
+ windows
3197
+ };
3198
+ }
3199
+ failureSnapshot(accountId, code, now) {
3200
+ const existing = this.store.get("antigravity", accountId, now);
3201
+ const snapshot = existing ? {
3202
+ ...existing,
3203
+ expiresAt: new Date(now + ANTIGRAVITY_ALLOWANCE_CACHE_MS).toISOString(),
3204
+ windows: existing.windows.map((window) => ({
3205
+ ...window,
3206
+ state: window.state === "unsupported" ? "unsupported" : window.usedPercent !== null || window.resetsAt || window.disabled ? "stale" : "unavailable"
3207
+ })),
3208
+ lastErrorCode: code
3209
+ } : {
3210
+ providerId: "antigravity",
3211
+ accountId,
3212
+ source: "oauth-usage-api",
3213
+ observedAt: new Date(now).toISOString(),
3214
+ expiresAt: new Date(now + ANTIGRAVITY_ALLOWANCE_CACHE_MS).toISOString(),
3215
+ windows: [
3216
+ { id: "antigravity-quota", label: "Antigravity quota", scope: "all", usedPercent: null, state: "unavailable" }
3217
+ ],
3218
+ lastErrorCode: code
3219
+ };
3220
+ this.store.set(snapshot);
3221
+ return snapshot;
3222
+ }
3223
+ unsupportedSnapshot(accountId, now) {
3224
+ return {
3225
+ providerId: "antigravity",
3226
+ accountId,
3227
+ source: "oauth-usage-api",
3228
+ observedAt: new Date(now).toISOString(),
3229
+ windows: [
3230
+ { id: "antigravity-quota", label: "Antigravity quota", scope: "all", usedPercent: null, state: "unsupported" }
3231
+ ],
3232
+ lastErrorCode: "antigravity_usage_unsupported_auth"
3233
+ };
3234
+ }
3235
+ };
3236
+
3237
+ // src/allowance/OpenCodeGoAllowanceCollector.ts
3238
+ var import_AccountAllowanceStore8 = require("@omnicross/core/pipeline/AccountAllowanceStore");
3239
+ var import_upstreamFetch8 = require("@omnicross/core/pipeline/upstreamFetch");
3240
+ var import_openCodeGoHeaders = require("@omnicross/core/provider-proxy/identity/openCodeGoHeaders");
2923
3241
  var import_subscriptions7 = require("@omnicross/subscriptions");
2924
3242
  var OPENCODEGO_ALLOWANCE_CACHE_MS = 5 * 6e4;
2925
3243
  var OPENCODEGO_DEFAULT_GO_BASE = "https://opencode.ai/zen/go";
@@ -2933,7 +3251,7 @@ function isoInstant2(value) {
2933
3251
  const time = Date.parse(value);
2934
3252
  return Number.isFinite(time) ? new Date(time).toISOString() : void 0;
2935
3253
  }
2936
- function secondsUntil7(instant, now) {
3254
+ function secondsUntil8(instant, now) {
2937
3255
  if (!instant) return void 0;
2938
3256
  return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
2939
3257
  }
@@ -2948,12 +3266,12 @@ function windowFromPayload3(id, label, minutes, payload, now) {
2948
3266
  usedPercent,
2949
3267
  windowMinutes: minutes,
2950
3268
  ...resetsAt !== void 0 ? { resetsAt } : {},
2951
- remainingSeconds: secondsUntil7(resetsAt, now),
3269
+ remainingSeconds: secondsUntil8(resetsAt, now),
2952
3270
  state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
2953
3271
  };
2954
3272
  }
2955
3273
  var OpenCodeGoAllowanceCollector = class {
2956
- constructor(credentials, store = (0, import_AccountAllowanceStore7.getSharedAccountAllowanceStore)(), fetchImpl = (url, init, accountId) => (0, import_upstreamFetch7.fetchUpstream)(url, init, { providerId: "opencodego", accountId, redactBodies: true }), now = Date.now) {
3274
+ constructor(credentials, store = (0, import_AccountAllowanceStore8.getSharedAccountAllowanceStore)(), fetchImpl = (url, init, accountId) => (0, import_upstreamFetch8.fetchUpstream)(url, init, { providerId: "opencodego", accountId, redactBodies: true }), now = Date.now) {
2957
3275
  this.credentials = credentials;
2958
3276
  this.store = store;
2959
3277
  this.fetchImpl = fetchImpl;
@@ -2986,7 +3304,14 @@ var OpenCodeGoAllowanceCollector = class {
2986
3304
  const base = account.tokens.baseUrl ? (0, import_subscriptions7.normalizeOpenCodeGoBaseUrl)(account.tokens.baseUrl) : OPENCODEGO_DEFAULT_GO_BASE;
2987
3305
  const response = await this.fetchImpl(`${base}/v1/usage`, {
2988
3306
  method: "GET",
2989
- headers: { Authorization: `Bearer ${apiKey}`, Accept: "application/json" },
3307
+ // opencodego-egress-identity: the background poll identifies itself with
3308
+ // the same configured/default UA the relay carries (no session header —
3309
+ // a poll has no conversation).
3310
+ headers: {
3311
+ Authorization: `Bearer ${apiKey}`,
3312
+ Accept: "application/json",
3313
+ "User-Agent": (0, import_openCodeGoHeaders.getOpenCodeGoUserAgent)()
3314
+ },
2990
3315
  signal: AbortSignal.timeout(15e3)
2991
3316
  }, account.id);
2992
3317
  if (response.status === 401 || response.status === 403) {
@@ -3058,7 +3383,7 @@ function codexUnavailable(accountId, now) {
3058
3383
  };
3059
3384
  }
3060
3385
  var AccountAllowanceService = class {
3061
- constructor(credentials, store = (0, import_AccountAllowanceStore8.getSharedAccountAllowanceStore)(), collector, codexCollector, kimiCollector, opencodegoCollector, grokCollector, copilotCollector, geminiCollector, now = Date.now) {
3386
+ constructor(credentials, store = (0, import_AccountAllowanceStore9.getSharedAccountAllowanceStore)(), collector, codexCollector, kimiCollector, opencodegoCollector, grokCollector, copilotCollector, geminiCollector, antigravityCollector, now = Date.now) {
3062
3387
  this.credentials = credentials;
3063
3388
  this.store = store;
3064
3389
  this.now = now;
@@ -3069,6 +3394,7 @@ var AccountAllowanceService = class {
3069
3394
  this.grokCollector = grokCollector ?? new GrokAllowanceCollector(credentials, store);
3070
3395
  this.copilotCollector = copilotCollector ?? new CopilotAllowanceCollector(credentials, store);
3071
3396
  this.geminiCollector = geminiCollector ?? new GeminiAllowanceCollector(credentials, store);
3397
+ this.antigravityCollector = antigravityCollector ?? new AntigravityAllowanceCollector(credentials, store);
3072
3398
  }
3073
3399
  credentials;
3074
3400
  store;
@@ -3080,6 +3406,7 @@ var AccountAllowanceService = class {
3080
3406
  copilotCollector;
3081
3407
  opencodegoCollector;
3082
3408
  geminiCollector;
3409
+ antigravityCollector;
3083
3410
  /**
3084
3411
  * Read all/filtered snapshots. Claude's and Codex's five-minute caches are
3085
3412
  * refreshed lazily on read (Codex polls `/backend-api/wham/usage`; the
@@ -3128,6 +3455,11 @@ var AccountAllowanceService = class {
3128
3455
  (account) => !filter.accountId || account.id === filter.accountId
3129
3456
  );
3130
3457
  if (wantsGemini) await this.geminiCollector.collectMany(geminiAccounts);
3458
+ const wantsAntigravity = !filter.providerId || filter.providerId === "antigravity";
3459
+ const antigravityAccounts = (config.antigravityAccounts ?? []).filter(
3460
+ (account) => !filter.accountId || account.id === filter.accountId
3461
+ );
3462
+ if (wantsAntigravity) await this.antigravityCollector.collectMany(antigravityAccounts);
3131
3463
  const known = /* @__PURE__ */ new Set();
3132
3464
  if (wantsClaude) for (const account of claudeAccounts) known.add(`claude\0${account.id}`);
3133
3465
  if (wantsCodex) for (const account of codexAccounts) known.add(`codex\0${account.id}`);
@@ -3136,6 +3468,7 @@ var AccountAllowanceService = class {
3136
3468
  if (wantsGrok) for (const account of grokAccounts) known.add(`grok\0${account.id}`);
3137
3469
  if (wantsCopilot) for (const account of copilotAccounts) known.add(`copilot\0${account.id}`);
3138
3470
  if (wantsGemini) for (const account of geminiAccounts) known.add(`gemini\0${account.id}`);
3471
+ if (wantsAntigravity) for (const account of antigravityAccounts) known.add(`antigravity\0${account.id}`);
3139
3472
  return this.store.list(filter).filter((snapshot) => known.has(`${snapshot.providerId}\0${snapshot.accountId}`));
3140
3473
  }
3141
3474
  knownAccounts(config) {
@@ -3146,7 +3479,8 @@ var AccountAllowanceService = class {
3146
3479
  ...(config.opencodegoAccounts ?? []).map((account) => ({ providerId: "opencodego", accountId: account.id })),
3147
3480
  ...(config.grokAccounts ?? []).map((account) => ({ providerId: "grok", accountId: account.id })),
3148
3481
  ...(config.copilotAccounts ?? []).map((account) => ({ providerId: "copilot", accountId: account.id })),
3149
- ...(config.geminiAccounts ?? []).map((account) => ({ providerId: "gemini", accountId: account.id }))
3482
+ ...(config.geminiAccounts ?? []).map((account) => ({ providerId: "gemini", accountId: account.id })),
3483
+ ...(config.antigravityAccounts ?? []).map((account) => ({ providerId: "antigravity", accountId: account.id }))
3150
3484
  ];
3151
3485
  }
3152
3486
  /** Force-refresh Claude usage for one account or every stored Claude account. */
@@ -3216,6 +3550,15 @@ var AccountAllowanceService = class {
3216
3550
  );
3217
3551
  return this.geminiCollector.collectMany(accounts, { force: true });
3218
3552
  }
3553
+ /** Force-refresh Antigravity usage (quotaSummary dual buckets) for one/all accounts. */
3554
+ async refreshAntigravity(accountId) {
3555
+ const config = await this.credentials.getFullConfig();
3556
+ this.store.pruneToKnownAccounts(this.knownAccounts(config));
3557
+ const accounts = (config.antigravityAccounts ?? []).filter(
3558
+ (account) => !accountId || account.id === accountId
3559
+ );
3560
+ return this.antigravityCollector.collectMany(accounts, { force: true });
3561
+ }
3219
3562
  /**
3220
3563
  * Keep Claude + Codex + Kimi snapshots warm for allowance-aware routing. All
3221
3564
  * collectors preserve their cache + per-account in-flight coalescing; a tick
@@ -3233,6 +3576,7 @@ var AccountAllowanceService = class {
3233
3576
  await this.grokCollector.collectMany(config.grokAccounts ?? [], { refreshAheadMs });
3234
3577
  await this.copilotCollector.collectMany(config.copilotAccounts ?? [], { refreshAheadMs });
3235
3578
  await this.geminiCollector.collectMany(config.geminiAccounts ?? [], { refreshAheadMs });
3579
+ await this.antigravityCollector.collectMany(config.antigravityAccounts ?? [], { refreshAheadMs });
3236
3580
  }
3237
3581
  /** Remove a cache row as soon as an account is deleted by the admin path. */
3238
3582
  removeAccountSnapshot(providerId, accountId) {
@@ -3327,7 +3671,7 @@ var ClaudeAllowanceRefreshScheduler = class {
3327
3671
  var import_node_crypto4 = require("crypto");
3328
3672
  var import_node_fs6 = require("fs");
3329
3673
  var import_node_path6 = require("path");
3330
- var import_AccountAllowanceStore9 = require("@omnicross/core/pipeline/AccountAllowanceStore");
3674
+ var import_AccountAllowanceStore10 = require("@omnicross/core/pipeline/AccountAllowanceStore");
3331
3675
  var ACCOUNT_ALLOWANCE_CACHE_VERSION = 1;
3332
3676
  var MAX_PERSISTED_ALLOWANCE_SNAPSHOTS = 256;
3333
3677
  var MAX_ALLOWANCE_CACHE_BYTES = 1e6;
@@ -3356,7 +3700,7 @@ var JsonAccountAllowancePersistence = class {
3356
3700
  save(snapshots) {
3357
3701
  const rows = [];
3358
3702
  for (const snapshot of snapshots) {
3359
- const normalized2 = (0, import_AccountAllowanceStore9.normalizeAccountAllowanceSnapshot)(snapshot);
3703
+ const normalized2 = (0, import_AccountAllowanceStore10.normalizeAccountAllowanceSnapshot)(snapshot);
3360
3704
  if (!normalized2) continue;
3361
3705
  rows.push(normalized2);
3362
3706
  if (rows.length >= MAX_PERSISTED_ALLOWANCE_SNAPSHOTS) break;
@@ -3632,7 +3976,7 @@ var import_outbound_api5 = require("@omnicross/core/outbound-api");
3632
3976
  var import_image_generation_types = require("@omnicross/contracts/image-generation-types");
3633
3977
  var import_AccountAllowanceScheduling2 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
3634
3978
  var import_SubscriptionAccountHealth = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
3635
- var import_upstreamFetch10 = require("@omnicross/core/pipeline/upstreamFetch");
3979
+ var import_upstreamFetch12 = require("@omnicross/core/pipeline/upstreamFetch");
3636
3980
  var import_core3 = require("@omnicross/core");
3637
3981
 
3638
3982
  // src/image-generation/imagesConfigValidation.ts
@@ -3949,6 +4293,19 @@ function resolveAdminConfig(admin) {
3949
4293
  token: typeof admin?.token === "string" && admin.token.length > 0 ? admin.token : void 0
3950
4294
  };
3951
4295
  }
4296
+ function validateAntigravity(raw) {
4297
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
4298
+ const a = raw;
4299
+ if (typeof a["sandboxFailover"] !== "boolean") return void 0;
4300
+ return { sandboxFailover: a["sandboxFailover"] };
4301
+ }
4302
+ function validateOpenCodeGo(raw) {
4303
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
4304
+ const o = raw;
4305
+ const ua = o["userAgent"];
4306
+ if (typeof ua !== "string" || ua.trim().length === 0) return void 0;
4307
+ return { userAgent: ua.trim() };
4308
+ }
3952
4309
  function validateUsage(raw) {
3953
4310
  if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
3954
4311
  const u = raw;
@@ -4242,7 +4599,9 @@ function validateConfig(raw) {
4242
4599
  const admin = validateAdmin(obj["admin"]);
4243
4600
  const logging = validateLogging(obj["logging"]);
4244
4601
  const usage = validateUsage(obj["usage"]);
4245
- return { providers, server, admin, logging };
4602
+ const antigravity = validateAntigravity(obj["antigravity"]);
4603
+ const opencodego = validateOpenCodeGo(obj["opencodego"]);
4604
+ return { providers, server, admin, logging, usage, antigravity, opencodego };
4246
4605
  }
4247
4606
  var secretBox = null;
4248
4607
  function setSecretBox(box) {
@@ -5286,11 +5645,11 @@ function preserveOutboundProxySecrets(incoming, current) {
5286
5645
  }
5287
5646
 
5288
5647
  // src/proxy/upstreamProxyResolver.ts
5289
- var import_upstreamFetch8 = require("@omnicross/core/pipeline/upstreamFetch");
5648
+ var import_upstreamFetch9 = require("@omnicross/core/pipeline/upstreamFetch");
5290
5649
  var serverProxy;
5291
5650
  function setServerProxyConfig(proxy) {
5292
5651
  serverProxy = proxy;
5293
- (0, import_upstreamFetch8.bumpUpstreamProxyGeneration)();
5652
+ (0, import_upstreamFetch9.bumpUpstreamProxyGeneration)();
5294
5653
  }
5295
5654
  function getServerProxyConfig() {
5296
5655
  return serverProxy;
@@ -5357,8 +5716,169 @@ function createUpstreamProxyResolver(src = {}) {
5357
5716
  };
5358
5717
  }
5359
5718
 
5360
- // src/admin/accountsOAuth.ts
5719
+ // src/admin/accountsAntigravityOAuth.ts
5720
+ var import_GeminiCodeAssistProjectResolver3 = require("@omnicross/core/auth/GeminiCodeAssistProjectResolver");
5361
5721
  var import_subscriptions8 = require("@omnicross/subscriptions");
5722
+ function err5(status, message) {
5723
+ return { status, body: { error: { type: "admin_api_error", message } } };
5724
+ }
5725
+ var DEFAULT_ANTIGRAVITY_OAUTH_TTL_MS = 10 * 6e4;
5726
+ function handleAntigravityOAuthStart(deps) {
5727
+ if (deps.antigravitySessions.isBusy()) {
5728
+ return err5(
5729
+ 409,
5730
+ "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"
5731
+ );
5732
+ }
5733
+ const { authUrl, state } = import_subscriptions8.antigravityOAuth.generateAuthParams();
5734
+ const { sessionId, signal } = deps.antigravitySessions.begin();
5735
+ void runAntigravityLoopback(sessionId, state, signal, deps);
5736
+ return { status: 200, body: { authUrl, sessionId } };
5737
+ }
5738
+ async function runAntigravityLoopback(sessionId, state, signal, deps) {
5739
+ const isPending = () => !signal.aborted && deps.antigravitySessions.get(sessionId)?.status === "pending";
5740
+ try {
5741
+ const code = await deps.antigravityAwaitLoopback(state, void 0, signal);
5742
+ if (!isPending()) return;
5743
+ const exchangeFetch = deps.oauthExchangeFetch("antigravity");
5744
+ const result = await import_subscriptions8.antigravityOAuth.exchangeCodeForTokens(code, exchangeFetch);
5745
+ if (!isPending()) return;
5746
+ const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
5747
+ const email = await import_subscriptions8.antigravityOAuth.fetchUserEmail(result.accessToken, exchangeFetch);
5748
+ if (!isPending()) return;
5749
+ const projectId = await (0, import_GeminiCodeAssistProjectResolver3.getAntigravityProjectResolver)().resolveProject(result.accessToken);
5750
+ if (!isPending()) return;
5751
+ const block = {
5752
+ authMethod: "oauth",
5753
+ status: "authorized",
5754
+ accessToken: result.accessToken,
5755
+ refreshToken: result.refreshToken,
5756
+ expiresAt,
5757
+ ...email ? { email } : {},
5758
+ ...projectId ? { projectId } : {},
5759
+ lastRefreshedAt: (/* @__PURE__ */ new Date()).toISOString()
5760
+ };
5761
+ await deps.subscriptionAccountAppender.appendProviderAccount("antigravity", block);
5762
+ if (isPending()) deps.antigravitySessions.settle(sessionId, "done");
5763
+ } catch (e) {
5764
+ if (!isPending()) return;
5765
+ const reason = e instanceof Error ? e.message : "antigravity sign-in failed";
5766
+ deps.antigravitySessions.settle(sessionId, "error", reason);
5767
+ }
5768
+ }
5769
+ function handleAntigravityOAuthCancel(sessionId, deps) {
5770
+ if (!deps.antigravitySessions.cancel(sessionId)) {
5771
+ return err5(404, "unknown or expired antigravity sign-in session");
5772
+ }
5773
+ return { status: 200, body: { ok: true } };
5774
+ }
5775
+ function handleAntigravityOAuthStatus(sessionId, deps) {
5776
+ const s = deps.antigravitySessions.get(sessionId);
5777
+ if (!s) return err5(404, "unknown or expired antigravity sign-in session");
5778
+ return { status: 200, body: { state: s.status, ...s.error ? { message: s.error } : {} } };
5779
+ }
5780
+
5781
+ // src/allowance/AntigravityModelDiscovery.ts
5782
+ var import_canonical_models = require("@omnicross/contracts/canonical-models");
5783
+ var import_subscription_model_catalog = require("@omnicross/contracts/subscription-model-catalog");
5784
+ var import_GeminiCodeAssistProjectResolver4 = require("@omnicross/core/auth/GeminiCodeAssistProjectResolver");
5785
+ var import_upstreamFetch10 = require("@omnicross/core/pipeline/upstreamFetch");
5786
+ var import_antigravityIdentity2 = require("@omnicross/core/transformer/transformers/antigravityIdentity");
5787
+ function isRecord6(value) {
5788
+ return !!value && typeof value === "object" && !Array.isArray(value);
5789
+ }
5790
+ function optionalString(value) {
5791
+ return typeof value === "string" && value.length > 0 ? value : void 0;
5792
+ }
5793
+ function optionalNumber(value) {
5794
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : void 0;
5795
+ }
5796
+ function optionalBoolean(value) {
5797
+ return typeof value === "boolean" ? value : void 0;
5798
+ }
5799
+ function parseAntigravityAvailableModels(payload) {
5800
+ if (!isRecord6(payload)) return [];
5801
+ const models = payload["models"];
5802
+ if (!isRecord6(models)) return [];
5803
+ const out = [];
5804
+ for (const [id, raw] of Object.entries(models)) {
5805
+ if (ANTIGRAVITY_DISCOVERY_DENYLIST.has(id)) continue;
5806
+ if (!isRecord6(raw)) continue;
5807
+ if (raw["isInternal"] === true) continue;
5808
+ out.push({
5809
+ id,
5810
+ ...optionalString(raw["displayName"]) ? { displayName: optionalString(raw["displayName"]) } : {},
5811
+ ...optionalBoolean(raw["supportsImages"]) !== void 0 ? { supportsImages: optionalBoolean(raw["supportsImages"]) } : {},
5812
+ ...optionalBoolean(raw["supportsThinking"]) !== void 0 ? { supportsThinking: optionalBoolean(raw["supportsThinking"]) } : {},
5813
+ ...optionalNumber(raw["thinkingBudget"]) !== void 0 ? { thinkingBudget: optionalNumber(raw["thinkingBudget"]) } : {},
5814
+ ...optionalNumber(raw["maxTokens"]) !== void 0 ? { maxTokens: optionalNumber(raw["maxTokens"]) } : {},
5815
+ ...optionalNumber(raw["maxOutputTokens"]) !== void 0 ? { maxOutputTokens: optionalNumber(raw["maxOutputTokens"]) } : {}
5816
+ });
5817
+ }
5818
+ out.sort((a, b) => a.id.localeCompare(b.id));
5819
+ return out;
5820
+ }
5821
+ function mergeAntigravityCatalog(discovered, log = (line) => console.warn(line), staticIds = import_subscription_model_catalog.SUBSCRIPTION_MODEL_CATALOG.antigravity) {
5822
+ const entries = staticIds.map((id) => {
5823
+ const capabilities = (0, import_canonical_models.lookupCanonicalCapabilities)(id);
5824
+ return {
5825
+ id,
5826
+ origin: "static",
5827
+ displayName: id,
5828
+ ...capabilities?.vision !== void 0 ? { supportsImages: capabilities.vision } : {},
5829
+ ...capabilities?.reasoning !== void 0 ? { supportsThinking: capabilities.reasoning } : {},
5830
+ ...capabilities?.thinkingTokenLimit ? { thinkingBudget: capabilities.thinkingTokenLimit.max } : {},
5831
+ // Discovery calls the context window maxTokens, not the output ceiling.
5832
+ ...capabilities?.contextLength !== void 0 ? { maxTokens: capabilities.contextLength } : {},
5833
+ ...capabilities?.maxTokens !== void 0 ? { maxOutputTokens: capabilities.maxTokens } : {}
5834
+ };
5835
+ });
5836
+ const staticSet = new Set(staticIds);
5837
+ for (const model of discovered) {
5838
+ if (staticSet.has(model.id)) {
5839
+ log(
5840
+ `[AntigravityModelDiscovery] dynamic model '${model.id}' conflicts with the static catalog \u2014 static entry kept`
5841
+ );
5842
+ continue;
5843
+ }
5844
+ entries.push({ ...model, origin: "discovered" });
5845
+ }
5846
+ return entries;
5847
+ }
5848
+ async function fetchAntigravityAvailableModels(accessToken, fetchImpl = (url, init) => (0, import_upstreamFetch10.fetchUpstream)(url, init, { providerId: "antigravity", redactBodies: true })) {
5849
+ let response;
5850
+ try {
5851
+ response = await fetchImpl(`${import_GeminiCodeAssistProjectResolver4.ANTIGRAVITY_CODE_ASSIST_ENDPOINT}/v1internal:fetchAvailableModels`, {
5852
+ method: "POST",
5853
+ headers: {
5854
+ Authorization: `Bearer ${accessToken}`,
5855
+ Accept: "application/json",
5856
+ "Content-Type": "application/json",
5857
+ "User-Agent": (0, import_antigravityIdentity2.getAntigravityUserAgent)()
5858
+ },
5859
+ body: JSON.stringify({}),
5860
+ signal: AbortSignal.timeout(15e3)
5861
+ });
5862
+ } catch {
5863
+ return null;
5864
+ }
5865
+ if (!response.ok) return null;
5866
+ const payload = await response.json().catch(() => null);
5867
+ if (!isRecord6(payload) || !isRecord6(payload["models"])) return null;
5868
+ return parseAntigravityAvailableModels(payload);
5869
+ }
5870
+ async function handleAntigravityModelsRoute(deps) {
5871
+ const accessToken = await deps.resolveAntigravityAccessToken().catch(() => null);
5872
+ const discovered = accessToken ? await fetchAntigravityAvailableModels(accessToken, deps.fetchImpl) : null;
5873
+ const models = mergeAntigravityCatalog(discovered ?? []);
5874
+ return {
5875
+ status: 200,
5876
+ body: { models, discovered: discovered !== null }
5877
+ };
5878
+ }
5879
+
5880
+ // src/admin/accountsOAuth.ts
5881
+ var import_subscriptions9 = require("@omnicross/subscriptions");
5362
5882
 
5363
5883
  // src/admin/accountsWrite.ts
5364
5884
  var VALID_PROVIDER_IDS = [
@@ -5368,7 +5888,8 @@ var VALID_PROVIDER_IDS = [
5368
5888
  "opencodego",
5369
5889
  "kimi",
5370
5890
  "grok",
5371
- "copilot"
5891
+ "copilot",
5892
+ "antigravity"
5372
5893
  ];
5373
5894
  function asSubscriptionProviderId(id) {
5374
5895
  return VALID_PROVIDER_IDS.includes(id) ? id : null;
@@ -5550,7 +6071,7 @@ function validateCopilot(body) {
5550
6071
  ]);
5551
6072
  return out;
5552
6073
  }
5553
- function validateOpenCodeGo(body) {
6074
+ function validateOpenCodeGo2(body) {
5554
6075
  const authMethod = str(body["authMethod"]);
5555
6076
  const status = str(body["status"]);
5556
6077
  if (authMethod !== "manual") return null;
@@ -5584,7 +6105,7 @@ function validateTokenBody(providerId, body) {
5584
6105
  case "gemini":
5585
6106
  return validateGemini(body);
5586
6107
  case "opencodego":
5587
- return validateOpenCodeGo(body);
6108
+ return validateOpenCodeGo2(body);
5588
6109
  case "kimi":
5589
6110
  return validateKimi(body);
5590
6111
  case "grok":
@@ -5620,37 +6141,37 @@ async function statusEntryFor(reader, providerId) {
5620
6141
 
5621
6142
  // src/admin/accountsOAuth.ts
5622
6143
  var OAUTH_HTTP_PROVIDERS = /* @__PURE__ */ new Set(["claude", "gemini"]);
5623
- function err5(status, message) {
6144
+ function err6(status, message) {
5624
6145
  return { status, body: { error: { type: "admin_api_error", message } } };
5625
6146
  }
5626
6147
  function handleOAuthStart(providerId, deps) {
5627
6148
  if (!OAUTH_HTTP_PROVIDERS.has(providerId)) {
5628
- return err5(400, `oauth not available for provider '${providerId}'`);
6149
+ return err6(400, `oauth not available for provider '${providerId}'`);
5629
6150
  }
5630
- const flow = providerId === "claude" ? import_subscriptions8.claudeOAuth : import_subscriptions8.geminiOAuth;
6151
+ const flow = providerId === "claude" ? import_subscriptions9.claudeOAuth : import_subscriptions9.geminiOAuth;
5631
6152
  const { authUrl, codeVerifier, state } = flow.generateAuthParams();
5632
6153
  const sessionId = deps.oauthSessions.put({ providerId, codeVerifier, state });
5633
6154
  return { status: 200, body: { authUrl, sessionId } };
5634
6155
  }
5635
6156
  async function handleOAuthComplete(providerId, body, deps) {
5636
6157
  if (!OAUTH_HTTP_PROVIDERS.has(providerId)) {
5637
- return err5(400, `oauth not available for provider '${providerId}'`);
6158
+ return err6(400, `oauth not available for provider '${providerId}'`);
5638
6159
  }
5639
6160
  const sessionId = typeof body["sessionId"] === "string" ? body["sessionId"] : "";
5640
6161
  const rawCode = typeof body["code"] === "string" ? body["code"] : "";
5641
- if (!sessionId) return err5(400, "oauth complete requires { sessionId }");
5642
- if (!rawCode) return err5(400, "oauth complete requires { code }");
6162
+ if (!sessionId) return err6(400, "oauth complete requires { sessionId }");
6163
+ if (!rawCode) return err6(400, "oauth complete requires { code }");
5643
6164
  const session = deps.oauthSessions.peek(sessionId);
5644
- if (!session) return err5(410, "oauth session is unknown, expired, or already used");
6165
+ if (!session) return err6(410, "oauth session is unknown, expired, or already used");
5645
6166
  if (session.providerId !== providerId) {
5646
- return err5(400, `oauth session does not match provider '${providerId}'`);
6167
+ return err6(400, `oauth session does not match provider '${providerId}'`);
5647
6168
  }
5648
6169
  let code = rawCode.trim();
5649
6170
  if (providerId === "claude") {
5650
6171
  const [splitCode, pastedState] = code.split("#");
5651
- if (!splitCode) return err5(400, "no authorization code was provided");
6172
+ if (!splitCode) return err6(400, "no authorization code was provided");
5652
6173
  if (pastedState && pastedState !== session.state) {
5653
- return err5(400, "oauth state did not match (possible CSRF) \u2014 aborting");
6174
+ return err6(400, "oauth state did not match (possible CSRF) \u2014 aborting");
5654
6175
  }
5655
6176
  code = splitCode;
5656
6177
  }
@@ -5660,7 +6181,7 @@ async function handleOAuthComplete(providerId, body, deps) {
5660
6181
  block = providerId === "claude" ? await exchangeClaude(code, session.codeVerifier, session.state, exchangeFetch) : await exchangeGemini(code, session.codeVerifier, exchangeFetch);
5661
6182
  } catch (exchangeError) {
5662
6183
  const reason = exchangeError instanceof Error ? exchangeError.message : "token exchange failed";
5663
- return err5(502, `oauth token exchange failed for '${providerId}': ${reason}`);
6184
+ return err6(502, `oauth token exchange failed for '${providerId}': ${reason}`);
5664
6185
  }
5665
6186
  deps.oauthSessions.consume(sessionId);
5666
6187
  const label = typeof body["label"] === "string" && body["label"].trim() ? body["label"].trim() : void 0;
@@ -5669,7 +6190,7 @@ async function handleOAuthComplete(providerId, body, deps) {
5669
6190
  return { status: 200, body: status ? { account: status } : { ok: true } };
5670
6191
  }
5671
6192
  async function exchangeClaude(code, codeVerifier, state, exchangeFetch) {
5672
- const result = await import_subscriptions8.claudeOAuth.exchangeCodeForTokens(
6193
+ const result = await import_subscriptions9.claudeOAuth.exchangeCodeForTokens(
5673
6194
  { authorizationCode: code, codeVerifier, state },
5674
6195
  exchangeFetch
5675
6196
  );
@@ -5685,7 +6206,7 @@ async function exchangeClaude(code, codeVerifier, state, exchangeFetch) {
5685
6206
  };
5686
6207
  }
5687
6208
  async function exchangeGemini(code, codeVerifier, exchangeFetch) {
5688
- const result = await import_subscriptions8.geminiOAuth.exchangeCodeForTokens(code, codeVerifier, exchangeFetch);
6209
+ const result = await import_subscriptions9.geminiOAuth.exchangeCodeForTokens(code, codeVerifier, exchangeFetch);
5689
6210
  const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
5690
6211
  return {
5691
6212
  authMethod: "oauth",
@@ -5990,8 +6511,8 @@ function errBody(message) {
5990
6511
  return { error: { type: "admin_api_error", message } };
5991
6512
  }
5992
6513
  var defaultCommandRunner = (command) => new Promise((resolve11) => {
5993
- (0, import_node_child_process.exec)(command, { timeout: 18e4 }, (err8, _stdout, stderr) => {
5994
- if (err8) resolve11({ ok: false, error: stderr.trim() || err8.message });
6514
+ (0, import_node_child_process.exec)(command, { timeout: 18e4 }, (err9, _stdout, stderr) => {
6515
+ if (err9) resolve11({ ok: false, error: stderr.trim() || err9.message });
5995
6516
  else resolve11({ ok: true });
5996
6517
  });
5997
6518
  });
@@ -6037,8 +6558,8 @@ async function handleCliLaunch(cli, body, ctx) {
6037
6558
  providerId: typeof body["providerId"] === "string" ? body["providerId"] : void 0,
6038
6559
  model: typeof body["model"] === "string" ? body["model"] : void 0
6039
6560
  });
6040
- } catch (err8) {
6041
- return { status: 400, body: errBody(err8 instanceof Error ? err8.message : "no launch target") };
6561
+ } catch (err9) {
6562
+ return { status: 400, body: errBody(err9 instanceof Error ? err9.message : "no launch target") };
6042
6563
  }
6043
6564
  const id = (0, import_node_crypto7.randomUUID)();
6044
6565
  let leaseId2;
@@ -6066,9 +6587,9 @@ async function handleCliLaunch(cli, body, ctx) {
6066
6587
  } else {
6067
6588
  launch = await buildLaunchEnv(cli, ctx.llmConfig, target);
6068
6589
  }
6069
- } catch (err8) {
6070
- const status = err8 instanceof import_provider_proxy2.RouteLeaseError ? err8.status : 400;
6071
- return { status, body: errBody(err8 instanceof Error ? err8.message : "failed to build launch env") };
6590
+ } catch (err9) {
6591
+ const status = err9 instanceof import_provider_proxy2.RouteLeaseError ? err9.status : 400;
6592
+ return { status, body: errBody(err9 instanceof Error ? err9.message : "failed to build launch env") };
6072
6593
  }
6073
6594
  const cwd = typeof body["cwd"] === "string" && body["cwd"].trim() ? body["cwd"].trim() : void 0;
6074
6595
  const opener = ctx.opener ?? defaultTerminalOpener;
@@ -6096,9 +6617,9 @@ async function handleCliLaunch(cli, body, ctx) {
6096
6617
  onFailure: onSessionEnd
6097
6618
  });
6098
6619
  if (cleanup) openerCleanup = cleanup;
6099
- } catch (err8) {
6620
+ } catch (err9) {
6100
6621
  onSessionEnd();
6101
- return { status: 500, body: errBody(err8 instanceof Error ? err8.message : "failed to open terminal") };
6622
+ return { status: 500, body: errBody(err9 instanceof Error ? err9.message : "failed to open terminal") };
6102
6623
  }
6103
6624
  if (ended) {
6104
6625
  openerCleanup?.();
@@ -6353,7 +6874,7 @@ async function runSearchLiveChecks(contributions, now = () => (/* @__PURE__ */ n
6353
6874
  }
6354
6875
 
6355
6876
  // src/search/SearchAssembly.ts
6356
- var import_upstreamFetch9 = require("@omnicross/core/pipeline/upstreamFetch");
6877
+ var import_upstreamFetch11 = require("@omnicross/core/pipeline/upstreamFetch");
6357
6878
  var import_search = require("@omnicross/core/search");
6358
6879
  var import_api2 = require("@omnicross/core/search/api");
6359
6880
  var import_http2 = require("@omnicross/core/search/http");
@@ -6371,7 +6892,7 @@ function searchPolicyFrom(config) {
6371
6892
  };
6372
6893
  }
6373
6894
  function resolveSearchUpstreamDispatcher(url) {
6374
- return (0, import_upstreamFetch9.resolveUpstreamDispatcher)({ url });
6895
+ return (0, import_upstreamFetch11.resolveUpstreamDispatcher)({ url });
6375
6896
  }
6376
6897
  var searchUpstreamProxyConfig = createUpstreamProxyResolver();
6377
6898
  function resolveSearchUpstreamProxyConfig(url) {
@@ -6653,7 +7174,7 @@ async function handleSearchQuery(req, res, deps) {
6653
7174
  // src/admin/searchAdminView.ts
6654
7175
  var API_KEY_PROVIDERS = /* @__PURE__ */ new Set(["tavily", "jina", "zhipu", "z.ai"]);
6655
7176
  var BASIC_AUTH_PROVIDERS = /* @__PURE__ */ new Set(["searxng"]);
6656
- function isRecord5(value) {
7177
+ function isRecord7(value) {
6657
7178
  return value !== null && typeof value === "object" && !Array.isArray(value);
6658
7179
  }
6659
7180
  function redactSearchServerConfig(search) {
@@ -6703,13 +7224,13 @@ function resolveSecretField(entry, field, stored) {
6703
7224
  else delete entry[field];
6704
7225
  }
6705
7226
  function preserveSearchSecrets(incoming, current) {
6706
- if (!isRecord5(incoming)) return incoming;
7227
+ if (!isRecord7(incoming)) return incoming;
6707
7228
  const section = { ...incoming };
6708
7229
  const providersValue = section["providers"];
6709
- if (!isRecord5(providersValue)) return section;
7230
+ if (!isRecord7(providersValue)) return section;
6710
7231
  const providers = {};
6711
7232
  for (const [id, entryValue] of Object.entries(providersValue)) {
6712
- if (!isRecord5(entryValue)) {
7233
+ if (!isRecord7(entryValue)) {
6713
7234
  providers[id] = entryValue;
6714
7235
  continue;
6715
7236
  }
@@ -6787,7 +7308,7 @@ function parseKeyPolicyBody(body) {
6787
7308
  var ENDPOINTS = /* @__PURE__ */ new Set(["chat", "responses", "messages", "gemini"]);
6788
7309
  var TARGET_KINDS = /* @__PURE__ */ new Set(["account", "account-group", "account-pool", "provider"]);
6789
7310
  var FALLBACKS = /* @__PURE__ */ new Set(["next", "fail", "global"]);
6790
- function isRecord6(value) {
7311
+ function isRecord8(value) {
6791
7312
  return !!value && typeof value === "object" && !Array.isArray(value);
6792
7313
  }
6793
7314
  function nonBlank(value) {
@@ -6807,7 +7328,7 @@ function validateGatewayBindingsSegment(patch) {
6807
7328
  const ids = /* @__PURE__ */ new Set();
6808
7329
  raw.forEach((entry, index) => {
6809
7330
  const path2 = `bindings[${index}]`;
6810
- if (!isRecord6(entry)) {
7331
+ if (!isRecord8(entry)) {
6811
7332
  errors.push(`${path2} must be an object`);
6812
7333
  return;
6813
7334
  }
@@ -6836,12 +7357,12 @@ function validateGatewayBindingsSegment(patch) {
6836
7357
  } else if (entry.modelMappings.length > 100) {
6837
7358
  errors.push(`${path2}.modelMappings cannot contain more than 100 entries`);
6838
7359
  } else if (entry.modelMappings.some(
6839
- (mapping) => !isRecord6(mapping) || !nonBlank(mapping.source) || !nonBlank(mapping.target)
7360
+ (mapping) => !isRecord8(mapping) || !nonBlank(mapping.source) || !nonBlank(mapping.target)
6840
7361
  )) {
6841
7362
  errors.push(`${path2}.modelMappings must contain non-empty source and target strings`);
6842
7363
  }
6843
7364
  }
6844
- if (!isRecord6(entry.target) || !TARGET_KINDS.has(String(entry.target.kind))) {
7365
+ if (!isRecord8(entry.target) || !TARGET_KINDS.has(String(entry.target.kind))) {
6845
7366
  errors.push(`${path2}.target is invalid`);
6846
7367
  } else {
6847
7368
  if (!nonBlank(entry.target.providerId)) errors.push(`${path2}.target.providerId is required`);
@@ -6856,7 +7377,7 @@ function validateGatewayBindingsSegment(patch) {
6856
7377
  }
6857
7378
  }
6858
7379
  if (entry.modelMap !== void 0) {
6859
- if (!isRecord6(entry.modelMap) || Object.values(entry.modelMap).some((value) => typeof value !== "string")) {
7380
+ if (!isRecord8(entry.modelMap) || Object.values(entry.modelMap).some((value) => typeof value !== "string")) {
6860
7381
  errors.push(`${path2}.modelMap must contain string values`);
6861
7382
  }
6862
7383
  }
@@ -7141,7 +7662,12 @@ var PROVIDER_KEYS = {
7141
7662
  },
7142
7663
  kimi: { block: "kimi", accounts: "kimiAccounts", active: "activeKimiAccountId" },
7143
7664
  grok: { block: "grok", accounts: "grokAccounts", active: "activeGrokAccountId" },
7144
- copilot: { block: "copilot", accounts: "copilotAccounts", active: "activeCopilotAccountId" }
7665
+ copilot: { block: "copilot", accounts: "copilotAccounts", active: "activeCopilotAccountId" },
7666
+ antigravity: {
7667
+ block: "antigravity",
7668
+ accounts: "antigravityAccounts",
7669
+ active: "activeAntigravityAccountId"
7670
+ }
7145
7671
  };
7146
7672
  function clone(value) {
7147
7673
  return JSON.parse(JSON.stringify(value));
@@ -7663,7 +8189,7 @@ async function applyImport(packString, passphrase, mode, deps, parseProviderInpu
7663
8189
  }
7664
8190
 
7665
8191
  // src/admin/adminMigration.ts
7666
- function err6(status, message) {
8192
+ function err7(status, message) {
7667
8193
  return { status, body: { error: { type: "admin_api_error", message } } };
7668
8194
  }
7669
8195
  async function handleExport(body, deps) {
@@ -7673,30 +8199,30 @@ async function handleExport(body, deps) {
7673
8199
  return { status: 200, body: { pack, version: BUNDLE_VERSION } };
7674
8200
  } catch (error) {
7675
8201
  if (error instanceof WeakPassphraseError) {
7676
- return err6(400, error.message);
8202
+ return err7(400, error.message);
7677
8203
  }
7678
- return err6(500, "failed to build the migration pack");
8204
+ return err7(500, "failed to build the migration pack");
7679
8205
  }
7680
8206
  }
7681
8207
  async function handleImport(body, deps) {
7682
8208
  const blob = typeof body["blob"] === "string" ? body["blob"] : "";
7683
8209
  const passphrase = typeof body["passphrase"] === "string" ? body["passphrase"] : "";
7684
8210
  const mode = body["mode"] === "overwrite" ? "overwrite" : "merge";
7685
- if (!blob) return err6(400, "import requires { blob }");
8211
+ if (!blob) return err7(400, "import requires { blob }");
7686
8212
  try {
7687
8213
  const counts = await applyImport(blob, passphrase, mode, deps, deps.parseProviderInput);
7688
8214
  return { status: 200, body: counts };
7689
8215
  } catch (error) {
7690
8216
  if (error instanceof WeakPassphraseError) {
7691
- return err6(400, error.message);
8217
+ return err7(400, error.message);
7692
8218
  }
7693
- return err6(400, error instanceof Error ? error.message : "import failed");
8219
+ return err7(400, error instanceof Error ? error.message : "import failed");
7694
8220
  }
7695
8221
  }
7696
8222
 
7697
8223
  // src/admin/usagePricing.ts
7698
8224
  var import_usage = require("@omnicross/core/usage");
7699
- var err7 = (status, message) => ({
8225
+ var err8 = (status, message) => ({
7700
8226
  status,
7701
8227
  body: { error: { type: "admin_api_error", message } }
7702
8228
  });
@@ -7709,7 +8235,7 @@ function parseRange(query2) {
7709
8235
  const startTs = parseFiniteInt(query2.get("startTs"));
7710
8236
  const endTs = parseFiniteInt(query2.get("endTs"));
7711
8237
  if (startTs === null || endTs === null) {
7712
- return err7(400, "startTs and endTs are required finite-integer unix-millis query params");
8238
+ return err8(400, "startTs and endTs are required finite-integer unix-millis query params");
7713
8239
  }
7714
8240
  return { startTs, endTs };
7715
8241
  }
@@ -7734,14 +8260,14 @@ async function handleUsageGet(view, query2, deps) {
7734
8260
  case "timeseries": {
7735
8261
  const bucket = query2.get("bucket");
7736
8262
  if (bucket !== "hour" && bucket !== "day" && bucket !== "month") {
7737
- return err7(400, "bucket must be one of 'hour', 'day', 'month'");
8263
+ return err8(400, "bucket must be one of 'hour', 'day', 'month'");
7738
8264
  }
7739
8265
  const now = Date.now();
7740
8266
  const clamped = { startTs: range.startTs, endTs: Math.min(range.endTs, now) };
7741
8267
  if (clamped.startTs < clamped.endTs) {
7742
8268
  const projected = Math.ceil((clamped.endTs - clamped.startTs) / BUCKET_SPAN_MS[bucket]) + 1;
7743
8269
  if (projected > MAX_TIMESERIES_BUCKETS) {
7744
- return err7(
8270
+ return err8(
7745
8271
  400,
7746
8272
  `requested range projects ~${projected} '${bucket}' buckets (max ${MAX_TIMESERIES_BUCKETS}); narrow the range or use a coarser bucket`
7747
8273
  );
@@ -7764,7 +8290,7 @@ async function handleUsageGet(view, query2, deps) {
7764
8290
  };
7765
8291
  }
7766
8292
  default:
7767
- return err7(404, `unknown usage view '${view ?? ""}'`);
8293
+ return err8(404, `unknown usage view '${view ?? ""}'`);
7768
8294
  }
7769
8295
  }
7770
8296
  function poolKeyLabels(cfg) {
@@ -7813,7 +8339,7 @@ async function handlePricingList(deps) {
7813
8339
  async function handlePricingUpsert(body, deps) {
7814
8340
  const input = parsePricingEntryInput(body);
7815
8341
  if (!input) {
7816
- return err7(400, "invalid pricing entry (providerId, modelId, finite numeric inputPricePer1m/outputPricePer1m required)");
8342
+ return err8(400, "invalid pricing entry (providerId, modelId, finite numeric inputPricePer1m/outputPricePer1m required)");
7817
8343
  }
7818
8344
  const entry = await deps.pricingEngine.upsertManual(input);
7819
8345
  return { status: 200, body: { entry } };
@@ -7822,7 +8348,7 @@ async function handlePricingDelete(query2, deps) {
7822
8348
  const providerId = query2.get("providerId")?.trim() ?? "";
7823
8349
  const modelId = query2.get("modelId")?.trim() ?? "";
7824
8350
  if (!providerId || !modelId) {
7825
- return err7(400, "delete requires providerId and modelId query params");
8351
+ return err8(400, "delete requires providerId and modelId query params");
7826
8352
  }
7827
8353
  const deleted = await deps.pricingStore.delete(providerId, modelId);
7828
8354
  if (deleted) await deps.pricingEngine.invalidateCache();
@@ -7842,13 +8368,13 @@ async function handlePricingFetchLatest(deps) {
7842
8368
  }
7843
8369
  };
7844
8370
  } catch (e) {
7845
- return err7(502, `pricing-source fetch failed: ${e instanceof Error ? e.message : String(e)}`);
8371
+ return err8(502, `pricing-source fetch failed: ${e instanceof Error ? e.message : String(e)}`);
7846
8372
  }
7847
8373
  }
7848
8374
  async function handlePricingResolveConflicts(body, deps) {
7849
8375
  const raw = body["resolutions"];
7850
8376
  if (!Array.isArray(raw)) {
7851
- return err7(400, "resolve-conflicts requires { resolutions: [...] }");
8377
+ return err8(400, "resolve-conflicts requires { resolutions: [...] }");
7852
8378
  }
7853
8379
  const currentRows = await deps.pricingStore.getAll();
7854
8380
  const userEditedKeys = new Set(
@@ -7858,21 +8384,21 @@ async function handlePricingResolveConflicts(body, deps) {
7858
8384
  const pendingIncoming = /* @__PURE__ */ new Map();
7859
8385
  let staleCount = 0;
7860
8386
  for (const item of raw) {
7861
- if (!item || typeof item !== "object") return err7(400, "invalid resolution entry");
8387
+ if (!item || typeof item !== "object") return err8(400, "invalid resolution entry");
7862
8388
  const r = item;
7863
8389
  const action = r["action"];
7864
8390
  if (action !== "overwrite" && action !== "skip") {
7865
- return err7(400, "resolution action must be 'overwrite' or 'skip'");
8391
+ return err8(400, "resolution action must be 'overwrite' or 'skip'");
7866
8392
  }
7867
8393
  const providerId = typeof r["providerId"] === "string" && r["providerId"].trim() ? r["providerId"].trim() : "";
7868
8394
  const modelId = typeof r["modelId"] === "string" && r["modelId"].trim() ? r["modelId"].trim() : "";
7869
8395
  if (!providerId || !modelId) {
7870
- return err7(400, "each resolution requires top-level providerId and modelId");
8396
+ return err8(400, "each resolution requires top-level providerId and modelId");
7871
8397
  }
7872
8398
  const incoming = parsePricingEntryInput(r["incoming"]);
7873
- if (!incoming) return err7(400, "each resolution must echo a valid incoming pricing entry");
8399
+ if (!incoming) return err8(400, "each resolution must echo a valid incoming pricing entry");
7874
8400
  if (incoming.providerId !== providerId || incoming.modelId !== modelId) {
7875
- return err7(400, "resolution providerId/modelId must match the echoed incoming entry");
8401
+ return err8(400, "resolution providerId/modelId must match the echoed incoming entry");
7876
8402
  }
7877
8403
  const key = `${providerId}::${modelId}`;
7878
8404
  if (action === "overwrite" && !userEditedKeys.has(key)) {
@@ -7917,7 +8443,7 @@ function query(req) {
7917
8443
  }
7918
8444
  function allowanceProvider(value) {
7919
8445
  if (!value) return void 0;
7920
- return value === "claude" || value === "codex" || value === "kimi" || value === "opencodego" || value === "grok" || value === "copilot" || value === "gemini" ? value : null;
8446
+ return value === "claude" || value === "codex" || value === "kimi" || value === "opencodego" || value === "grok" || value === "copilot" || value === "gemini" || value === "antigravity" ? value : null;
7921
8447
  }
7922
8448
  async function handleAccountAllowanceApi(req, res, method, rest, service) {
7923
8449
  if (!service) return writeError2(res, 501, "account allowance service is not available");
@@ -7994,6 +8520,16 @@ async function handleAccountAllowanceApi(req, res, method, rest, service) {
7994
8520
  }
7995
8521
  return writeJson3(res, 200, { allowances: allowances2 });
7996
8522
  }
8523
+ if (requestedProvider === "antigravity") {
8524
+ if (!service.refreshAntigravity) {
8525
+ return writeError2(res, 501, "antigravity allowance refresh is not available");
8526
+ }
8527
+ const allowances2 = await service.refreshAntigravity(accountId);
8528
+ if (accountId && allowances2.length === 0) {
8529
+ return writeError2(res, 404, `Antigravity account '${accountId}' not found`);
8530
+ }
8531
+ return writeJson3(res, 200, { allowances: allowances2 });
8532
+ }
7997
8533
  if (requestedProvider === "gemini") {
7998
8534
  if (!service.refreshGemini) {
7999
8535
  return writeError2(res, 501, "gemini allowance refresh is not available");
@@ -8148,7 +8684,7 @@ async function handleAdminApi(req, res, path2, deps) {
8148
8684
  case "server":
8149
8685
  return await handleServer(req, res, method, deps);
8150
8686
  case "images":
8151
- return await handleImages(res, method, rest, deps);
8687
+ return await handleImages(req, res, method, rest, deps);
8152
8688
  case "search":
8153
8689
  return await handleSearchAdmin(req, res, method, rest, deps);
8154
8690
  case "accounts":
@@ -8174,8 +8710,8 @@ async function handleAdminApi(req, res, path2, deps) {
8174
8710
  default:
8175
8711
  return writeJsonError(res, 404, `unknown admin resource '${resource}'`);
8176
8712
  }
8177
- } catch (err8) {
8178
- writeJsonError(res, 500, err8 instanceof Error ? err8.message : String(err8));
8713
+ } catch (err9) {
8714
+ writeJsonError(res, 500, err9 instanceof Error ? err9.message : String(err9));
8179
8715
  }
8180
8716
  }
8181
8717
  function requestQuery(req) {
@@ -8350,7 +8886,7 @@ async function handleDiscoverModels(res, id, cfg) {
8350
8886
  const headers = { Accept: "application/json" };
8351
8887
  if (resolvedKey) headers["Authorization"] = `Bearer ${resolvedKey}`;
8352
8888
  Object.assign(headers, expandRowExtraHeaders(row));
8353
- const response = await (0, import_upstreamFetch10.fetchUpstream)(url, { method: "GET", headers }, { providerId: "byo" });
8889
+ const response = await (0, import_upstreamFetch12.fetchUpstream)(url, { method: "GET", headers }, { providerId: "byo" });
8354
8890
  if (!response.ok) {
8355
8891
  const text = await response.text().catch(() => "");
8356
8892
  let message = text.slice(0, 300);
@@ -8367,8 +8903,8 @@ async function handleDiscoverModels(res, id, cfg) {
8367
8903
  const data = await response.json();
8368
8904
  const models = Array.isArray(data?.data) ? data.data.map((m) => typeof m?.id === "string" ? m.id : "").filter((m) => m.length > 0) : [];
8369
8905
  return writeJson4(res, 200, { models });
8370
- } catch (err8) {
8371
- const message = err8 instanceof Error ? err8.message : String(err8);
8906
+ } catch (err9) {
8907
+ const message = err9 instanceof Error ? err9.message : String(err9);
8372
8908
  return writeJson4(res, 200, { models: [], error: `discovery failed: ${message}` });
8373
8909
  }
8374
8910
  }
@@ -8410,7 +8946,7 @@ async function handleTestModel(req, res, id, cfg) {
8410
8946
  Object.assign(headers, expandRowExtraHeaders(row));
8411
8947
  const startedAt = Date.now();
8412
8948
  try {
8413
- const response = await (0, import_upstreamFetch10.fetchUpstream)(
8949
+ const response = await (0, import_upstreamFetch12.fetchUpstream)(
8414
8950
  url,
8415
8951
  { method: "POST", headers, body: JSON.stringify(payload) },
8416
8952
  { providerId: "byo" }
@@ -8432,8 +8968,8 @@ async function handleTestModel(req, res, id, cfg) {
8432
8968
  latencyMs,
8433
8969
  sample: extractSampleText(text, row.apiFormat)
8434
8970
  });
8435
- } catch (err8) {
8436
- const message = err8 instanceof Error ? err8.message : String(err8);
8971
+ } catch (err9) {
8972
+ const message = err9 instanceof Error ? err9.message : String(err9);
8437
8973
  return writeJson4(res, 200, { ok: false, latencyMs: Date.now() - startedAt, message });
8438
8974
  }
8439
8975
  }
@@ -9018,8 +9554,8 @@ function imageConfigurationAuditFields(previous, next) {
9018
9554
  const after = next ?? import_outbound_api5.DEFAULT_IMAGES_SERVER_CONFIG;
9019
9555
  const fields = [];
9020
9556
  if (before.enabled !== after.enabled) fields.push("enablement");
9021
- if (before.provider !== after.provider) fields.push("provider");
9022
- if (before.defaultModel !== after.defaultModel || !sameConfigValue(before.modelAliases, after.modelAliases)) fields.push("model");
9557
+ if (!sameConfigValue(before.models, after.models)) fields.push("provider");
9558
+ if (before.defaultModel !== after.defaultModel || !sameConfigValue(before.aliases, after.aliases) || !sameConfigValue(before.codex, after.codex)) fields.push("model");
9023
9559
  if (!sameConfigValue(before.account, after.account)) fields.push("account");
9024
9560
  if (!sameConfigValue(before.queue, after.queue)) fields.push("queue");
9025
9561
  if (!sameConfigValue(before.temporary, after.temporary)) fields.push("temporary");
@@ -9223,6 +9759,12 @@ async function handleAccounts(req, res, method, rest, deps) {
9223
9759
  deps.accountAllowanceService
9224
9760
  );
9225
9761
  }
9762
+ if (method === "GET" && rest[0] === "antigravity" && rest[1] === "models") {
9763
+ const result = await handleAntigravityModelsRoute({
9764
+ resolveAntigravityAccessToken: deps.resolveAntigravityAccessToken ?? (async () => null)
9765
+ });
9766
+ return writeJson4(res, result.status, result.body);
9767
+ }
9226
9768
  if (method === "GET" && rest.length === 0) {
9227
9769
  const accounts = await deps.subscriptionAccounts.listAll();
9228
9770
  const providerAccounts = await deps.subscriptionTokenWriter.listSanitizedAccounts();
@@ -9248,12 +9790,12 @@ async function handleAccounts(req, res, method, rest, deps) {
9248
9790
  }
9249
9791
  return writeJson4(res, 200, { ok: true, affected: result.affected });
9250
9792
  }
9251
- if (method === "GET" && (rest[0] === "codex" || rest[0] === "kimi" || rest[0] === "grok" || rest[0] === "copilot") && rest[1] === "oauth" && rest[3] === "status") {
9252
- 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);
9793
+ if (method === "GET" && (rest[0] === "codex" || rest[0] === "kimi" || rest[0] === "grok" || rest[0] === "copilot" || rest[0] === "antigravity") && rest[1] === "oauth" && rest[3] === "status") {
9794
+ 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);
9253
9795
  return writeJson4(res, result.status, result.body);
9254
9796
  }
9255
- if (method === "DELETE" && (rest[0] === "codex" || rest[0] === "kimi" || rest[0] === "grok" || rest[0] === "copilot") && rest[1] === "oauth" && rest[2]) {
9256
- 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);
9797
+ if (method === "DELETE" && (rest[0] === "codex" || rest[0] === "kimi" || rest[0] === "grok" || rest[0] === "copilot" || rest[0] === "antigravity") && rest[1] === "oauth" && rest[2]) {
9798
+ 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);
9257
9799
  return writeJson4(res, result.status, result.body);
9258
9800
  }
9259
9801
  if (method === "GET" && rest.length === 3 && rest[2] === "diagnostics") {
@@ -9323,6 +9865,10 @@ async function handleAccounts(req, res, method, rest, deps) {
9323
9865
  const result2 = await handleCopilotOAuthStart(deps, body2["enterpriseUrl"]);
9324
9866
  return writeJson4(res, result2.status, result2.body);
9325
9867
  }
9868
+ if (providerId === "antigravity") {
9869
+ const result2 = handleAntigravityOAuthStart(deps);
9870
+ return writeJson4(res, result2.status, result2.body);
9871
+ }
9326
9872
  const result = handleOAuthStart(providerId, deps);
9327
9873
  return writeJson4(res, result.status, result.body);
9328
9874
  }
@@ -9685,7 +10231,41 @@ function imageEndpointUrls(base) {
9685
10231
  edits: `${base}/v1/images/edits`
9686
10232
  }) : null;
9687
10233
  }
9688
- async function handleImages(res, method, rest, deps) {
10234
+ function imageProviderEvidence(images, capabilities) {
10235
+ const evidenceAt = safeStatusTimestamp(capabilities?.oldestEvidenceAt);
10236
+ const resolvedAt = safeStatusTimestamp(capabilities?.resolvedAt);
10237
+ if (evidenceAt === void 0 || resolvedAt === void 0) return null;
10238
+ const expiresAt = evidenceAt <= Number.MAX_SAFE_INTEGER - images.evidenceTtlMs ? evidenceAt + images.evidenceTtlMs : void 0;
10239
+ return Object.freeze({
10240
+ verifiedAt: evidenceAt,
10241
+ ageMs: Math.max(0, resolvedAt - evidenceAt),
10242
+ ...expiresAt !== void 0 ? { expiresAt } : {}
10243
+ });
10244
+ }
10245
+ async function handleImagesVerifyLive(req, res, deps) {
10246
+ const verifier = deps.imageLiveVerifier;
10247
+ if (!verifier) {
10248
+ return writeJsonError(res, 501, "Images live verification is not available");
10249
+ }
10250
+ const serverConfig = await (0, import_outbound_api5.loadServerConfig)(deps.settingsStore);
10251
+ const images = serverConfig.images ?? import_outbound_api5.DEFAULT_IMAGES_SERVER_CONFIG;
10252
+ req.resume();
10253
+ const controller = new AbortController();
10254
+ req.on("close", () => controller.abort());
10255
+ const result = await verifier.verifyLive(images, controller.signal);
10256
+ const antigravityRouted = Object.values(images.models).includes("antigravity-subscription");
10257
+ return writeJson4(res, 200, {
10258
+ ...result,
10259
+ ...antigravityRouted ? { antigravityDeferred: true } : {}
10260
+ });
10261
+ }
10262
+ async function handleImages(req, res, method, rest, deps) {
10263
+ if (rest.length === 1 && rest[0] === "verify-live") {
10264
+ if (method !== "POST") {
10265
+ return writeJsonError(res, 405, `method ${method} not allowed on Images verify-live`);
10266
+ }
10267
+ return handleImagesVerifyLive(req, res, deps);
10268
+ }
9689
10269
  if (rest.length !== 1 || rest[0] !== "capabilities") {
9690
10270
  return writeJsonError(res, 404, "unknown Images admin resource");
9691
10271
  }
@@ -9700,14 +10280,14 @@ async function handleImages(res, method, rest, deps) {
9700
10280
  const capability = await reader.inspectCapability(IMAGE_ADMIN_STATUS_TENANT);
9701
10281
  const resources = safeRuntimeResources(reader.resourceStatus());
9702
10282
  const outbound = deps.outboundApiServer.getStatus();
9703
- const evidenceAt = safeStatusTimestamp(capability.capabilities?.oldestEvidenceAt);
9704
- const resolvedAt = safeStatusTimestamp(capability.capabilities?.resolvedAt);
9705
- const expiresAt = evidenceAt !== void 0 && evidenceAt <= Number.MAX_SAFE_INTEGER - images.evidenceTtlMs ? evidenceAt + images.evidenceTtlMs : void 0;
9706
- const evidence = evidenceAt !== void 0 && resolvedAt !== void 0 ? Object.freeze({
9707
- verifiedAt: evidenceAt,
9708
- ageMs: Math.max(0, resolvedAt - evidenceAt),
9709
- ...expiresAt !== void 0 ? { expiresAt } : {}
9710
- }) : null;
10283
+ const evidence = imageProviderEvidence(images, capability.capabilities);
10284
+ const providers = (capability.providers ?? []).map((provider) => Object.freeze({
10285
+ providerId: provider.providerId,
10286
+ available: provider.available === true,
10287
+ reason: provider.available ? null : safeImageCapabilityReason(provider.reason),
10288
+ models: Object.freeze([...provider.models]),
10289
+ evidence: imageProviderEvidence(images, provider.capabilities)
10290
+ }));
9711
10291
  const draining = lifecycle.draining.map((generation) => Object.freeze({
9712
10292
  generationId: safeImageGenerationId(generation.generationId),
9713
10293
  enabled: generation.enabled,
@@ -9717,7 +10297,7 @@ async function handleImages(res, method, rest, deps) {
9717
10297
  return writeJson4(res, 200, {
9718
10298
  configured: {
9719
10299
  enabled: images.enabled,
9720
- provider: images.provider,
10300
+ provider: images.models[images.defaultModel] ?? "codex-subscription",
9721
10301
  model: images.defaultModel,
9722
10302
  remoteUrlsEnabled: images.remote.enabled,
9723
10303
  referenceTtlMs: images.references.ttlMs
@@ -9728,6 +10308,7 @@ async function handleImages(res, method, rest, deps) {
9728
10308
  evidence,
9729
10309
  features: safeCapabilityValues(capability.capabilities, images.defaultModel)
9730
10310
  },
10311
+ providers,
9731
10312
  runtime: {
9732
10313
  disposed: lifecycle.disposed,
9733
10314
  generationId: safeImageGenerationId(lifecycle.current.generationId),
@@ -9817,12 +10398,12 @@ async function handlePlayground(req, res, method, deps) {
9817
10398
  const payload = body["body"];
9818
10399
  const status = deps.outboundApiServer.getStatus();
9819
10400
  if (!status.running || !status.port) return writeJsonError(res, 503, "outbound server not running");
9820
- const path2 = resolvePlaygroundPath(endpoint, isRecord7(payload) ? payload : {});
10401
+ const path2 = resolvePlaygroundPath(endpoint, isRecord9(payload) ? payload : {});
9821
10402
  if (!path2) return writeJsonError(res, 400, `unknown endpoint '${endpoint}'`);
9822
10403
  const upstreamBody = typeof payload === "string" ? payload : JSON.stringify(payload ?? {});
9823
10404
  await proxyToOutbound(res, status.port, path2, key, upstreamBody);
9824
10405
  }
9825
- function isRecord7(v) {
10406
+ function isRecord9(v) {
9826
10407
  return !!v && typeof v === "object" && !Array.isArray(v);
9827
10408
  }
9828
10409
  function proxyToOutbound(res, outboundPort, path2, key, body) {
@@ -9851,8 +10432,8 @@ function proxyToOutbound(res, outboundPort, path2, key, body) {
9851
10432
  });
9852
10433
  }
9853
10434
  );
9854
- upstream.on("error", (err8) => {
9855
- if (!res.headersSent) writeJsonError(res, 502, `playground proxy failed: ${err8.message}`);
10435
+ upstream.on("error", (err9) => {
10436
+ if (!res.headersSent) writeJsonError(res, 502, `playground proxy failed: ${err9.message}`);
9856
10437
  else res.end();
9857
10438
  resolve11();
9858
10439
  });
@@ -9958,7 +10539,7 @@ async function handleUiStatic(req, res, urlPath, uiDist) {
9958
10539
  }
9959
10540
 
9960
10541
  // src/admin/version.ts
9961
- var DAEMON_VERSION = true ? "0.4.2" : "0.0.0-dev";
10542
+ var DAEMON_VERSION = true ? "0.4.4" : "0.0.0-dev";
9962
10543
 
9963
10544
  // src/admin/AdminServer.ts
9964
10545
  var LOOPBACK_ADDR = "127.0.0.1";
@@ -10001,13 +10582,13 @@ var AdminServer = class {
10001
10582
  const server = import_node_http2.default.createServer((req, res) => {
10002
10583
  this.onRequest(req, res);
10003
10584
  });
10004
- const onError = (err8) => {
10005
- if (err8.code === "EADDRINUSE" && port !== 0) {
10585
+ const onError = (err9) => {
10586
+ if (err9.code === "EADDRINUSE" && port !== 0) {
10006
10587
  server.removeListener("error", onError);
10007
10588
  this.listen(bindAddr, 0).then(resolve11, reject);
10008
10589
  return;
10009
10590
  }
10010
- reject(err8);
10591
+ reject(err9);
10011
10592
  };
10012
10593
  server.on("error", onError);
10013
10594
  server.listen(port, bindAddr, () => {
@@ -10025,8 +10606,8 @@ var AdminServer = class {
10025
10606
  }
10026
10607
  /** Per-request handler: auth gate (when a token is set) → routing. */
10027
10608
  onRequest(req, res) {
10028
- void this.dispatch(req, res).catch((err8) => {
10029
- const message = err8 instanceof Error ? err8.message : String(err8);
10609
+ void this.dispatch(req, res).catch((err9) => {
10610
+ const message = err9 instanceof Error ? err9.message : String(err9);
10030
10611
  this.deps.logger.error("[AdminServer] unhandled error:", message);
10031
10612
  if (!res.headersSent) {
10032
10613
  res.writeHead(500, { "Content-Type": "application/json" });
@@ -10249,7 +10830,10 @@ var HTML_HEADERS = {
10249
10830
  function pageHtml(message) {
10250
10831
  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>`;
10251
10832
  }
10252
- function awaitLoopbackCode(expectedState, timeoutMs = DEFAULT_TIMEOUT_MS, signal) {
10833
+ function awaitLoopbackCode(expectedState, timeoutMs = DEFAULT_TIMEOUT_MS, signal, binding = {}) {
10834
+ const port = binding.port ?? LOOPBACK_PORT;
10835
+ const callbackPath = binding.path ?? CALLBACK_PATH;
10836
+ const label = binding.label ?? "codex";
10253
10837
  return new Promise((resolve11, reject) => {
10254
10838
  let settled = false;
10255
10839
  const finish = (server2, fn) => {
@@ -10260,8 +10844,8 @@ function awaitLoopbackCode(expectedState, timeoutMs = DEFAULT_TIMEOUT_MS, signal
10260
10844
  server2.close();
10261
10845
  };
10262
10846
  const server = (0, import_node_http3.createServer)((req, res) => {
10263
- const url = new URL(req.url ?? "", `http://${LOOPBACK_HOST}:${LOOPBACK_PORT}`);
10264
- if (url.pathname !== CALLBACK_PATH) {
10847
+ const url = new URL(req.url ?? "", `http://${LOOPBACK_HOST}:${port}`);
10848
+ if (url.pathname !== callbackPath) {
10265
10849
  res.writeHead(404, HTML_HEADERS);
10266
10850
  res.end(pageHtml("Not found"));
10267
10851
  return;
@@ -10290,25 +10874,25 @@ function awaitLoopbackCode(expectedState, timeoutMs = DEFAULT_TIMEOUT_MS, signal
10290
10874
  return;
10291
10875
  }
10292
10876
  signal?.addEventListener("abort", abort, { once: true });
10293
- server.on("error", (err8) => {
10877
+ server.on("error", (err9) => {
10294
10878
  if (settled) return;
10295
10879
  settled = true;
10296
10880
  clearTimeout(timer);
10297
- if (err8.code === "EADDRINUSE") {
10881
+ if (err9.code === "EADDRINUSE") {
10298
10882
  reject(
10299
10883
  new Error(
10300
- `login: cannot bind ${LOOPBACK_HOST}:${LOOPBACK_PORT} (address in use) \u2014 another codex login or process is holding the port`
10884
+ `login: cannot bind ${LOOPBACK_HOST}:${port} (address in use) \u2014 another ${label} login or process is holding the port`
10301
10885
  )
10302
10886
  );
10303
10887
  } else {
10304
- reject(err8);
10888
+ reject(err9);
10305
10889
  }
10306
10890
  });
10307
10891
  const timer = setTimeout(() => {
10308
10892
  finish(server, () => reject(new Error(`login: timed out after ${Math.round(timeoutMs / 1e3)}s waiting for the callback`)));
10309
10893
  }, timeoutMs);
10310
10894
  if (typeof timer.unref === "function") timer.unref();
10311
- server.listen(LOOPBACK_PORT, LOOPBACK_HOST);
10895
+ server.listen(port, LOOPBACK_HOST);
10312
10896
  });
10313
10897
  }
10314
10898
 
@@ -10378,7 +10962,7 @@ function createPoolKeysLoader(getProviderRow, autoDisabled) {
10378
10962
 
10379
10963
  // src/allowance/ProviderKeyQuotaService.ts
10380
10964
  var import_core4 = require("@omnicross/core");
10381
- var import_upstreamFetch11 = require("@omnicross/core/pipeline/upstreamFetch");
10965
+ var import_upstreamFetch13 = require("@omnicross/core/pipeline/upstreamFetch");
10382
10966
 
10383
10967
  // src/allowance/ProviderKeyQuota.ts
10384
10968
  var MINUTE_MS3 = 6e4;
@@ -10407,11 +10991,11 @@ function isoInstant3(value) {
10407
10991
  }
10408
10992
  return void 0;
10409
10993
  }
10410
- function secondsUntil8(instant, now) {
10994
+ function secondsUntil9(instant, now) {
10411
10995
  if (!instant) return void 0;
10412
10996
  return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
10413
10997
  }
10414
- function isRecord8(value) {
10998
+ function isRecord10(value) {
10415
10999
  return !!value && typeof value === "object" && !Array.isArray(value);
10416
11000
  }
10417
11001
  function detectProviderKeyQuotaAdapter(baseUrl) {
@@ -10478,17 +11062,17 @@ function zaiWindowIdLabel(durationMs) {
10478
11062
  return { id: "quota", label: "Quota" };
10479
11063
  }
10480
11064
  function parseZaiQuotaPayload(payload, now) {
10481
- if (!isRecord8(payload)) return null;
10482
- const data = isRecord8(payload["data"]) ? payload["data"] : payload;
11065
+ if (!isRecord10(payload)) return null;
11066
+ const data = isRecord10(payload["data"]) ? payload["data"] : payload;
10483
11067
  if (payload["success"] === false) return null;
10484
11068
  const limits = Array.isArray(data["limits"]) ? data["limits"] : [];
10485
11069
  const byWindow = /* @__PURE__ */ new Map();
10486
11070
  for (const raw of limits) {
10487
- if (!isRecord8(raw)) continue;
11071
+ if (!isRecord10(raw)) continue;
10488
11072
  const item = raw;
10489
11073
  if (item.type === void 0) continue;
10490
11074
  const details = raw["usageDetails"];
10491
- if (Array.isArray(details) && details.some((d) => isRecord8(d) && d["modelCode"] === "zread")) {
11075
+ if (Array.isArray(details) && details.some((d) => isRecord10(d) && d["modelCode"] === "zread")) {
10492
11076
  continue;
10493
11077
  }
10494
11078
  const durationMs = zaiWindowDurationMs(item);
@@ -10507,7 +11091,7 @@ function parseZaiQuotaPayload(payload, now) {
10507
11091
  usedPercent,
10508
11092
  ...durationMs !== void 0 ? { windowMinutes: Math.round(durationMs / MINUTE_MS3) } : {},
10509
11093
  ...resetsAt !== void 0 ? { resetsAt } : {},
10510
- remainingSeconds: secondsUntil8(resetsAt, now),
11094
+ remainingSeconds: secondsUntil9(resetsAt, now),
10511
11095
  state: "fresh"
10512
11096
  };
10513
11097
  const existing = byWindow.get(id);
@@ -10521,7 +11105,7 @@ function parseZaiQuotaPayload(payload, now) {
10521
11105
  var MINIMAX_STATUS_EXHAUSTED = 2;
10522
11106
  var MINIMAX_SHARED_BUCKET = "general";
10523
11107
  function parseMiniMaxBucket(value) {
10524
- if (!isRecord8(value)) return null;
11108
+ if (!isRecord10(value)) return null;
10525
11109
  const modelName = typeof value["model_name"] === "string" ? value["model_name"].trim() : "";
10526
11110
  if (!modelName) return null;
10527
11111
  const instant = (v) => {
@@ -10548,14 +11132,14 @@ function minimaxWindow(id, label, windowMinutes, resetsAtMs, remainingPercent, s
10548
11132
  usedPercent,
10549
11133
  ...windowMinutes !== void 0 ? { windowMinutes } : {},
10550
11134
  ...resetsAt !== void 0 ? { resetsAt } : {},
10551
- remainingSeconds: secondsUntil8(resetsAt, now),
11135
+ remainingSeconds: secondsUntil9(resetsAt, now),
10552
11136
  state: usedPercent !== null ? "fresh" : "unavailable"
10553
11137
  };
10554
11138
  }
10555
11139
  function parseMiniMaxTokenPlanPayload(payload, now) {
10556
- if (!isRecord8(payload)) return null;
11140
+ if (!isRecord10(payload)) return null;
10557
11141
  const baseResp = payload["base_resp"];
10558
- if (!isRecord8(baseResp) || baseResp["status_code"] !== 0) return null;
11142
+ if (!isRecord10(baseResp) || baseResp["status_code"] !== 0) return null;
10559
11143
  const buckets = Array.isArray(payload["model_remains"]) ? payload["model_remains"] : [];
10560
11144
  let general = null;
10561
11145
  for (const raw of buckets) {
@@ -10588,11 +11172,11 @@ function parseMiniMaxTokenPlanPayload(payload, now) {
10588
11172
  ];
10589
11173
  }
10590
11174
  function parseUmansUsagePayload(payload, now) {
10591
- if (!isRecord8(payload)) return null;
10592
- const limits = isRecord8(payload["limits"]) ? payload["limits"] : void 0;
10593
- const requests = limits && isRecord8(limits["requests"]) ? limits["requests"] : void 0;
10594
- const usage = isRecord8(payload["usage"]) ? payload["usage"] : void 0;
10595
- const window = isRecord8(payload["window"]) ? payload["window"] : void 0;
11175
+ if (!isRecord10(payload)) return null;
11176
+ const limits = isRecord10(payload["limits"]) ? payload["limits"] : void 0;
11177
+ const requests = limits && isRecord10(limits["requests"]) ? limits["requests"] : void 0;
11178
+ const usage = isRecord10(payload["usage"]) ? payload["usage"] : void 0;
11179
+ const window = isRecord10(payload["window"]) ? payload["window"] : void 0;
10596
11180
  const hardCap = finiteNumber5(requests?.["hard_cap"]);
10597
11181
  const softLimit = finiteNumber5(requests?.["limit"]);
10598
11182
  const requestsInWindow = finiteNumber5(usage?.["requests_in_window"]);
@@ -10613,15 +11197,15 @@ function parseUmansUsagePayload(payload, now) {
10613
11197
  usedPercent,
10614
11198
  windowMinutes: 5 * 60,
10615
11199
  ...resetsAt !== void 0 ? { resetsAt } : {},
10616
- remainingSeconds: secondsUntil8(resetsAt, now),
11200
+ remainingSeconds: secondsUntil9(resetsAt, now),
10617
11201
  state: "fresh"
10618
11202
  }
10619
11203
  ];
10620
11204
  }
10621
11205
  function parseSyntheticQuotasPayload(payload, now) {
10622
- if (!isRecord8(payload)) return null;
10623
- const fiveHour = isRecord8(payload["rollingFiveHourLimit"]) ? payload["rollingFiveHourLimit"] : void 0;
10624
- const weekly = isRecord8(payload["weeklyTokenLimit"]) ? payload["weeklyTokenLimit"] : void 0;
11206
+ if (!isRecord10(payload)) return null;
11207
+ const fiveHour = isRecord10(payload["rollingFiveHourLimit"]) ? payload["rollingFiveHourLimit"] : void 0;
11208
+ const weekly = isRecord10(payload["weeklyTokenLimit"]) ? payload["weeklyTokenLimit"] : void 0;
10625
11209
  const windows = [];
10626
11210
  if (fiveHour) {
10627
11211
  const max = finiteNumber5(fiveHour["max"]);
@@ -10635,7 +11219,7 @@ function parseSyntheticQuotasPayload(payload, now) {
10635
11219
  usedPercent,
10636
11220
  windowMinutes: 5 * 60,
10637
11221
  ...resetsAt !== void 0 ? { resetsAt } : {},
10638
- remainingSeconds: secondsUntil8(resetsAt, now),
11222
+ remainingSeconds: secondsUntil9(resetsAt, now),
10639
11223
  state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
10640
11224
  });
10641
11225
  }
@@ -10650,7 +11234,7 @@ function parseSyntheticQuotasPayload(payload, now) {
10650
11234
  usedPercent,
10651
11235
  windowMinutes: 7 * 24 * 60,
10652
11236
  ...resetsAt !== void 0 ? { resetsAt } : {},
10653
- remainingSeconds: secondsUntil8(resetsAt, now),
11237
+ remainingSeconds: secondsUntil9(resetsAt, now),
10654
11238
  state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
10655
11239
  });
10656
11240
  }
@@ -10662,12 +11246,12 @@ var CLINE_WINDOW_CONFIG = {
10662
11246
  monthly: { id: "thirty-day", label: "30 days", minutes: 30 * 24 * 60 }
10663
11247
  };
10664
11248
  function parseClinePassUsageLimitsPayload(payload, now) {
10665
- if (!isRecord8(payload)) return null;
10666
- const data = isRecord8(payload["data"]) ? payload["data"] : payload;
11249
+ if (!isRecord10(payload)) return null;
11250
+ const data = isRecord10(payload["data"]) ? payload["data"] : payload;
10667
11251
  const limits = Array.isArray(data["limits"]) ? data["limits"] : [];
10668
11252
  const windows = [];
10669
11253
  for (const raw of limits) {
10670
- if (!isRecord8(raw)) continue;
11254
+ if (!isRecord10(raw)) continue;
10671
11255
  const config = CLINE_WINDOW_CONFIG[typeof raw["type"] === "string" ? raw["type"] : ""];
10672
11256
  if (!config) continue;
10673
11257
  const usedPercent = finitePercent4(raw["percentUsed"]);
@@ -10680,7 +11264,7 @@ function parseClinePassUsageLimitsPayload(payload, now) {
10680
11264
  usedPercent,
10681
11265
  windowMinutes: config.minutes,
10682
11266
  ...resetsAt !== void 0 ? { resetsAt } : {},
10683
- remainingSeconds: secondsUntil8(resetsAt, now),
11267
+ remainingSeconds: secondsUntil9(resetsAt, now),
10684
11268
  state: "fresh"
10685
11269
  });
10686
11270
  }
@@ -10719,7 +11303,7 @@ function rowKeyEntries(row) {
10719
11303
  return [];
10720
11304
  }
10721
11305
  var ProviderKeyQuotaService = class {
10722
- constructor(box, fetchImpl = (url, init) => (0, import_upstreamFetch11.fetchUpstream)(url, init, { redactBodies: true }), now = Date.now) {
11306
+ constructor(box, fetchImpl = (url, init) => (0, import_upstreamFetch13.fetchUpstream)(url, init, { redactBodies: true }), now = Date.now) {
10723
11307
  this.box = box;
10724
11308
  this.fetchImpl = fetchImpl;
10725
11309
  this.now = now;
@@ -10822,7 +11406,7 @@ var ProviderKeyQuotaService = class {
10822
11406
  // src/image-generation/ImageDoctorService.ts
10823
11407
  var import_image_generation = require("@omnicross/core/image-generation");
10824
11408
  var import_outbound_api7 = require("@omnicross/core/outbound-api");
10825
- var import_subscriptions9 = require("@omnicross/subscriptions");
11409
+ var import_subscriptions10 = require("@omnicross/subscriptions");
10826
11410
 
10827
11411
  // src/image-generation/FileCodexImageCapabilityEvidenceSource.ts
10828
11412
  var import_node_crypto13 = require("crypto");
@@ -11260,16 +11844,16 @@ function createImageDoctorService(options) {
11260
11844
  paths,
11261
11845
  ttlMs: config.evidenceTtlMs
11262
11846
  }));
11263
- const createLiveVerifier = options.createLiveVerifier ?? ((strategy, config) => (0, import_subscriptions9.createCodexImageLiveVerifier)({
11847
+ const createLiveVerifier = options.createLiveVerifier ?? ((strategy, config) => (0, import_subscriptions10.createCodexImageLiveVerifier)({
11264
11848
  authStrategy: strategy,
11265
11849
  generationTimeoutMs: config.queue.generationTimeoutMs
11266
11850
  }));
11267
- const readAccount = async () => {
11268
- const codex = (await options.subscriptionAccounts.listAll()).find((entry) => entry.providerId === "codex");
11851
+ const readAccount = async (providerId) => {
11852
+ const entry = (await options.subscriptionAccounts.listAll()).find((candidate) => candidate.providerId === providerId);
11269
11853
  return Object.freeze({
11270
- present: codex !== void 0,
11271
- usable: codex?.credentialStatus.ok === true,
11272
- reason: codex === void 0 ? "missing" : codex.credentialStatus.ok ? "ready" : "unavailable"
11854
+ present: entry !== void 0,
11855
+ usable: entry?.credentialStatus.ok === true,
11856
+ reason: entry === void 0 ? "missing" : entry.credentialStatus.ok ? "ready" : "unavailable"
11273
11857
  });
11274
11858
  };
11275
11859
  const activePaths = () => options.storageCatalog.active().resolver;
@@ -11307,6 +11891,7 @@ function createImageDoctorService(options) {
11307
11891
  } catch {
11308
11892
  storesValid = false;
11309
11893
  }
11894
+ const antigravityAccount = await readAccount("antigravity");
11310
11895
  const rows = await options.keyDb.outboundApiKeysList();
11311
11896
  let legacyRows = 0;
11312
11897
  let invalidRows = 0;
@@ -11323,7 +11908,7 @@ function createImageDoctorService(options) {
11323
11908
  invalidRows += 1;
11324
11909
  }
11325
11910
  }
11326
- const account = await readAccount();
11911
+ const account = await readAccount("codex");
11327
11912
  let evidence;
11328
11913
  let evidenceStore;
11329
11914
  try {
@@ -11337,10 +11922,11 @@ function createImageDoctorService(options) {
11337
11922
  return Object.freeze({
11338
11923
  config: Object.freeze({
11339
11924
  enabled: config.enabled,
11340
- provider: config.provider,
11925
+ provider: config.models[config.defaultModel] ?? "codex-subscription",
11341
11926
  model: config.defaultModel,
11342
11927
  valid: configErrors.length === 0,
11343
- errorCount: configErrors.length
11928
+ errorCount: configErrors.length,
11929
+ routedProviders: Object.freeze([...new Set(Object.values(config.models))])
11344
11930
  }),
11345
11931
  roots: Object.freeze({
11346
11932
  valid: verifiedAreas === ROOT_AREAS.length,
@@ -11365,12 +11951,13 @@ function createImageDoctorService(options) {
11365
11951
  imagesAuthorizedRows
11366
11952
  }),
11367
11953
  account,
11954
+ antigravityAccount,
11368
11955
  evidence: Object.freeze(evidence)
11369
11956
  });
11370
11957
  },
11371
11958
  verifyLive: async (config, signal) => {
11372
11959
  if (!config.enabled) return Object.freeze({ ok: false, code: "images_disabled" });
11373
- const account = await readAccount();
11960
+ const account = await readAccount("codex");
11374
11961
  if (!account.usable) {
11375
11962
  return Object.freeze({ ok: false, code: "codex_account_unavailable" });
11376
11963
  }
@@ -11622,7 +12209,7 @@ var ImageCleanupService = class {
11622
12209
  var import_node_crypto16 = require("crypto");
11623
12210
  var import_image_generation5 = require("@omnicross/core/image-generation");
11624
12211
  var import_outbound_api8 = require("@omnicross/core/outbound-api");
11625
- var import_subscriptions10 = require("@omnicross/subscriptions");
12212
+ var import_subscriptions11 = require("@omnicross/subscriptions");
11626
12213
 
11627
12214
  // src/image-generation/ImageApiRuntimeResolver.ts
11628
12215
  var import_node_crypto14 = require("crypto");
@@ -11650,10 +12237,11 @@ function createTrustedImageApiRuntimeResolver(options) {
11650
12237
  throw new TypeError("enabled image remote loading requires a proven resolver");
11651
12238
  }
11652
12239
  const hmacKey = Buffer.from(options.hmacKey);
11653
- const modelAliases = new Map(Object.entries(options.config.modelAliases));
12240
+ const modelAliases = new Map(Object.entries(options.config.aliases));
12241
+ const modelRoutes = new Map(Object.entries(options.config.models));
11654
12242
  const limits = Object.freeze({ ...options.config.limits });
11655
- const providerId = options.config.provider;
11656
12243
  const defaultModel = options.config.defaultModel;
12244
+ const providerId = modelRoutes.get(defaultModel) ?? "codex-subscription";
11657
12245
  const referenceStore = options.referenceStore;
11658
12246
  const retention = Object.freeze({
11659
12247
  enabled: true,
@@ -11674,6 +12262,7 @@ function createTrustedImageApiRuntimeResolver(options) {
11674
12262
  providerId,
11675
12263
  defaultModel,
11676
12264
  modelAliases,
12265
+ modelRoutes,
11677
12266
  limits,
11678
12267
  ...preferredAccountId ? { preferredAccountId } : {},
11679
12268
  ...preferredAccountGroup ? { preferredAccountGroup } : {},
@@ -12075,7 +12664,9 @@ var GENERATION_ID = /^[A-Za-z0-9][A-Za-z0-9_.:-]{0,127}$/u;
12075
12664
  function snapshotConfig(config) {
12076
12665
  return {
12077
12666
  ...config,
12078
- modelAliases: { ...config.modelAliases },
12667
+ models: { ...config.models },
12668
+ aliases: { ...config.aliases },
12669
+ codex: { ...config.codex },
12079
12670
  account: { ...config.account },
12080
12671
  queue: { ...config.queue },
12081
12672
  temporary: { ...config.temporary },
@@ -12109,10 +12700,15 @@ function createImageRuntimeGeneration(options) {
12109
12700
  }
12110
12701
  });
12111
12702
  }
12112
- const authStrategy = options.subscriptionAccounts.getStrategy("codex");
12113
- if (!authStrategy || authStrategy.providerId !== "codex") {
12703
+ const routedProviders = [...new Set(Object.values(config.models))];
12704
+ const codexStrategy = routedProviders.includes("codex-subscription") ? options.subscriptionAccounts.getStrategy("codex") : void 0;
12705
+ if (routedProviders.includes("codex-subscription") && (!codexStrategy || codexStrategy.providerId !== "codex")) {
12114
12706
  throw new TypeError("enabled image runtime requires the Codex subscription strategy");
12115
12707
  }
12708
+ const antigravityStrategy = routedProviders.includes("antigravity-subscription") ? options.subscriptionAccounts.getStrategy("antigravity") : void 0;
12709
+ if (routedProviders.includes("antigravity-subscription") && (!antigravityStrategy || antigravityStrategy.providerId !== "antigravity")) {
12710
+ throw new TypeError("enabled image runtime requires the Antigravity subscription strategy");
12711
+ }
12116
12712
  const privateHmacKey = options.privateHmacKey ? Buffer.from(options.privateHmacKey) : loadOrCreateImageTenantHmacSalt(options.storage.paths, import_node_crypto16.randomBytes);
12117
12713
  if (privateHmacKey.byteLength !== 32) {
12118
12714
  privateHmacKey.fill(0);
@@ -12147,23 +12743,32 @@ function createImageRuntimeGeneration(options) {
12147
12743
  if (options.testOnlySyntheticVerifiedProvider && options.testOnlySyntheticVerifiedProvider.label !== "synthetic-verified-image-provider-test-only") {
12148
12744
  throw new TypeError("synthetic verified image provider test seam label is invalid");
12149
12745
  }
12150
- const provider = options.testOnlySyntheticVerifiedProvider ? options.testOnlySyntheticVerifiedProvider.createProvider({
12746
+ const providers = options.testOnlySyntheticVerifiedProvider ? [options.testOnlySyntheticVerifiedProvider.createProvider({
12151
12747
  generationId: options.generationId,
12152
12748
  scheduler,
12153
12749
  now: options.now ?? Date.now,
12154
12750
  referenceStore: options.storage.referenceStore,
12155
12751
  stateStore: options.storage.stateStore
12156
- }) : (0, import_subscriptions10.createCodexSubscriptionImageProvider)({
12157
- authStrategy,
12752
+ })] : routedProviders.map((providerId) => providerId === "codex-subscription" ? (0, import_subscriptions11.createCodexSubscriptionImageProvider)({
12753
+ authStrategy: codexStrategy,
12158
12754
  evidenceSource: generationEvidenceSource,
12159
12755
  executionScheduler: scheduler,
12160
12756
  generationTimeoutMs: config.queue.generationTimeoutMs,
12757
+ now: options.now,
12758
+ wire: {
12759
+ imageModel: config.codex.imageModel,
12760
+ carrierModel: config.codex.carrierModel
12761
+ }
12762
+ }) : (0, import_subscriptions11.createAntigravitySubscriptionImageProvider)({
12763
+ authStrategy: antigravityStrategy,
12764
+ executionScheduler: scheduler,
12765
+ generationTimeoutMs: config.queue.generationTimeoutMs,
12161
12766
  now: options.now
12162
- });
12163
- if (provider.id !== config.provider) {
12767
+ }));
12768
+ if (providers.length === 1 && providers[0].id !== "codex-subscription") {
12164
12769
  throw new TypeError("synthetic verified image provider id must match configured provider");
12165
12770
  }
12166
- const providerRegistry = new import_image_generation5.ImageProviderRegistry([provider]);
12771
+ const providerRegistry = new import_image_generation5.ImageProviderRegistry(providers);
12167
12772
  const orchestrator = new import_image_generation5.ImageOrchestrator({
12168
12773
  registry: providerRegistry,
12169
12774
  referenceStore: options.storage.referenceStore,
@@ -12185,35 +12790,72 @@ function createImageRuntimeGeneration(options) {
12185
12790
  ...options.createCallId ? { createCallId: options.createCallId } : {},
12186
12791
  ...options.now ? { now: options.now } : {}
12187
12792
  });
12793
+ const defaultProviderId = config.models[config.defaultModel] ?? "codex-subscription";
12794
+ const inspectOneProvider = async (providerId, apiKeyId) => {
12795
+ const capabilities = await orchestrator.getCapabilities(providerId, {
12796
+ requestId: `${options.generationId}:capability-inspection`,
12797
+ tenantId: apiKeyId,
12798
+ signal: new AbortController().signal,
12799
+ sessionKey: `outbound:images:${apiKeyId}`,
12800
+ ...config.account.id ? { preferredAccountId: config.account.id } : {},
12801
+ ...config.account.group ? { preferredAccountGroup: config.account.group } : {},
12802
+ boundAccountFallbackPolicy: config.account.fallback
12803
+ });
12804
+ return capabilities;
12805
+ };
12188
12806
  const inspectCapability = async (apiKeyId) => {
12189
- try {
12190
- const capabilities = await orchestrator.getCapabilities(config.provider, {
12191
- requestId: `${options.generationId}:capability-inspection`,
12192
- tenantId: apiKeyId,
12193
- signal: new AbortController().signal,
12194
- sessionKey: `outbound:images:${apiKeyId}`,
12195
- ...config.account.id ? { preferredAccountId: config.account.id } : {},
12196
- ...config.account.group ? { preferredAccountGroup: config.account.group } : {},
12197
- boundAccountFallbackPolicy: config.account.fallback
12198
- });
12199
- const available = capabilities.available === true && capabilities.generate === true && capabilities.models.includes(config.defaultModel);
12200
- return Object.freeze({
12201
- enabled: true,
12202
- available,
12203
- providerId: config.provider,
12204
- model: config.defaultModel,
12205
- ...!available ? { reason: capabilities.reason ?? "runtime_unavailable" } : {},
12206
- capabilities
12207
- });
12208
- } catch (error) {
12807
+ const providerCapabilities = /* @__PURE__ */ new Map();
12808
+ let defaultProviderError;
12809
+ const providerRows = [];
12810
+ for (const providerId of [...new Set(Object.values(config.models))]) {
12811
+ try {
12812
+ const capabilities2 = await inspectOneProvider(providerId, apiKeyId);
12813
+ providerCapabilities.set(providerId, capabilities2);
12814
+ const affirmed = capabilities2.available === true && capabilities2.generate === true;
12815
+ providerRows.push({
12816
+ providerId,
12817
+ available: affirmed,
12818
+ ...!affirmed ? { reason: capabilities2.reason ?? "runtime_unavailable" } : {},
12819
+ models: affirmed ? Object.entries(config.models).filter(([model, modelProvider]) => modelProvider === providerId && capabilities2.models.includes(model)).map(([model]) => model) : [],
12820
+ capabilities: capabilities2
12821
+ });
12822
+ } catch (error) {
12823
+ if (providerId === defaultProviderId) defaultProviderError = error;
12824
+ providerRows.push({
12825
+ providerId,
12826
+ available: false,
12827
+ reason: error instanceof import_image_generation5.ImageGenerationError && (error.code === "upstream_auth_required" || error.code === "invalid_api_key") ? "account_unverified" : "runtime_unavailable",
12828
+ models: []
12829
+ });
12830
+ }
12831
+ }
12832
+ const providers2 = Object.freeze(providerRows);
12833
+ const routedModels = Object.freeze(
12834
+ providerRows.flatMap((row) => row.available ? row.models : [])
12835
+ );
12836
+ const capabilities = providerCapabilities.get(defaultProviderId);
12837
+ if (!capabilities) {
12209
12838
  return Object.freeze({
12210
12839
  enabled: true,
12211
12840
  available: false,
12212
- providerId: config.provider,
12841
+ providerId: defaultProviderId,
12213
12842
  model: config.defaultModel,
12214
- reason: error instanceof import_image_generation5.ImageGenerationError && (error.code === "upstream_auth_required" || error.code === "invalid_api_key") ? "account_unverified" : "runtime_unavailable"
12843
+ routedModels,
12844
+ providers: providers2,
12845
+ reason: defaultProviderError instanceof import_image_generation5.ImageGenerationError && (defaultProviderError.code === "upstream_auth_required" || defaultProviderError.code === "invalid_api_key") ? "account_unverified" : "runtime_unavailable"
12215
12846
  });
12216
12847
  }
12848
+ const available = capabilities.available === true && capabilities.generate === true && capabilities.models.includes(config.defaultModel);
12849
+ return Object.freeze({
12850
+ enabled: true,
12851
+ available,
12852
+ providerId: defaultProviderId,
12853
+ model: config.defaultModel,
12854
+ routedModels,
12855
+ providers: providers2,
12856
+ ...!available ? { reason: capabilities.reason ?? "runtime_unavailable" } : {},
12857
+ capabilities
12858
+ });
12217
12859
  };
12218
12860
  const resolverToDispose = runtimeResolver;
12219
12861
  const schedulerToDispose = scheduler;
@@ -12251,7 +12893,7 @@ function createImageRuntimeGeneration(options) {
12251
12893
  imageApi,
12252
12894
  hosted,
12253
12895
  hostedRuntime: Object.freeze({
12254
- providerId: config.provider,
12896
+ providerId: defaultProviderId,
12255
12897
  imageModel: config.defaultModel,
12256
12898
  referenceTtlMs: config.references.ttlMs,
12257
12899
  maxOutputBytes: config.limits.maxOutputBytes,
@@ -15194,6 +15836,9 @@ var ImageRuntimeManager = class {
15194
15836
  }
15195
15837
  async listAvailableModels(apiKeyId) {
15196
15838
  const inspection = await this.inspectCapability(apiKeyId);
15839
+ if (inspection.routedModels !== void 0) {
15840
+ return Object.freeze([...inspection.routedModels]);
15841
+ }
15197
15842
  return inspection.available && inspection.model === "gpt-image-2" ? Object.freeze([inspection.model]) : Object.freeze([]);
15198
15843
  }
15199
15844
  resourceStatus() {
@@ -17381,11 +18026,12 @@ var JsonVoucherDb = class {
17381
18026
  // src/ports/JsonSubscriptionCredentialStore.ts
17382
18027
  var import_node_fs28 = require("fs");
17383
18028
  var import_node_path27 = require("path");
18029
+ var import_GeminiCodeAssistProjectResolver5 = require("@omnicross/core/auth/GeminiCodeAssistProjectResolver");
17384
18030
  var import_SubscriptionAccountHealth2 = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
17385
18031
  var import_AccountAllowanceScheduling3 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
17386
- var import_upstreamFetch12 = require("@omnicross/core/pipeline/upstreamFetch");
18032
+ var import_upstreamFetch14 = require("@omnicross/core/pipeline/upstreamFetch");
17387
18033
  var import_SubscriptionIdentityStore2 = require("@omnicross/core/provider-proxy/identity/SubscriptionIdentityStore");
17388
- var import_subscriptions11 = require("@omnicross/subscriptions");
18034
+ var import_subscriptions12 = require("@omnicross/subscriptions");
17389
18035
 
17390
18036
  // src/ports/account-sync.ts
17391
18037
  function viewOf(tokens) {
@@ -17533,7 +18179,7 @@ var JsonSubscriptionCredentialStore = class {
17533
18179
  * a plaintext token pair into `upstream-trace.jsonl`.
17534
18180
  */
17535
18181
  buildRefreshFetch(providerId, accountId) {
17536
- return this.fetchImpl ?? ((url, init) => (0, import_upstreamFetch12.fetchUpstream)(url, init, { providerId, accountId, redactBodies: true }));
18182
+ return this.fetchImpl ?? ((url, init) => (0, import_upstreamFetch14.fetchUpstream)(url, init, { providerId, accountId, redactBodies: true }));
17537
18183
  }
17538
18184
  /**
17539
18185
  * In-flight refresh coalescing. OAuth refresh tokens are
@@ -17574,7 +18220,7 @@ var JsonSubscriptionCredentialStore = class {
17574
18220
  * other hot reads. Never returns token material.
17575
18221
  */
17576
18222
  getAccountProxy(providerId, accountId) {
17577
- if (providerId !== "claude" && providerId !== "codex" && providerId !== "gemini" && providerId !== "opencodego" && providerId !== "kimi" && providerId !== "grok" && providerId !== "copilot") {
18223
+ if (providerId !== "claude" && providerId !== "codex" && providerId !== "gemini" && providerId !== "opencodego" && providerId !== "kimi" && providerId !== "grok" && providerId !== "copilot" && providerId !== "antigravity") {
17578
18224
  return void 0;
17579
18225
  }
17580
18226
  return getAccountProxy(this.readConfig(), providerId, accountId);
@@ -17593,7 +18239,7 @@ var JsonSubscriptionCredentialStore = class {
17593
18239
  const fingerprintOn = identityStore.isEnabled();
17594
18240
  const now = Date.now();
17595
18241
  const out = {};
17596
- for (const provider of ["claude", "codex", "gemini", "opencodego", "kimi", "grok", "copilot"]) {
18242
+ for (const provider of ["claude", "codex", "gemini", "opencodego", "kimi", "grok", "copilot", "antigravity"]) {
17597
18243
  const sanitized = sanitizeAccounts(config, provider);
17598
18244
  if (sanitized.length === 0) continue;
17599
18245
  for (const account of sanitized) {
@@ -17659,7 +18305,7 @@ var JsonSubscriptionCredentialStore = class {
17659
18305
  this.materializeMigration(config);
17660
18306
  const refreshFetch = this.buildRefreshFetch("claude", capturedId);
17661
18307
  try {
17662
- const result = await import_subscriptions11.claudeOAuth.refreshAccessToken(claude.refreshToken, refreshFetch);
18308
+ const result = await import_subscriptions12.claudeOAuth.refreshAccessToken(claude.refreshToken, refreshFetch);
17663
18309
  const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
17664
18310
  const next = {
17665
18311
  ...claude,
@@ -17694,7 +18340,7 @@ var JsonSubscriptionCredentialStore = class {
17694
18340
  this.materializeMigration(config);
17695
18341
  const refreshFetch = this.buildRefreshFetch("codex", capturedId);
17696
18342
  try {
17697
- const result = await import_subscriptions11.codexOAuth.refreshAccessToken(codex.refreshToken, refreshFetch);
18343
+ const result = await import_subscriptions12.codexOAuth.refreshAccessToken(codex.refreshToken, refreshFetch);
17698
18344
  const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
17699
18345
  const next = {
17700
18346
  ...codex,
@@ -17732,7 +18378,7 @@ var JsonSubscriptionCredentialStore = class {
17732
18378
  this.materializeMigration(config);
17733
18379
  const refreshFetch = this.buildRefreshFetch("gemini", capturedId);
17734
18380
  try {
17735
- const result = await import_subscriptions11.geminiOAuth.refreshAccessToken(gemini.refreshToken, refreshFetch);
18381
+ const result = await import_subscriptions12.geminiOAuth.refreshAccessToken(gemini.refreshToken, refreshFetch);
17736
18382
  const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
17737
18383
  const next = {
17738
18384
  ...gemini,
@@ -17768,10 +18414,10 @@ var JsonSubscriptionCredentialStore = class {
17768
18414
  this.materializeMigration(config);
17769
18415
  const refreshFetch = this.buildRefreshFetch("kimi", capturedId);
17770
18416
  try {
17771
- const result = await import_subscriptions11.kimiOAuth.refreshAccessToken(
18417
+ const result = await import_subscriptions12.kimiOAuth.refreshAccessToken(
17772
18418
  kimi.refreshToken,
17773
18419
  refreshFetch,
17774
- import_subscriptions11.kimiOAuth.kimiFingerprintHeaders(kimi.deviceId)
18420
+ import_subscriptions12.kimiOAuth.kimiFingerprintHeaders(kimi.deviceId)
17775
18421
  );
17776
18422
  const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
17777
18423
  const next = {
@@ -17808,8 +18454,8 @@ var JsonSubscriptionCredentialStore = class {
17808
18454
  this.materializeMigration(config);
17809
18455
  const refreshFetch = this.buildRefreshFetch("grok", capturedId);
17810
18456
  try {
17811
- const tokenEndpoint = await import_subscriptions11.grokOAuth.resolveGrokTokenEndpoint(refreshFetch);
17812
- const result = await import_subscriptions11.grokOAuth.refreshGrokAccessToken(grok.refreshToken, tokenEndpoint, refreshFetch);
18457
+ const tokenEndpoint = await import_subscriptions12.grokOAuth.resolveGrokTokenEndpoint(refreshFetch);
18458
+ const result = await import_subscriptions12.grokOAuth.refreshGrokAccessToken(grok.refreshToken, tokenEndpoint, refreshFetch);
17813
18459
  const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
17814
18460
  const next = {
17815
18461
  ...grok,
@@ -17852,6 +18498,76 @@ var JsonSubscriptionCredentialStore = class {
17852
18498
  return false;
17853
18499
  });
17854
18500
  }
18501
+ /**
18502
+ * Refresh the Antigravity (Google) OAuth access token. Like gemini, the
18503
+ * Google token endpoint does NOT return a refresh_token on refresh, so this
18504
+ * writes ONLY access+expiresAt (+status/lastRefreshedAt) and DELIBERATELY
18505
+ * preserves the stored `refreshToken` — plus the account's `projectId`
18506
+ * (a handshake product; the post-refresh re-validation is the refresh
18507
+ * scheduler's hook, not this write) and `email`. HONEST `false` when no
18508
+ * refresh_token.
18509
+ */
18510
+ async refreshAntigravityToken() {
18511
+ return this.coalesce("antigravity:active", async () => {
18512
+ const config = this.readConfig();
18513
+ const active = getActiveAccount(config, "antigravity");
18514
+ const antigravity = active?.tokens;
18515
+ if (!active || !antigravity?.refreshToken) return false;
18516
+ const capturedId = active.id;
18517
+ this.materializeMigration(config);
18518
+ const refreshFetch = this.buildRefreshFetch("antigravity", capturedId);
18519
+ try {
18520
+ const result = await import_subscriptions12.antigravityOAuth.refreshAccessToken(antigravity.refreshToken, refreshFetch);
18521
+ const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
18522
+ const next = {
18523
+ ...antigravity,
18524
+ // KEEP the existing refreshToken/projectId/email.
18525
+ accessToken: result.accessToken,
18526
+ expiresAt,
18527
+ status: "authorized",
18528
+ lastRefreshedAt: (/* @__PURE__ */ new Date()).toISOString(),
18529
+ errorMessage: void 0
18530
+ };
18531
+ this.writeBackById("antigravity", capturedId, next);
18532
+ await this.revalidateAntigravityProject(capturedId);
18533
+ return true;
18534
+ } catch (error) {
18535
+ this.markExpiredById("antigravity", capturedId, antigravity, error);
18536
+ return false;
18537
+ }
18538
+ });
18539
+ }
18540
+ /**
18541
+ * Post-refresh project re-validation hook (antigravity design D8): after a
18542
+ * successful antigravity token refresh, re-run the Code Assist project
18543
+ * handshake and write the (possibly rotated) `projectId` back to the account.
18544
+ * A handshake FAILURE keeps the stored projectId untouched (logged) so the
18545
+ * account keeps serving with the last-known-good project until a later
18546
+ * refresh succeeds. Returns whether the handshake produced a project.
18547
+ */
18548
+ async revalidateAntigravityProject(accountId) {
18549
+ const before = getAccountById(this.readConfig(), "antigravity", accountId);
18550
+ const accessToken = before?.tokens?.accessToken;
18551
+ if (!accessToken) return false;
18552
+ try {
18553
+ const projectId = await (0, import_GeminiCodeAssistProjectResolver5.getAntigravityProjectResolver)().resolveProject(accessToken);
18554
+ if (projectId !== void 0) {
18555
+ const config = this.readConfig();
18556
+ const account = getAccountById(config, "antigravity", accountId);
18557
+ const tokens = account?.tokens;
18558
+ if (account && tokens?.accessToken === accessToken && tokens.projectId !== projectId) {
18559
+ this.writeBackById("antigravity", accountId, { ...tokens, projectId });
18560
+ }
18561
+ return true;
18562
+ }
18563
+ return false;
18564
+ } catch (error) {
18565
+ console.warn(
18566
+ `[JsonSubscriptionCredentialStore] antigravity project re-validation failed for account ${accountId}: ` + (error instanceof Error ? error.message : String(error))
18567
+ );
18568
+ return false;
18569
+ }
18570
+ }
17855
18571
  /**
17856
18572
  * Refresh a SPECIFIC managed account by id (background scheduler sweep and
17857
18573
  * account-pool resolution). It uses only that account's stored refresh
@@ -17880,6 +18596,7 @@ var JsonSubscriptionCredentialStore = class {
17880
18596
  };
17881
18597
  if (refreshed.idToken) next.idToken = refreshed.idToken;
17882
18598
  this.writeBackById(provider, id, next);
18599
+ if (provider === "antigravity") await this.revalidateAntigravityProject(id);
17883
18600
  return true;
17884
18601
  } catch (error) {
17885
18602
  this.markExpiredById(provider, id, captured, error);
@@ -17904,7 +18621,7 @@ var JsonSubscriptionCredentialStore = class {
17904
18621
  }
17905
18622
  const oauth = account.tokens;
17906
18623
  if (!oauth.accessToken) return null;
17907
- if (providerId === "codex" || providerId === "gemini" || providerId === "kimi" || providerId === "grok" || providerId === "copilot") {
18624
+ if (providerId === "codex" || providerId === "gemini" || providerId === "kimi" || providerId === "grok" || providerId === "copilot" || providerId === "antigravity") {
17908
18625
  const expiresAtMs = oauth.expiresAt ? Date.parse(oauth.expiresAt) : 0;
17909
18626
  const expiringSoon = expiresAtMs > 0 && Date.now() >= expiresAtMs - ACCOUNT_REFRESH_LEAD_MS;
17910
18627
  if (expiringSoon && oauth.refreshToken) {
@@ -17997,10 +18714,10 @@ var JsonSubscriptionCredentialStore = class {
17997
18714
  if (provider === "kimi") {
17998
18715
  const account = accountId ? getAccountById(this.readConfig(), "kimi", accountId) : void 0;
17999
18716
  const deviceId = account?.tokens?.deviceId;
18000
- const r2 = await import_subscriptions11.kimiOAuth.refreshAccessToken(
18717
+ const r2 = await import_subscriptions12.kimiOAuth.refreshAccessToken(
18001
18718
  refreshToken,
18002
18719
  refreshFetch,
18003
- import_subscriptions11.kimiOAuth.kimiFingerprintHeaders(deviceId)
18720
+ import_subscriptions12.kimiOAuth.kimiFingerprintHeaders(deviceId)
18004
18721
  );
18005
18722
  return {
18006
18723
  accessToken: r2.accessToken,
@@ -18009,8 +18726,8 @@ var JsonSubscriptionCredentialStore = class {
18009
18726
  };
18010
18727
  }
18011
18728
  if (provider === "grok") {
18012
- const tokenEndpoint = await import_subscriptions11.grokOAuth.resolveGrokTokenEndpoint(refreshFetch);
18013
- const r2 = await import_subscriptions11.grokOAuth.refreshGrokAccessToken(refreshToken, tokenEndpoint, refreshFetch);
18729
+ const tokenEndpoint = await import_subscriptions12.grokOAuth.resolveGrokTokenEndpoint(refreshFetch);
18730
+ const r2 = await import_subscriptions12.grokOAuth.refreshGrokAccessToken(refreshToken, tokenEndpoint, refreshFetch);
18014
18731
  return {
18015
18732
  accessToken: r2.accessToken,
18016
18733
  refreshToken: r2.refreshToken,
@@ -18020,7 +18737,14 @@ var JsonSubscriptionCredentialStore = class {
18020
18737
  if (provider === "copilot") {
18021
18738
  throw new Error("GitHub Copilot tokens cannot be refreshed \u2014 re-authenticate the account");
18022
18739
  }
18023
- const flow = provider === "claude" ? import_subscriptions11.claudeOAuth : provider === "codex" ? import_subscriptions11.codexOAuth : import_subscriptions11.geminiOAuth;
18740
+ if (provider === "antigravity") {
18741
+ const r2 = await import_subscriptions12.antigravityOAuth.refreshAccessToken(refreshToken, refreshFetch);
18742
+ return {
18743
+ accessToken: r2.accessToken,
18744
+ expiresAt: new Date(Date.now() + r2.expiresIn * 1e3).toISOString()
18745
+ };
18746
+ }
18747
+ const flow = provider === "claude" ? import_subscriptions12.claudeOAuth : provider === "codex" ? import_subscriptions12.codexOAuth : import_subscriptions12.geminiOAuth;
18024
18748
  const r = await flow.refreshAccessToken(refreshToken, refreshFetch);
18025
18749
  return {
18026
18750
  accessToken: r.accessToken,
@@ -18263,7 +18987,7 @@ var JsonSubscriptionCredentialStore = class {
18263
18987
  };
18264
18988
 
18265
18989
  // src/AccountHealthProbeScheduler.ts
18266
- var import_upstreamFetch13 = require("@omnicross/core/pipeline/upstreamFetch");
18990
+ var import_upstreamFetch15 = require("@omnicross/core/pipeline/upstreamFetch");
18267
18991
 
18268
18992
  // src/probe/CodexGenerationProbe.ts
18269
18993
  var import_codexCliHeaders = require("@omnicross/core/provider-proxy/identity/codexCliHeaders");
@@ -18415,7 +19139,11 @@ var PROVIDER_PROBE_PLANS = {
18415
19139
  // The Copilot quota endpoint (copilot_internal/user) is a verified FREE
18416
19140
  // authed GET but lives on api.github.com with its own auth dialect and a
18417
19141
  // monthly-only window — the allowance collector owns the health surface.
18418
- copilot: { kind: "local" }
19142
+ copilot: { kind: "local" },
19143
+ // Antigravity's quota endpoints are POST RPCs on daily-cloudcode-pa (not a
19144
+ // cheap GET) and need the antigravity/hub UA — the allowance collector owns
19145
+ // the health surface; the probe stays local.
19146
+ antigravity: { kind: "local" }
18419
19147
  };
18420
19148
  function probePlanFor(providerId) {
18421
19149
  return PROVIDER_PROBE_PLANS[providerId] ?? { kind: "local" };
@@ -18437,7 +19165,7 @@ var AccountHealthProbeScheduler = class {
18437
19165
  this.logger = logger;
18438
19166
  this.config = config;
18439
19167
  this.now = opts.now ?? Date.now;
18440
- this.fetchImpl = opts.fetchImpl ?? import_upstreamFetch13.fetchUpstream;
19168
+ this.fetchImpl = opts.fetchImpl ?? import_upstreamFetch15.fetchUpstream;
18441
19169
  this.sleep = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
18442
19170
  this.planFor = opts.planFor ?? probePlanFor;
18443
19171
  }
@@ -19593,7 +20321,7 @@ var AuditWriter = class {
19593
20321
  var import_node_fs34 = require("fs");
19594
20322
  var import_node_crypto24 = require("crypto");
19595
20323
  var import_node_path34 = require("path");
19596
- var import_upstreamFetch14 = require("@omnicross/core/pipeline/upstreamFetch");
20324
+ var import_upstreamFetch16 = require("@omnicross/core/pipeline/upstreamFetch");
19597
20325
 
19598
20326
  // src/billing/billingFiles.ts
19599
20327
  var BILLING_FILE_RE = /^billing-(\d{4})-(\d{2})-(\d{2})\.jsonl$/;
@@ -19616,7 +20344,7 @@ var BillingPublisher = class {
19616
20344
  constructor(billingDir, logger, opts = {}) {
19617
20345
  this.billingDir = billingDir;
19618
20346
  this.logger = logger;
19619
- this.fetchImpl = opts.fetchImpl ?? ((url, init) => (0, import_upstreamFetch14.fetchUpstream)(url, init));
20347
+ this.fetchImpl = opts.fetchImpl ?? ((url, init) => (0, import_upstreamFetch16.fetchUpstream)(url, init));
19620
20348
  this.defer = opts.defer ?? ((fn) => setTimeout(fn, 0));
19621
20349
  this.timeoutMs = opts.timeoutMs ?? BILLING_POST_TIMEOUT_MS;
19622
20350
  this.now = opts.now ?? Date.now;
@@ -19866,7 +20594,7 @@ var BillingRetrySweeper = class {
19866
20594
  // src/TokenRefreshScheduler.ts
19867
20595
  var REFRESH_LEAD_MS2 = 5 * 6e4;
19868
20596
  var SWEEP_INTERVAL_MS5 = 6e4;
19869
- var OAUTH_PROVIDERS2 = ["claude", "codex", "gemini", "kimi", "grok", "copilot"];
20597
+ var OAUTH_PROVIDERS2 = ["claude", "codex", "gemini", "kimi", "grok", "copilot", "antigravity"];
19870
20598
  var TokenRefreshScheduler = class {
19871
20599
  constructor(store, logger, intervalMs = SWEEP_INTERVAL_MS5, leadMs = REFRESH_LEAD_MS2) {
19872
20600
  this.store = store;
@@ -19957,6 +20685,8 @@ var TokenRefreshScheduler = class {
19957
20685
  // never reaches this — the branch exists for union totality.
19958
20686
  case "copilot":
19959
20687
  return this.store.refreshCopilotToken();
20688
+ case "antigravity":
20689
+ return this.store.refreshAntigravityToken();
19960
20690
  }
19961
20691
  }
19962
20692
  };
@@ -20033,7 +20763,7 @@ function createRouteLeaseSubscriptionPreflight(credentials) {
20033
20763
 
20034
20764
  // src/webhook/WebhookDispatcher.ts
20035
20765
  var import_node_crypto25 = require("crypto");
20036
- var import_upstreamFetch15 = require("@omnicross/core/pipeline/upstreamFetch");
20766
+ var import_upstreamFetch17 = require("@omnicross/core/pipeline/upstreamFetch");
20037
20767
  var WEBHOOK_MAX_ATTEMPTS = 3;
20038
20768
  var WEBHOOK_QUEUE_MAX = 1e3;
20039
20769
  var WEBHOOK_SEND_TIMEOUT_MS = 1e4;
@@ -20053,7 +20783,7 @@ var WebhookDispatcher = class {
20053
20783
  sleep;
20054
20784
  now;
20055
20785
  constructor(opts = {}) {
20056
- this.fetchImpl = opts.fetchImpl ?? ((url, init) => (0, import_upstreamFetch15.fetchUpstream)(url, init));
20786
+ this.fetchImpl = opts.fetchImpl ?? ((url, init) => (0, import_upstreamFetch17.fetchUpstream)(url, init));
20057
20787
  this.logger = opts.logger;
20058
20788
  this.maxAttempts = opts.maxAttempts ?? WEBHOOK_MAX_ATTEMPTS;
20059
20789
  this.queueMax = opts.queueMax ?? WEBHOOK_QUEUE_MAX;
@@ -20139,8 +20869,8 @@ var WebhookDispatcher = class {
20139
20869
  signal: AbortSignal.timeout(this.timeoutMs)
20140
20870
  });
20141
20871
  return res.ok ? { ok: true, status: res.status } : { ok: false, status: res.status };
20142
- } catch (err8) {
20143
- return { ok: false, error: err8 instanceof Error ? err8.message : String(err8) };
20872
+ } catch (err9) {
20873
+ return { ok: false, error: err9 instanceof Error ? err9.message : String(err9) };
20144
20874
  }
20145
20875
  }
20146
20876
  /**
@@ -20277,12 +21007,12 @@ function buildDaemon(config, paths) {
20277
21007
  setSecretBox(secretBox3);
20278
21008
  setSecretBox2(secretBox3);
20279
21009
  const decryptedConfig = decryptConfigSecrets(config, secretBox3);
20280
- const accountAllowanceStore = new import_AccountAllowanceStore10.AccountAllowanceStore(
21010
+ const accountAllowanceStore = new import_AccountAllowanceStore11.AccountAllowanceStore(
20281
21011
  Date.now,
20282
21012
  void 0,
20283
21013
  new JsonAccountAllowancePersistence(defaultAccountAllowancePath(paths.configPath))
20284
21014
  );
20285
- (0, import_AccountAllowanceStore10.setSharedAccountAllowanceStore)(accountAllowanceStore);
21015
+ (0, import_AccountAllowanceStore11.setSharedAccountAllowanceStore)(accountAllowanceStore);
20286
21016
  (0, import_AccountAllowanceScheduling5.getSharedAccountAllowanceScheduling)().configure(
20287
21017
  (0, import_outbound_api10.normalizeServerConfig)(decryptedConfig.server).allowanceScheduling
20288
21018
  );
@@ -20307,20 +21037,22 @@ function buildDaemon(config, paths) {
20307
21037
  claudeAllowanceRefreshScheduler.configure(
20308
21038
  (0, import_outbound_api10.normalizeServerConfig)(decryptedConfig.server).allowanceScheduling
20309
21039
  );
20310
- const subscriptionAccounts = new import_subscriptions12.SubscriptionAccountService(credentialStore);
20311
- (0, import_subscriptions12.setSubscriptionAccountService)(subscriptionAccounts);
20312
- const subscriptionRegistry = new import_subscriptions12.SubscriptionProviderRegistry(
21040
+ const subscriptionAccounts = new import_subscriptions13.SubscriptionAccountService(credentialStore);
21041
+ (0, import_subscriptions13.setSubscriptionAccountService)(subscriptionAccounts);
21042
+ const subscriptionRegistry = new import_subscriptions13.SubscriptionProviderRegistry(
20313
21043
  subscriptionAccounts,
20314
21044
  credentialStore
20315
21045
  );
20316
- (0, import_subscriptions12.setSubscriptionProviderRegistry)(subscriptionRegistry);
21046
+ (0, import_subscriptions13.setSubscriptionProviderRegistry)(subscriptionRegistry);
20317
21047
  setServerProxyConfig(decryptedConfig.server?.proxy);
20318
- (0, import_upstreamFetch16.setUpstreamProxyResolver)(
21048
+ (0, import_upstreamFetch18.setUpstreamProxyResolver)(
20319
21049
  createUpstreamProxyResolver({
20320
21050
  getAccountProxy: (providerId, accountId) => credentialStore.getAccountProxy(providerId, accountId)
20321
21051
  })
20322
21052
  );
20323
- (0, import_gemini_code_assist_resolver.setGeminiCodeAssistResolver)((0, import_GeminiCodeAssistProjectResolver2.getGeminiCodeAssistProjectResolver)());
21053
+ (0, import_gemini_code_assist_resolver.setGeminiCodeAssistResolver)((0, import_GeminiCodeAssistProjectResolver6.getGeminiCodeAssistProjectResolver)());
21054
+ (0, import_antigravityFailover.setAntigravitySandboxFailover)(decryptedConfig.antigravity?.sandboxFailover === true);
21055
+ (0, import_openCodeGoHeaders2.setOpenCodeGoUserAgent)(decryptedConfig.opencodego?.userAgent ?? null);
20324
21056
  const autoDisableStore = new AutoDisableStore();
20325
21057
  const providerKeyQuotaService = new ProviderKeyQuotaService(secretBox3);
20326
21058
  const apiKeyPool = new import_ApiKeyPoolService.ApiKeyPoolService(
@@ -20339,7 +21071,7 @@ function buildDaemon(config, paths) {
20339
21071
  const pricingEngine = new import_usage2.PricingEngine(pricingStore, logger, {
20340
21072
  // Catalog egress follows the same global/env proxy policy as every other
20341
21073
  // daemon upstream call; no provider/account override applies here.
20342
- fetchImpl: ((input, init) => (0, import_upstreamFetch16.fetchUpstream)(String(input), init ?? {}))
21074
+ fetchImpl: ((input, init) => (0, import_upstreamFetch18.fetchUpstream)(String(input), init ?? {}))
20343
21075
  });
20344
21076
  const pricingRefreshScheduler = new PricingRefreshScheduler(
20345
21077
  pricingEngine,
@@ -20581,6 +21313,7 @@ function buildDaemon(config, paths) {
20581
21313
  outboundApiServer,
20582
21314
  imageRuntimeConfig,
20583
21315
  imageRuntimeStatus: paths.imageRuntimeStatus ?? imageRuntimeManager,
21316
+ imageLiveVerifier: paths.imageLiveVerifier ?? imageDoctor,
20584
21317
  imageConfigAudit: paths.imageConfigAudit ?? ((record) => {
20585
21318
  imageObservability.recordConfigurationAudit(record);
20586
21319
  }),
@@ -20624,7 +21357,7 @@ function buildDaemon(config, paths) {
20624
21357
  // — `server.proxy.byProvider[...]` was silently skipped — and the call was
20625
21358
  // excluded from the upstream trace, so a failing login left no evidence.
20626
21359
  // `redactBodies` keeps the code/verifier + minted token out of that trace.
20627
- oauthExchangeFetch: paths.oauthExchangeFetch ? () => paths.oauthExchangeFetch : (providerId) => (url, init) => (0, import_upstreamFetch16.fetchUpstream)(url, init, { providerId, redactBodies: true }),
21360
+ oauthExchangeFetch: paths.oauthExchangeFetch ? () => paths.oauthExchangeFetch : (providerId) => (url, init) => (0, import_upstreamFetch18.fetchUpstream)(url, init, { providerId, redactBodies: true }),
20628
21361
  subscriptionAccountAppender: credentialStore,
20629
21362
  // Codex interactive OAuth (app-parity-2 child 5) — the async loopback flow store
20630
21363
  // + the one-shot 127.0.0.1:1455 listener. Token captured + persisted daemon-side;
@@ -20639,6 +21372,21 @@ function buildDaemon(config, paths) {
20639
21372
  // Grok interactive OAuth — the same async DEVICE-CODE shape as kimi.
20640
21373
  grokSessions: new CodexOAuthSessionStore(),
20641
21374
  copilotSessions: new CodexOAuthSessionStore(),
21375
+ // Antigravity interactive OAuth — the async LOOPBACK flow store + the
21376
+ // one-shot 127.0.0.1:51121 listener (same shape as codex; test seam below).
21377
+ antigravitySessions: new CodexOAuthSessionStore(),
21378
+ antigravityAwaitLoopback: paths.antigravityAwaitLoopback ?? ((state, timeoutMs, signal) => awaitLoopbackCode(state, timeoutMs, signal, {
21379
+ port: 51121,
21380
+ path: "/oauth-callback",
21381
+ label: "antigravity"
21382
+ })),
21383
+ // The dynamic model-catalog probe's token source (the ACTIVE antigravity
21384
+ // account; refreshed by the by-id near-expiry seam inside the lookup).
21385
+ resolveAntigravityAccessToken: async () => {
21386
+ const config2 = await credentialStore.getFullConfig();
21387
+ const activeId = config2.activeAntigravityAccountId ?? config2.antigravityAccounts?.[0]?.id;
21388
+ return activeId ? credentialStore.getAccessTokenForAccount("antigravity", activeId) : null;
21389
+ },
20642
21390
  // Migration pack (app-parity child 6, design D2/D3) — the concrete credential
20643
21391
  // store provides BOTH the full DECRYPTED read (`getFullConfig`, export) and
20644
21392
  // the multi-account append (`appendProviderAccount`, import re-encrypts at-
@@ -20697,7 +21445,7 @@ function buildDaemon(config, paths) {
20697
21445
  });
20698
21446
  const webhookDispatcher = new WebhookDispatcher({
20699
21447
  logger,
20700
- fetchImpl: (url, init) => (0, import_upstreamFetch16.fetchUpstream)(url, init)
21448
+ fetchImpl: (url, init) => (0, import_upstreamFetch18.fetchUpstream)(url, init)
20701
21449
  });
20702
21450
  setWebhookRuntime(webhookDispatcher, (0, import_SubscriptionAccountHealth4.getSharedAccountHealth)());
20703
21451
  const auditWriter = new AuditWriter(auditDir, logger);
@@ -20832,15 +21580,59 @@ function buildClaudeDoctorChecks(config) {
20832
21580
  });
20833
21581
  return checks;
20834
21582
  }
21583
+ function buildAntigravityDoctorChecks(snapshot) {
21584
+ const checks = [];
21585
+ checks.push({
21586
+ name: "antigravity credential",
21587
+ ok: snapshot.accountCount > 0 && snapshot.hasAccessToken,
21588
+ 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"}`
21589
+ });
21590
+ const expiresAtMs = snapshot.expiresAt ? Date.parse(snapshot.expiresAt) : 0;
21591
+ const expired = snapshot.expired || expiresAtMs > 0 && Date.now() >= expiresAtMs;
21592
+ const expiringSoon = expiresAtMs > 0 && Date.now() >= expiresAtMs - 10 * 6e4;
21593
+ checks.push({
21594
+ name: "token freshness",
21595
+ ok: !expired,
21596
+ warn: !expired && expiringSoon,
21597
+ 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)"
21598
+ });
21599
+ return checks;
21600
+ }
21601
+ function hasFreshAntigravityQuota(snapshot, now = Date.now()) {
21602
+ if (!snapshot || snapshot.lastErrorCode) return false;
21603
+ if (snapshot.expiresAt && !(Date.parse(snapshot.expiresAt) > now)) return false;
21604
+ return snapshot.windows.some(
21605
+ (window) => window.state === "fresh" && (!window.resetsAt || Date.parse(window.resetsAt) > now) && (window.disabled === true || typeof window.usedPercent === "number" && Number.isFinite(window.usedPercent))
21606
+ );
21607
+ }
21608
+ function buildAntigravityLiveChecks(result) {
21609
+ return [
21610
+ {
21611
+ name: "token refresh (--live)",
21612
+ ok: result.refreshOk,
21613
+ detail: result.refreshOk ? "the active account refreshed successfully" : "refresh failed (see the daemon log)"
21614
+ },
21615
+ {
21616
+ name: "quota collection (--live)",
21617
+ ok: result.quotaOk,
21618
+ detail: result.quotaOk ? "quotaSummary windows collected" : result.detail
21619
+ }
21620
+ ];
21621
+ }
20835
21622
  function buildImagesDoctorChecks(snapshot) {
20836
21623
  const enabled = snapshot.config.enabled;
20837
- const accountOk = !enabled || snapshot.account.usable;
21624
+ const routed = snapshot.config.routedProviders ?? ["codex-subscription"];
21625
+ const codexRouted = routed.includes("codex-subscription");
21626
+ const antigravityRouted = routed.includes("antigravity-subscription");
21627
+ const antigravity = snapshot.antigravityAccount ?? { present: false, usable: false, reason: "missing" };
21628
+ const accountOk = !enabled || !codexRouted || snapshot.account.usable;
21629
+ const antigravityOk = !enabled || !antigravityRouted || antigravity.usable;
20838
21630
  const evidenceOk = !enabled || snapshot.evidence.valid && snapshot.evidence.freshEntries > 0;
20839
21631
  return [
20840
21632
  {
20841
21633
  name: "normalized Images config",
20842
21634
  ok: snapshot.config.valid,
20843
- detail: snapshot.config.valid ? `enabled=${enabled}, provider=${snapshot.config.provider}, model=${snapshot.config.model}` : `invalid normalized configuration (${snapshot.config.errorCount} issue(s))`
21635
+ detail: snapshot.config.valid ? `enabled=${enabled}, providers=${routed.join("+")}, default=${snapshot.config.model} (${snapshot.config.provider})` : `invalid normalized configuration (${snapshot.config.errorCount} issue(s))`
20844
21636
  },
20845
21637
  {
20846
21638
  name: "private roots",
@@ -20861,8 +21653,14 @@ function buildImagesDoctorChecks(snapshot) {
20861
21653
  {
20862
21654
  name: "Codex account",
20863
21655
  ok: accountOk,
20864
- warn: !snapshot.account.usable,
20865
- detail: snapshot.account.usable ? "eligible local credential is present" : `${snapshot.account.reason}; Images live verification is unavailable`
21656
+ warn: enabled && codexRouted && !snapshot.account.usable,
21657
+ 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`
21658
+ },
21659
+ {
21660
+ name: "Antigravity account",
21661
+ ok: antigravityOk,
21662
+ warn: enabled && antigravityRouted && !antigravity.usable,
21663
+ 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`
20866
21664
  },
20867
21665
  {
20868
21666
  name: "cached capability evidence",
@@ -20877,6 +21675,12 @@ async function runImagesLiveDoctor(config, doctor, signal = new AbortController(
20877
21675
  " [\u26A0] live Images verification may consume subscription quota; one minimal low-quality PNG request will be sent"
20878
21676
  );
20879
21677
  const result = await doctor.verifyLive(config.images ?? import_outbound_api12.DEFAULT_IMAGES_SERVER_CONFIG, signal);
21678
+ const antigravityRouted = Object.values(config.images?.models ?? {}).includes("antigravity-subscription");
21679
+ if (antigravityRouted) {
21680
+ console.info(
21681
+ " [i] live verification covers the Codex wire only; the Antigravity provider has no independent verifier in v1 (its first real request bootstraps)"
21682
+ );
21683
+ }
20880
21684
  if (!result.ok) {
20881
21685
  console.info(` [\u2717] live Images verification: ${result.code}`);
20882
21686
  return false;
@@ -21011,14 +21815,49 @@ async function runLiveProbe(url, key, fetchImpl = fetch) {
21011
21815
  status: res.status,
21012
21816
  estimateHeader: res.headers.get("x-omnicross-count-estimate")
21013
21817
  };
21014
- } catch (err8) {
21818
+ } catch (err9) {
21015
21819
  return {
21016
21820
  status: null,
21017
21821
  estimateHeader: null,
21018
- error: err8 instanceof Error ? err8.message : String(err8)
21822
+ error: err9 instanceof Error ? err9.message : String(err9)
21019
21823
  };
21020
21824
  }
21021
21825
  }
21826
+ async function runAntigravityDoctor(daemon, live) {
21827
+ const config = await daemon.credentialStore.getFullConfig();
21828
+ const accounts = config.antigravityAccounts ?? [];
21829
+ const activeId = config.activeAntigravityAccountId ?? accounts[0]?.id;
21830
+ const active = accounts.find((account) => account.id === activeId);
21831
+ const snapshot = {
21832
+ accountCount: accounts.length,
21833
+ ...active?.tokens.email ? { activeEmail: active.tokens.email } : {},
21834
+ hasAccessToken: Boolean(active?.tokens.accessToken),
21835
+ expired: active?.tokens.status === "expired",
21836
+ ...active?.tokens.expiresAt ? { expiresAt: active.tokens.expiresAt } : {}
21837
+ };
21838
+ const checks = buildAntigravityDoctorChecks(snapshot);
21839
+ if (live && active) {
21840
+ const refreshOk = await daemon.credentialStore.refreshAntigravityToken();
21841
+ let quotaOk = false;
21842
+ let detail = "quotaSummary collection produced no usable windows";
21843
+ try {
21844
+ const snapshots = await daemon.accountAllowanceService.refreshAntigravity(active.id);
21845
+ quotaOk = hasFreshAntigravityQuota(snapshots.find((entry) => entry.accountId === active.id));
21846
+ if (!quotaOk) detail = snapshots[0]?.lastErrorCode ?? detail;
21847
+ } catch (error) {
21848
+ detail = error instanceof Error ? error.message : String(error);
21849
+ }
21850
+ checks.push(...buildAntigravityLiveChecks({ refreshOk, quotaOk, detail }));
21851
+ }
21852
+ console.info("omnicross doctor antigravity \u2014 subscription credential health");
21853
+ let hardFailure = false;
21854
+ for (const check of checks) {
21855
+ const mark = check.ok ? check.warn ? "\u26A0" : "\u2713" : "\u2717";
21856
+ if (!check.ok) hardFailure = true;
21857
+ console.info(` [${mark}] ${check.name}: ${check.detail}`);
21858
+ }
21859
+ return hardFailure ? 1 : 0;
21860
+ }
21022
21861
  async function runDoctor(argv, fetchImpl = fetch) {
21023
21862
  const { values, positionals } = (0, import_node_util2.parseArgs)({
21024
21863
  args: argv,
@@ -21032,8 +21871,8 @@ async function runDoctor(argv, fetchImpl = fetch) {
21032
21871
  allowPositionals: true
21033
21872
  });
21034
21873
  const subject = positionals[0] ?? "claude";
21035
- if (subject !== "claude" && subject !== "images" && subject !== "search") {
21036
- throw new Error(`doctor: unknown subject '${subject}' (supported: 'claude', 'images', 'search')`);
21874
+ if (subject !== "claude" && subject !== "images" && subject !== "search" && subject !== "antigravity") {
21875
+ throw new Error(`doctor: unknown subject '${subject}' (supported: 'claude', 'images', 'search', 'antigravity')`);
21037
21876
  }
21038
21877
  const configPath = values.config;
21039
21878
  if (!configPath) {
@@ -21056,6 +21895,9 @@ async function runDoctor(argv, fetchImpl = fetch) {
21056
21895
  runtime: daemon.searchRuntime
21057
21896
  });
21058
21897
  }
21898
+ if (subject === "antigravity") {
21899
+ return await runAntigravityDoctor(daemon, values.live === true);
21900
+ }
21059
21901
  const checks = subject === "images" ? buildImagesDoctorChecks(await daemon.imageDoctor.inspectLocal(
21060
21902
  serverConfig.images ?? import_outbound_api12.DEFAULT_IMAGES_SERVER_CONFIG
21061
21903
  )) : buildClaudeDoctorChecks(serverConfig);
@@ -21422,9 +22264,9 @@ async function runLaunch(argv, deps) {
21422
22264
  await daemon.llmConfig.ready();
21423
22265
  await daemon.migrateUsageStore();
21424
22266
  await daemon.providerProxy.start();
21425
- } catch (err8) {
22267
+ } catch (err9) {
21426
22268
  await shutdownLaunchDaemon(daemon);
21427
- throw err8;
22269
+ throw err9;
21428
22270
  }
21429
22271
  let launch;
21430
22272
  try {
@@ -21432,9 +22274,9 @@ async function runLaunch(argv, deps) {
21432
22274
  providerId: values.provider,
21433
22275
  model: values.model
21434
22276
  });
21435
- } catch (err8) {
22277
+ } catch (err9) {
21436
22278
  await shutdownLaunchDaemon(daemon);
21437
- throw err8;
22279
+ throw err9;
21438
22280
  }
21439
22281
  try {
21440
22282
  const plan = buildCliSpawnPlan({
@@ -21539,9 +22381,9 @@ function spawnCliInherit(plan) {
21539
22381
  process.removeListener("SIGINT", onSignal);
21540
22382
  process.removeListener("SIGTERM", onSignal);
21541
22383
  };
21542
- child.on("error", (err8) => {
22384
+ child.on("error", (err9) => {
21543
22385
  detach();
21544
- if (err8.code === "ENOENT") {
22386
+ if (err9.code === "ENOENT") {
21545
22387
  reject(
21546
22388
  new Error(
21547
22389
  `launch: "${plan.command}" not found on PATH \u2014 install the CLI first.`
@@ -21549,7 +22391,7 @@ function spawnCliInherit(plan) {
21549
22391
  );
21550
22392
  return;
21551
22393
  }
21552
- reject(err8);
22394
+ reject(err9);
21553
22395
  });
21554
22396
  child.on("exit", (code, signal) => {
21555
22397
  detach();
@@ -21562,9 +22404,10 @@ function spawnCliInherit(plan) {
21562
22404
  var import_node_child_process3 = require("child_process");
21563
22405
  var import_node_readline2 = require("readline");
21564
22406
  var import_node_util7 = require("util");
21565
- var import_upstreamFetch17 = require("@omnicross/core/pipeline/upstreamFetch");
21566
- var import_subscriptions13 = require("@omnicross/subscriptions");
21567
- var PROVIDERS2 = ["claude", "codex", "gemini", "kimi", "grok", "copilot"];
22407
+ var import_GeminiCodeAssistProjectResolver7 = require("@omnicross/core/auth/GeminiCodeAssistProjectResolver");
22408
+ var import_upstreamFetch19 = require("@omnicross/core/pipeline/upstreamFetch");
22409
+ var import_subscriptions14 = require("@omnicross/subscriptions");
22410
+ var PROVIDERS2 = ["claude", "codex", "gemini", "kimi", "grok", "copilot", "antigravity"];
21568
22411
  async function runLogin(argv, deps) {
21569
22412
  const { values, positionals } = (0, import_node_util7.parseArgs)({
21570
22413
  args: argv,
@@ -21591,11 +22434,11 @@ async function runLogin(argv, deps) {
21591
22434
  if (values.enterprise !== void 0 && provider !== "copilot") {
21592
22435
  throw new Error("login: --enterprise is only supported for the copilot provider");
21593
22436
  }
21594
- const enterpriseDomain = values.enterprise !== void 0 ? import_subscriptions13.copilotOAuth.normalizeCopilotEnterpriseDomain(values.enterprise) : void 0;
22437
+ const enterpriseDomain = values.enterprise !== void 0 ? import_subscriptions14.copilotOAuth.normalizeCopilotEnterpriseDomain(values.enterprise) : void 0;
21595
22438
  const resolved = {
21596
22439
  openBrowser: deps?.openBrowser ?? openBrowser,
21597
22440
  promptPaste: deps?.promptPaste ?? promptPaste,
21598
- awaitLoopback: deps?.awaitLoopback ?? ((state) => awaitLoopbackCode(state)),
22441
+ awaitLoopback: deps?.awaitLoopback ?? ((state, timeoutMs, signal, binding) => awaitLoopbackCode(state, timeoutMs, signal, binding)),
21599
22442
  awaitKimiDevice: deps?.awaitKimiDevice ?? ((fetchImpl) => runKimiDeviceFlow(fetchImpl, resolvedOpenBrowser)),
21600
22443
  awaitGrokDevice: deps?.awaitGrokDevice ?? ((fetchImpl) => runGrokDeviceFlow(fetchImpl, resolvedOpenBrowser)),
21601
22444
  awaitCopilotDevice: deps?.awaitCopilotDevice ?? ((fetchImpl, enterpriseUrl) => runCopilotDeviceFlow(fetchImpl, resolvedOpenBrowser, enterpriseUrl)),
@@ -21604,10 +22447,10 @@ async function runLogin(argv, deps) {
21604
22447
  const resolvedOpenBrowser = resolved.openBrowser;
21605
22448
  const box = resolveSecretBox(values["master-key-file"]);
21606
22449
  setSecretBox(box);
21607
- (0, import_upstreamFetch17.setUpstreamProxyResolver)(createUpstreamProxyResolver());
22450
+ (0, import_upstreamFetch19.setUpstreamProxyResolver)(createUpstreamProxyResolver());
21608
22451
  try {
21609
22452
  const tokensPath = defaultTokensPath(values.config);
21610
- const exchangeFetch = resolved.tokensFetch ?? ((url, init) => (0, import_upstreamFetch17.fetchUpstream)(url, init, { providerId: provider, redactBodies: true }));
22453
+ const exchangeFetch = resolved.tokensFetch ?? ((url, init) => (0, import_upstreamFetch19.fetchUpstream)(url, init, { providerId: provider, redactBodies: true }));
21611
22454
  const store = new JsonSubscriptionCredentialStore(tokensPath, box, exchangeFetch);
21612
22455
  const expiresAt = await runProviderLogin(
21613
22456
  provider,
@@ -21621,7 +22464,7 @@ async function runLogin(argv, deps) {
21621
22464
  console.info(` token: [stored, encrypted] expiresAt: ${expiresAt ?? "n/a"}`);
21622
22465
  } finally {
21623
22466
  setSecretBox(null);
21624
- (0, import_upstreamFetch17.setUpstreamProxyResolver)(null);
22467
+ (0, import_upstreamFetch19.setUpstreamProxyResolver)(null);
21625
22468
  }
21626
22469
  }
21627
22470
  async function runProviderLogin(provider, store, deps, exchangeFetch, label, enterpriseUrl) {
@@ -21630,13 +22473,14 @@ async function runProviderLogin(provider, store, deps, exchangeFetch, label, ent
21630
22473
  if (provider === "kimi") return loginKimi(store, deps, exchangeFetch, label);
21631
22474
  if (provider === "grok") return loginGrok(store, deps, exchangeFetch, label);
21632
22475
  if (provider === "copilot") return loginCopilot(store, deps, exchangeFetch, label, enterpriseUrl);
22476
+ if (provider === "antigravity") return loginAntigravity(store, deps, exchangeFetch, label);
21633
22477
  return loginGemini(store, deps, exchangeFetch, label);
21634
22478
  }
21635
22479
  async function loginCodex(store, deps, exchangeFetch, label) {
21636
- const { authUrl, codeVerifier, state } = import_subscriptions13.codexOAuth.generateAuthParams();
22480
+ const { authUrl, codeVerifier, state } = import_subscriptions14.codexOAuth.generateAuthParams();
21637
22481
  await presentUrl(authUrl, deps);
21638
22482
  const code = await deps.awaitLoopback(state);
21639
- const result = await import_subscriptions13.codexOAuth.exchangeCodeForTokens(
22483
+ const result = await import_subscriptions14.codexOAuth.exchangeCodeForTokens(
21640
22484
  { authorizationCode: code, codeVerifier, state },
21641
22485
  exchangeFetch
21642
22486
  );
@@ -21655,7 +22499,7 @@ async function loginCodex(store, deps, exchangeFetch, label) {
21655
22499
  return expiresAt;
21656
22500
  }
21657
22501
  async function loginClaude(store, deps, exchangeFetch, label) {
21658
- const { authUrl, codeVerifier, state } = import_subscriptions13.claudeOAuth.generateAuthParams();
22502
+ const { authUrl, codeVerifier, state } = import_subscriptions14.claudeOAuth.generateAuthParams();
21659
22503
  await presentUrl(authUrl, deps);
21660
22504
  const pasted = (await deps.promptPaste("Paste the authorization code (code#state): ")).trim();
21661
22505
  const [code, pastedState] = pasted.split("#");
@@ -21663,7 +22507,7 @@ async function loginClaude(store, deps, exchangeFetch, label) {
21663
22507
  if (pastedState && pastedState !== state) {
21664
22508
  throw new Error("login: pasted state did not match (possible CSRF) \u2014 aborting");
21665
22509
  }
21666
- const result = await import_subscriptions13.claudeOAuth.exchangeCodeForTokens(
22510
+ const result = await import_subscriptions14.claudeOAuth.exchangeCodeForTokens(
21667
22511
  { authorizationCode: code, codeVerifier, state },
21668
22512
  exchangeFetch
21669
22513
  );
@@ -21682,11 +22526,11 @@ async function loginClaude(store, deps, exchangeFetch, label) {
21682
22526
  return expiresAt;
21683
22527
  }
21684
22528
  async function loginGemini(store, deps, exchangeFetch, label) {
21685
- const { authUrl, codeVerifier } = import_subscriptions13.geminiOAuth.generateAuthParams();
22529
+ const { authUrl, codeVerifier } = import_subscriptions14.geminiOAuth.generateAuthParams();
21686
22530
  await presentUrl(authUrl, deps);
21687
22531
  const code = (await deps.promptPaste("Paste the authorization code: ")).trim();
21688
22532
  if (!code) throw new Error("login: no authorization code was pasted");
21689
- const result = await import_subscriptions13.geminiOAuth.exchangeCodeForTokens(code, codeVerifier, exchangeFetch);
22533
+ const result = await import_subscriptions14.geminiOAuth.exchangeCodeForTokens(code, codeVerifier, exchangeFetch);
21690
22534
  const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
21691
22535
  const block = {
21692
22536
  authMethod: "oauth",
@@ -21701,9 +22545,9 @@ async function loginGemini(store, deps, exchangeFetch, label) {
21701
22545
  return expiresAt;
21702
22546
  }
21703
22547
  async function runKimiDeviceFlow(exchangeFetch, openBrowserFn) {
21704
- const deviceId = import_subscriptions13.kimiOAuth.generateKimiDeviceId();
21705
- const fingerprint = import_subscriptions13.kimiOAuth.kimiFingerprintHeaders(deviceId);
21706
- const authorization = await import_subscriptions13.kimiOAuth.requestDeviceAuthorization(exchangeFetch, fingerprint);
22548
+ const deviceId = import_subscriptions14.kimiOAuth.generateKimiDeviceId();
22549
+ const fingerprint = import_subscriptions14.kimiOAuth.kimiFingerprintHeaders(deviceId);
22550
+ const authorization = await import_subscriptions14.kimiOAuth.requestDeviceAuthorization(exchangeFetch, fingerprint);
21707
22551
  const url = authorization.verificationUriComplete ?? authorization.verificationUri;
21708
22552
  console.info("Open this URL in your browser and approve the request:");
21709
22553
  console.info(` ${url}`);
@@ -21711,14 +22555,14 @@ async function runKimiDeviceFlow(exchangeFetch, openBrowserFn) {
21711
22555
  console.info(` Then enter this code: ${authorization.userCode}`);
21712
22556
  }
21713
22557
  await openBrowserFn(url).catch(() => false);
21714
- const result = await import_subscriptions13.kimiOAuth.awaitDeviceToken(authorization, exchangeFetch, {
22558
+ const result = await import_subscriptions14.kimiOAuth.awaitDeviceToken(authorization, exchangeFetch, {
21715
22559
  fingerprint,
21716
22560
  onPending: () => process.stdout.write(".")
21717
22561
  });
21718
22562
  console.info("");
21719
22563
  return {
21720
22564
  ...result,
21721
- accountId: import_subscriptions13.kimiOAuth.kimiAccountIdFromAccessToken(result.accessToken),
22565
+ accountId: import_subscriptions14.kimiOAuth.kimiAccountIdFromAccessToken(result.accessToken),
21722
22566
  deviceId
21723
22567
  };
21724
22568
  }
@@ -21740,8 +22584,8 @@ async function loginKimi(store, deps, exchangeFetch, label) {
21740
22584
  return expiresAt;
21741
22585
  }
21742
22586
  async function runGrokDeviceFlow(exchangeFetch, openBrowserFn) {
21743
- const tokenEndpoint = await import_subscriptions13.grokOAuth.resolveGrokTokenEndpoint(exchangeFetch);
21744
- const authorization = await import_subscriptions13.grokOAuth.requestGrokDeviceAuthorization(exchangeFetch);
22587
+ const tokenEndpoint = await import_subscriptions14.grokOAuth.resolveGrokTokenEndpoint(exchangeFetch);
22588
+ const authorization = await import_subscriptions14.grokOAuth.requestGrokDeviceAuthorization(exchangeFetch);
21745
22589
  const url = authorization.verificationUriComplete ?? authorization.verificationUri;
21746
22590
  console.info("Open this URL in your browser and approve the request:");
21747
22591
  console.info(` ${url}`);
@@ -21749,13 +22593,13 @@ async function runGrokDeviceFlow(exchangeFetch, openBrowserFn) {
21749
22593
  console.info(` Then enter this code: ${authorization.userCode}`);
21750
22594
  }
21751
22595
  await openBrowserFn(url).catch(() => false);
21752
- const result = await import_subscriptions13.grokOAuth.awaitGrokDeviceToken(authorization, tokenEndpoint, exchangeFetch, {
22596
+ const result = await import_subscriptions14.grokOAuth.awaitGrokDeviceToken(authorization, tokenEndpoint, exchangeFetch, {
21753
22597
  onPending: () => process.stdout.write(".")
21754
22598
  });
21755
22599
  console.info("");
21756
22600
  return {
21757
22601
  ...result,
21758
- accountId: import_subscriptions13.grokOAuth.grokAccountIdFromAccessToken(result.accessToken)
22602
+ accountId: import_subscriptions14.grokOAuth.grokAccountIdFromAccessToken(result.accessToken)
21759
22603
  };
21760
22604
  }
21761
22605
  async function loginGrok(store, deps, exchangeFetch, label) {
@@ -21776,28 +22620,28 @@ async function loginGrok(store, deps, exchangeFetch, label) {
21776
22620
  }
21777
22621
  async function runCopilotDeviceFlow(exchangeFetch, openBrowserFn, enterpriseUrl) {
21778
22622
  if (enterpriseUrl) console.info(`Using GitHub Enterprise host: ${enterpriseUrl}`);
21779
- const authorization = await import_subscriptions13.copilotOAuth.requestCopilotDeviceAuthorization(exchangeFetch, enterpriseUrl);
22623
+ const authorization = await import_subscriptions14.copilotOAuth.requestCopilotDeviceAuthorization(exchangeFetch, enterpriseUrl);
21780
22624
  const url = authorization.verificationUri;
21781
22625
  console.info("Open this URL in your browser and approve the request:");
21782
22626
  console.info(` ${url}`);
21783
22627
  console.info(` Then enter this code: ${authorization.userCode}`);
21784
22628
  await openBrowserFn(url).catch(() => false);
21785
- const result = await import_subscriptions13.copilotOAuth.awaitCopilotDeviceToken(authorization, exchangeFetch, {
22629
+ const result = await import_subscriptions14.copilotOAuth.awaitCopilotDeviceToken(authorization, exchangeFetch, {
21786
22630
  onPending: () => process.stdout.write("."),
21787
22631
  ...enterpriseUrl ? { enterpriseUrl } : {}
21788
22632
  });
21789
22633
  console.info("");
21790
- const identity = await import_subscriptions13.copilotOAuth.fetchCopilotIdentity(result.accessToken, exchangeFetch, enterpriseUrl);
21791
- const apiEndpoint = await import_subscriptions13.copilotOAuth.discoverCopilotApiEndpoint(result.accessToken, exchangeFetch, enterpriseUrl);
22634
+ const identity = await import_subscriptions14.copilotOAuth.fetchCopilotIdentity(result.accessToken, exchangeFetch, enterpriseUrl);
22635
+ const apiEndpoint = await import_subscriptions14.copilotOAuth.discoverCopilotApiEndpoint(result.accessToken, exchangeFetch, enterpriseUrl);
21792
22636
  console.info("Enabling Copilot models (policy)...");
21793
- await import_subscriptions13.copilotOAuth.enableAllCopilotModels(
22637
+ await import_subscriptions14.copilotOAuth.enableAllCopilotModels(
21794
22638
  result.accessToken,
21795
22639
  { apiEndpoint, ...enterpriseUrl ? { enterpriseUrl } : {} },
21796
22640
  exchangeFetch
21797
22641
  );
21798
22642
  return {
21799
22643
  accessToken: result.accessToken,
21800
- expiresIn: Math.floor(import_subscriptions13.copilotOAuth.COPILOT_FAR_FUTURE_MS / 1e3),
22644
+ expiresIn: Math.floor(import_subscriptions14.copilotOAuth.COPILOT_FAR_FUTURE_MS / 1e3),
21801
22645
  ...identity,
21802
22646
  ...apiEndpoint ? { apiEndpoint } : {}
21803
22647
  };
@@ -21823,6 +22667,70 @@ async function loginCopilot(store, deps, exchangeFetch, label, enterpriseUrl) {
21823
22667
  logMasked("copilot", result.accessToken);
21824
22668
  return expiresAt;
21825
22669
  }
22670
+ async function loginAntigravity(store, deps, exchangeFetch, label) {
22671
+ const { authUrl, state } = import_subscriptions14.antigravityOAuth.generateAuthParams();
22672
+ await presentUrl(authUrl, deps);
22673
+ const code = await captureAntigravityCode(deps, state);
22674
+ const result = await import_subscriptions14.antigravityOAuth.exchangeCodeForTokens(code, exchangeFetch);
22675
+ const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
22676
+ const email = await import_subscriptions14.antigravityOAuth.fetchUserEmail(result.accessToken, exchangeFetch);
22677
+ console.info("Resolving the Antigravity Cloud Code Assist project...");
22678
+ const projectId = await (0, import_GeminiCodeAssistProjectResolver7.getAntigravityProjectResolver)().resolveProject(result.accessToken);
22679
+ const block = {
22680
+ authMethod: "oauth",
22681
+ status: "authorized",
22682
+ accessToken: result.accessToken,
22683
+ refreshToken: result.refreshToken,
22684
+ expiresAt,
22685
+ ...email ? { email } : {},
22686
+ ...projectId ? { projectId } : {},
22687
+ lastRefreshedAt: (/* @__PURE__ */ new Date()).toISOString()
22688
+ };
22689
+ await store.appendProviderAccount("antigravity", block, label);
22690
+ logMasked("antigravity", result.accessToken);
22691
+ return expiresAt;
22692
+ }
22693
+ async function captureAntigravityCode(deps, state) {
22694
+ try {
22695
+ return await deps.awaitLoopback(state, void 0, void 0, {
22696
+ port: 51121,
22697
+ path: "/oauth-callback",
22698
+ label: "antigravity"
22699
+ });
22700
+ } catch (loopbackError) {
22701
+ const reason = loopbackError instanceof Error ? loopbackError.message : String(loopbackError);
22702
+ console.warn(`(loopback capture unavailable: ${reason})`);
22703
+ console.info(
22704
+ "Paste fallback: after authorizing, copy the failing redirect URL (or just its code parameter) here."
22705
+ );
22706
+ const pasted = (await deps.promptPaste("Paste the authorization code (or redirect URL): ")).trim();
22707
+ if (!pasted) throw new Error("login: no authorization code was pasted");
22708
+ const { code, state: pastedState } = parseAntigravityPaste(pasted);
22709
+ if (!code) throw new Error("login: the pasted value carried no authorization code");
22710
+ if (pastedState && pastedState !== state) {
22711
+ throw new Error("login: pasted state did not match (possible CSRF) \u2014 aborting");
22712
+ }
22713
+ return code;
22714
+ }
22715
+ }
22716
+ function parseAntigravityPaste(pasted) {
22717
+ if (pasted.includes("://")) {
22718
+ try {
22719
+ const url = new URL(pasted);
22720
+ const code = url.searchParams.get("code") ?? "";
22721
+ const state = url.searchParams.get("state") ?? void 0;
22722
+ return { code, ...state ? { state } : {} };
22723
+ } catch {
22724
+ }
22725
+ }
22726
+ if (/^[?]?code=/.test(pasted)) {
22727
+ const params = new URLSearchParams(pasted.replace(/^\?/, ""));
22728
+ const code = params.get("code") ?? "";
22729
+ const state = params.get("state") ?? void 0;
22730
+ return { code, ...state ? { state } : {} };
22731
+ }
22732
+ return { code: pasted };
22733
+ }
21826
22734
  function isLoginProvider(value) {
21827
22735
  return PROVIDERS2.includes(value);
21828
22736
  }
@@ -22244,7 +23152,11 @@ var TOKEN_FIELDS2 = {
22244
23152
  claude: ["accessToken", "refreshToken"],
22245
23153
  codex: ["accessToken", "refreshToken", "idToken"],
22246
23154
  gemini: ["accessToken", "refreshToken"],
22247
- opencodego: ["apiKey"]
23155
+ opencodego: ["apiKey"],
23156
+ kimi: ["accessToken", "refreshToken"],
23157
+ grok: ["accessToken", "refreshToken"],
23158
+ copilot: ["accessToken", "refreshToken"],
23159
+ antigravity: ["accessToken", "refreshToken"]
22248
23160
  };
22249
23161
  function walkTokens(raw, fn) {
22250
23162
  const next = { ...raw };
@@ -22528,7 +23440,7 @@ async function main() {
22528
23440
  process.exitCode = 1;
22529
23441
  }
22530
23442
  }
22531
- main().catch((err8) => {
22532
- console.error(err8 instanceof Error ? err8.message : String(err8));
23443
+ main().catch((err9) => {
23444
+ console.error(err9 instanceof Error ? err9.message : String(err9));
22533
23445
  process.exitCode = 1;
22534
23446
  });