@yansigit/opencodex 2.33.0 → 2.35.0
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/README.md +3 -3
- package/gui/dist/assets/index-BjCaHxdz.js +112 -0
- package/gui/dist/assets/index-DLkXOXLC.css +1 -0
- package/gui/dist/index.html +2 -2
- package/package.json +1 -1
- package/src/adapters/anthropic.ts +79 -2
- package/src/adapters/command-code.ts +141 -23
- package/src/adapters/cursor/call-id.ts +44 -0
- package/src/adapters/cursor/checkpoint-store.ts +15 -10
- package/src/adapters/cursor/discovery.ts +60 -2
- package/src/adapters/cursor/effort-map.ts +79 -1
- package/src/adapters/cursor/envelope-echo.ts +162 -0
- package/src/adapters/cursor/live-models.ts +7 -2
- package/src/adapters/cursor/live-transport.ts +17 -1
- package/src/adapters/cursor/message-mapper.ts +4 -1
- package/src/adapters/cursor/native-exec-fs.ts +13 -12
- package/src/adapters/cursor/native-exec-network.ts +3 -5
- package/src/adapters/cursor/native-exec-policy.ts +47 -0
- package/src/adapters/cursor/native-exec-shell.ts +116 -31
- package/src/adapters/cursor/native-exec.ts +38 -10
- package/src/adapters/cursor/protobuf-events.ts +28 -2
- package/src/adapters/cursor/protobuf-request.ts +93 -41
- package/src/adapters/cursor/request-builder.ts +39 -10
- package/src/adapters/cursor/tool-definitions.ts +27 -3
- package/src/adapters/cursor/tool-result-normalize.ts +51 -6
- package/src/adapters/cursor/types.ts +23 -4
- package/src/adapters/cursor.ts +170 -29
- package/src/adapters/google-aistudio-parser.ts +49 -0
- package/src/adapters/google-antigravity-replay.ts +105 -25
- package/src/adapters/google-antigravity-wire.ts +5 -0
- package/src/adapters/google-errors.ts +41 -12
- package/src/adapters/google-http.ts +12 -11
- package/src/adapters/google.ts +219 -36
- package/src/adapters/image.ts +1 -1
- package/src/adapters/kiro-constants.ts +15 -0
- package/src/adapters/kiro-tools.ts +43 -15
- package/src/adapters/kiro.ts +54 -9
- package/src/adapters/openai-chat.ts +286 -242
- package/src/adapters/openai-responses.ts +335 -24
- package/src/adapters/run-turn-queue.ts +36 -1
- package/src/adapters/tool-catalog-nudge.ts +2 -2
- package/src/adapters/xai-tool-schema.ts +436 -0
- package/src/bridge.ts +67 -26
- package/src/chat/inbound.ts +29 -1
- package/src/chat/outbound.ts +15 -7
- package/src/claude/agents-inject.ts +8 -1
- package/src/claude/outbound.ts +10 -8
- package/src/cli/account-api.ts +27 -7
- package/src/cli/account-extended.ts +10 -3
- package/src/cli/account.ts +29 -5
- package/src/cli/alias.ts +66 -0
- package/src/cli/claude.ts +26 -1
- package/src/cli/dispatch.ts +13 -1
- package/src/cli/help.ts +1 -0
- package/src/cli/index.ts +6 -1
- package/src/cli/init.ts +1 -0
- package/src/cli/models-runtime.ts +95 -0
- package/src/cli/models.ts +13 -7
- package/src/cli/provider-runtime.ts +16 -2
- package/src/cli/registry.ts +6 -1
- package/src/cli/telemetry-commands.ts +25 -0
- package/src/cli/v2.ts +34 -10
- package/src/codex/account-pause.ts +2 -1
- package/src/codex/account-priority.ts +3 -2
- package/src/codex/app-server-processes.ts +80 -6
- package/src/codex/auth-api.ts +48 -8
- package/src/codex/auth-context.ts +21 -18
- package/src/codex/catalog/aggregation.ts +6 -0
- package/src/codex/catalog/model-metadata.ts +13 -1
- package/src/codex/catalog/native-models.ts +5 -2
- package/src/codex/catalog/parsing.ts +16 -0
- package/src/codex/catalog/provider-fetch.ts +20 -3
- package/src/codex/catalog/sync.ts +127 -2
- package/src/codex/catalog.ts +1 -1
- package/src/codex/codex-write-lock.ts +3 -1
- package/src/codex/convergence-types.ts +1 -1
- package/src/codex/convergence.ts +22 -2
- package/src/codex/desired-state.ts +2 -2
- package/src/codex/desktop-app-restart.ts +18 -5
- package/src/codex/inject-coordination.ts +83 -0
- package/src/codex/inject.ts +14 -1
- package/src/codex/log-guard/inspect.ts +22 -4
- package/src/codex/model-entitlements.ts +9 -2
- package/src/codex/prompt-layers.ts +371 -25
- package/src/codex/prompt-text-probe.ts +238 -0
- package/src/codex/quota.ts +123 -18
- package/src/codex/routing.ts +9 -0
- package/src/codex/subagent-model-fallback.ts +198 -27
- package/src/codex/transition-state.ts +107 -8
- package/src/combos/types.ts +10 -0
- package/src/compatibility/openai-responses.ts +33 -1
- package/src/config/autonomous-remediation.ts +21 -0
- package/src/config/provider-validation.ts +14 -0
- package/src/config/rebase-provenance.ts +68 -0
- package/src/config.ts +191 -17
- package/src/generated/compatibility-version.json +279 -159
- package/src/generated/model-metadata.ts +3 -0
- package/src/images/loop.ts +5 -4
- package/src/lab/conformance/fixtures/protocol-v1-cases.json +1 -1
- package/src/lab/fabric/producer-child.ts +1 -1
- package/src/lib/config-ownership.ts +20 -0
- package/src/lib/errors.ts +11 -2
- package/src/lib/package-tree-integrity.ts +101 -0
- package/src/oauth/aistudio-credentials.ts +65 -0
- package/src/oauth/aistudio-native-daemon.ts +116 -0
- package/src/oauth/aistudio-session-sync.ts +95 -0
- package/src/oauth/generic-account-failover.ts +231 -0
- package/src/oauth/google-aistudio-auth.ts +98 -0
- package/src/oauth/index.ts +57 -5
- package/src/oauth/key-providers.ts +18 -1
- package/src/oauth/kiro.ts +45 -0
- package/src/oauth/login-cli.ts +65 -1
- package/src/oauth/types.ts +15 -0
- package/src/providers/codex-capacity.ts +5 -2
- package/src/providers/command-code-efforts.ts +38 -6
- package/src/providers/context-cap.ts +4 -3
- package/src/providers/default-aliases.ts +65 -0
- package/src/providers/derive.ts +29 -1
- package/src/providers/fastwire.ts +7 -1
- package/src/providers/model-presets.ts +119 -0
- package/src/providers/new-model-policy.ts +146 -0
- package/src/providers/provider-id-rewrite.ts +2 -1
- package/src/providers/quota.ts +157 -46
- package/src/providers/registry.ts +184 -71
- package/src/providers/slug-codec.ts +52 -0
- package/src/responses/code-mode-helper-compat.ts +50 -0
- package/src/responses/custom-tool-compat.ts +34 -10
- package/src/responses/parser.ts +4 -0
- package/src/responses/schema.ts +5 -1
- package/src/responses/thought-signature-replay.ts +17 -0
- package/src/router.ts +43 -2
- package/src/routing/account-pool/cooldown.ts +8 -0
- package/src/routing/account-pool/index.ts +1 -0
- package/src/routing/analytics.ts +1 -0
- package/src/routing/quota.ts +10 -0
- package/src/server/auth-cors.ts +24 -0
- package/src/server/chat-completions.ts +26 -16
- package/src/server/chat-native-sse.ts +3 -3
- package/src/server/chat-native.ts +30 -11
- package/src/server/claude-messages.ts +1 -1
- package/src/server/effort-policy.ts +16 -0
- package/src/server/index.ts +180 -14
- package/src/server/lifecycle.ts +52 -1
- package/src/server/management/agent-settings-routes.ts +31 -15
- package/src/server/management/codex-prompt-routes.ts +570 -0
- package/src/server/management/combo-routes.ts +2 -1
- package/src/server/management/config-routes.ts +27 -9
- package/src/server/management/context.ts +9 -0
- package/src/server/management/logs-usage-routes.ts +11 -5
- package/src/server/management/model-routes.ts +266 -0
- package/src/server/management/oauth-account-routes.ts +13 -3
- package/src/server/management/provider-routes.ts +137 -3
- package/src/server/management/routing-profile-routes.ts +2 -2
- package/src/server/management-api.ts +2 -0
- package/src/server/port-reclaim.ts +19 -1
- package/src/server/relay-eager.ts +147 -20
- package/src/server/relay.ts +251 -19
- package/src/server/request-log-conversation.ts +33 -0
- package/src/server/request-log.ts +48 -21
- package/src/server/responses/collaboration.ts +42 -5
- package/src/server/responses/combo-stream-preflight.ts +10 -3
- package/src/server/responses/core.ts +575 -140
- package/src/server/responses/empty-completion-guard.ts +35 -0
- package/src/server/responses/fetch-helpers.ts +14 -6
- package/src/server/responses/input-admission.ts +3 -1
- package/src/server/responses/passthrough-error.ts +33 -9
- package/src/server/responses/policy-fallback.ts +1 -1
- package/src/server/responses/responses-field-backfill.ts +105 -13
- package/src/server/responses/ws-upstream.ts +35 -5
- package/src/server/responses-custom-tool-repair.ts +52 -7
- package/src/server/responses-terminal-repair.ts +25 -4
- package/src/server/sse-frame-buffer.ts +31 -4
- package/src/server/ws-bridge.ts +14 -2
- package/src/smoke/fingerprint-cache.ts +133 -0
- package/src/smoke/live-scenarios.ts +33 -0
- package/src/smoke/runner.ts +119 -0
- package/src/telemetry/dispatcher.ts +44 -0
- package/src/telemetry/fingerprint.ts +24 -0
- package/src/telemetry/hook.ts +43 -0
- package/src/telemetry/ledger.ts +54 -0
- package/src/telemetry/types.ts +23 -0
- package/src/types/config.ts +66 -14
- package/src/types/provider.ts +79 -1
- package/src/types/request.ts +18 -10
- package/src/types/tools.ts +30 -11
- package/src/types.ts +1 -0
- package/src/usage/command-code-manifest.ts +116 -0
- package/src/usage/cost.ts +2 -2
- package/src/usage/expected-prices.ts +126 -24
- package/src/usage/log.ts +18 -8
- package/src/usage/summary.ts +34 -12
- package/src/web-search/exa-executor.ts +40 -9
- package/src/web-search/index.ts +16 -8
- package/src/web-search/loop.ts +5 -4
- package/gui/dist/assets/index-DKLr4LTE.js +0 -102
- package/gui/dist/assets/index-DrSQdTRd.css +0 -1
package/src/providers/quota.ts
CHANGED
|
@@ -3,7 +3,9 @@ import {
|
|
|
3
3
|
effectiveCodexAuthAccountId,
|
|
4
4
|
fetchMainAccountInfoSnapshot,
|
|
5
5
|
listCodexAuthAccountsSnapshot,
|
|
6
|
+
withSparkVisibility,
|
|
6
7
|
} from "../codex/auth-api";
|
|
8
|
+
import type { StoredAccountQuota } from "../codex/quota";
|
|
7
9
|
import { isMainAccountIdentityGenerationLive } from "../codex/main-account-cache";
|
|
8
10
|
import { MAIN_CODEX_ACCOUNT_ID } from "../codex/main-account";
|
|
9
11
|
import { codexPlanKey } from "../codex/plan";
|
|
@@ -173,6 +175,27 @@ function quotaSignatureValue(quota: CodexCapacityQuota | null): unknown {
|
|
|
173
175
|
};
|
|
174
176
|
}
|
|
175
177
|
|
|
178
|
+
function providerQuotaFromCodexQuota(
|
|
179
|
+
quota: StoredAccountQuota | Omit<StoredAccountQuota, "updatedAt"> | null | undefined,
|
|
180
|
+
): CodexCapacityQuota | null {
|
|
181
|
+
if (!quota) return null;
|
|
182
|
+
// Every Codex-sourced provider report funnels through here — the pooled path via
|
|
183
|
+
// listCodexAuthAccountsSnapshot and the `direct` path via fetchMainAccountInfoSnapshot, which
|
|
184
|
+
// never touches the Codex Auth DTO. Applying the Spark preference at this one point is what
|
|
185
|
+
// stops the row surviving on /api/provider-quotas after the operator switched it off.
|
|
186
|
+
quota = withSparkVisibility(quota ?? null) ?? quota;
|
|
187
|
+
return {
|
|
188
|
+
...(quota.shortPercent !== undefined ? { fiveHourPercent: quota.shortPercent } : {}),
|
|
189
|
+
...(quota.shortResetAt !== undefined ? { fiveHourResetAt: quota.shortResetAt } : {}),
|
|
190
|
+
...(quota.weeklyPercent !== undefined ? { weeklyPercent: quota.weeklyPercent } : {}),
|
|
191
|
+
...(quota.weeklyResetAt !== undefined ? { weeklyResetAt: quota.weeklyResetAt } : {}),
|
|
192
|
+
...(quota.monthlyPercent !== undefined ? { monthlyPercent: quota.monthlyPercent } : {}),
|
|
193
|
+
...(quota.monthlyResetAt !== undefined ? { monthlyResetAt: quota.monthlyResetAt } : {}),
|
|
194
|
+
...(quota.customWindows !== undefined ? { customWindows: quota.customWindows } : {}),
|
|
195
|
+
updatedAt: "updatedAt" in quota ? quota.updatedAt : Date.now(),
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
|
|
176
199
|
/** Hash only presentation-relevant state; account ids and email addresses never enter the key. */
|
|
177
200
|
function cacheKeyWithAggregationState(
|
|
178
201
|
config: OcxConfig,
|
|
@@ -190,7 +213,7 @@ function cacheKeyWithAggregationState(
|
|
|
190
213
|
plan: codexPlanKey(account.plan) ?? null,
|
|
191
214
|
paused: account.paused,
|
|
192
215
|
needsReauth: account.needsReauth === true,
|
|
193
|
-
quota: quotaSignatureValue(account.quota
|
|
216
|
+
quota: quotaSignatureValue(providerQuotaFromCodexQuota(account.quota)),
|
|
194
217
|
}));
|
|
195
218
|
const canonicalRows = rows.map(row => JSON.stringify(row)).sort();
|
|
196
219
|
const digest = createHash("sha256").update(JSON.stringify(canonicalRows)).digest("hex").slice(0, 24);
|
|
@@ -1110,9 +1133,8 @@ async function fetchChatGptForwardQuota(
|
|
|
1110
1133
|
): Promise<ProviderQuotaReport | null> {
|
|
1111
1134
|
if (providerCodexAccountMode(provider, providerConfig) === "direct") {
|
|
1112
1135
|
const snapshot = await fetchMainAccountInfoSnapshot(forceRefresh);
|
|
1113
|
-
const quota = snapshot.info.quota
|
|
1114
|
-
|
|
1115
|
-
: null;
|
|
1136
|
+
const quota = providerQuotaFromCodexQuota(snapshot.info.quota);
|
|
1137
|
+
if (quota) quota.updatedAt = Date.now();
|
|
1116
1138
|
return quota
|
|
1117
1139
|
? tagNativeMainReport(report(provider, "chatgpt:wham", quota), snapshot.mainIdentityGeneration)
|
|
1118
1140
|
: null;
|
|
@@ -1120,10 +1142,14 @@ async function fetchChatGptForwardQuota(
|
|
|
1120
1142
|
const snapshot = await (prefetchedSnapshot ?? listCodexAuthAccountsSnapshot(config, forceRefresh));
|
|
1121
1143
|
const accounts = snapshot.accounts;
|
|
1122
1144
|
const activeId = effectiveCodexAuthAccountId(config);
|
|
1123
|
-
const capacityAccounts = accounts.map(account => ({
|
|
1145
|
+
const capacityAccounts = accounts.map(account => ({
|
|
1146
|
+
...account,
|
|
1147
|
+
active: account.id === activeId,
|
|
1148
|
+
quota: providerQuotaFromCodexQuota(account.quota),
|
|
1149
|
+
}));
|
|
1124
1150
|
const active = capacityAccounts.find(account => account.active)
|
|
1125
|
-
??
|
|
1126
|
-
??
|
|
1151
|
+
?? capacityAccounts.find(account => account.id === MAIN_CODEX_ACCOUNT_ID)
|
|
1152
|
+
?? capacityAccounts[0];
|
|
1127
1153
|
const now = Date.now();
|
|
1128
1154
|
const capacity = aggregateCodexPoolCapacity(capacityAccounts, now);
|
|
1129
1155
|
if (capacity.aggregation && capacity.quota) {
|
|
@@ -1139,7 +1165,12 @@ async function fetchChatGptForwardQuota(
|
|
|
1139
1165
|
}
|
|
1140
1166
|
const activeUsable = !!active && !active.paused && active.needsReauth !== true;
|
|
1141
1167
|
const quota = activeUsable && active?.quota
|
|
1142
|
-
? {
|
|
1168
|
+
? {
|
|
1169
|
+
...active.quota,
|
|
1170
|
+
fiveHourPercent: active.quota.fiveHourPercent ?? active.quota.shortPercent,
|
|
1171
|
+
fiveHourResetAt: active.quota.fiveHourResetAt ?? active.quota.shortResetAt,
|
|
1172
|
+
updatedAt: active.quota.updatedAt ?? Date.now(),
|
|
1173
|
+
} as CodexCapacityQuota
|
|
1143
1174
|
: null;
|
|
1144
1175
|
const quotaFresh = !!quota
|
|
1145
1176
|
&& Number.isFinite(quota.updatedAt)
|
|
@@ -1285,6 +1316,24 @@ function parseClaudeBucket(value: unknown): { percent?: number; resetAt?: number
|
|
|
1285
1316
|
return { percent, resetAt };
|
|
1286
1317
|
}
|
|
1287
1318
|
|
|
1319
|
+
function parseClaudeLimit(value: unknown): { label: string; percent: number; resetAt?: number } | null {
|
|
1320
|
+
const rec = asRecord(value);
|
|
1321
|
+
if (!rec) return null;
|
|
1322
|
+
const percent = normalizePercent(rec.percent);
|
|
1323
|
+
if (percent === undefined) return null;
|
|
1324
|
+
const scope = asRecord(rec.scope);
|
|
1325
|
+
const model = asRecord(scope?.model);
|
|
1326
|
+
const rawLabel = String(model?.display_name ?? "").trim();
|
|
1327
|
+
if (!rawLabel) return null;
|
|
1328
|
+
const lowerLabel = rawLabel.toLowerCase();
|
|
1329
|
+
const label = lowerLabel.includes("fable") ? "Fable"
|
|
1330
|
+
: lowerLabel.includes("opus") ? "Opus"
|
|
1331
|
+
: lowerLabel.includes("sonnet") ? "Sonnet"
|
|
1332
|
+
: rawLabel;
|
|
1333
|
+
const resetAt = normalizeResetAt(rec.resets_at);
|
|
1334
|
+
return { label, percent, ...(resetAt !== undefined ? { resetAt } : {}) };
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1288
1337
|
/** Claude's OAuth usage endpoint, probed with ONE account's own bearer token. */
|
|
1289
1338
|
const anthropicUsageInflight = new Map<string, Promise<ProviderQuota | null>>();
|
|
1290
1339
|
|
|
@@ -1308,11 +1357,25 @@ async function fetchAnthropicUsageQuota(accessToken: string): Promise<ProviderQu
|
|
|
1308
1357
|
if (!body) return null;
|
|
1309
1358
|
const fiveHour = parseClaudeBucket(body.five_hour);
|
|
1310
1359
|
const sevenDay = parseClaudeBucket(body.seven_day);
|
|
1360
|
+
const fable = parseClaudeBucket(body.seven_day_fable);
|
|
1311
1361
|
const opus = parseClaudeBucket(body.seven_day_opus);
|
|
1312
1362
|
const sonnet = parseClaudeBucket(body.seven_day_sonnet);
|
|
1313
1363
|
const customWindows: ProviderQuotaWindow[] = [];
|
|
1364
|
+
if (fable?.percent !== undefined) customWindows.push({ label: "Fable", percent: fable.percent, ...(fable.resetAt !== undefined ? { resetAt: fable.resetAt } : {}) });
|
|
1314
1365
|
if (opus?.percent !== undefined) customWindows.push({ label: "Opus", percent: opus.percent, ...(opus.resetAt !== undefined ? { resetAt: opus.resetAt } : {}) });
|
|
1315
1366
|
if (sonnet?.percent !== undefined) customWindows.push({ label: "Sonnet", percent: sonnet.percent, ...(sonnet.resetAt !== undefined ? { resetAt: sonnet.resetAt } : {}) });
|
|
1367
|
+
const knownLabels = new Set(customWindows.map(window => window.label.toLowerCase()));
|
|
1368
|
+
const limits = Array.isArray(body.limits) ? body.limits : [];
|
|
1369
|
+
for (const rawLimit of limits) {
|
|
1370
|
+
const limitRecord = asRecord(rawLimit);
|
|
1371
|
+
// `session` and `weekly_all` mirror the canonical five-hour and weekly
|
|
1372
|
+
// buckets above; only model-scoped weekly limits add a third window.
|
|
1373
|
+
if (String(limitRecord?.kind ?? "").trim().toLowerCase() !== "weekly_scoped") continue;
|
|
1374
|
+
const limit = parseClaudeLimit(rawLimit);
|
|
1375
|
+
if (!limit || knownLabels.has(limit.label.toLowerCase())) continue;
|
|
1376
|
+
knownLabels.add(limit.label.toLowerCase());
|
|
1377
|
+
customWindows.push(limit);
|
|
1378
|
+
}
|
|
1316
1379
|
const quota: ProviderQuota = {
|
|
1317
1380
|
// Claude's 5-hour window is a first-class rate limit, same as the Codex login 5h/weekly
|
|
1318
1381
|
// rows: report it in the canonical fields so the dashboard renders it with the standard
|
|
@@ -1401,7 +1464,12 @@ export interface ProviderAccountQuota {
|
|
|
1401
1464
|
|
|
1402
1465
|
/** Providers whose per-account quota can be probed. Extend as other OAuth APIs are covered. */
|
|
1403
1466
|
export function supportsPerAccountQuota(provider: string): boolean {
|
|
1404
|
-
return
|
|
1467
|
+
return (
|
|
1468
|
+
provider === "anthropic" ||
|
|
1469
|
+
provider === "google-antigravity" ||
|
|
1470
|
+
provider === "command-code" ||
|
|
1471
|
+
provider === "cursor"
|
|
1472
|
+
);
|
|
1405
1473
|
}
|
|
1406
1474
|
|
|
1407
1475
|
function accountCacheKey(provider: string, accountId: string): string {
|
|
@@ -1526,6 +1594,14 @@ async function fetchAccountQuota(
|
|
|
1526
1594
|
quota = await fetchAnthropicUsageQuota(token);
|
|
1527
1595
|
} else if (provider === "google-antigravity") {
|
|
1528
1596
|
quota = await fetchAntigravityAccountQuota(accountId);
|
|
1597
|
+
} else if (provider === "command-code") {
|
|
1598
|
+
const token = await getTokenForAccountQuotaProbe(provider, accountId);
|
|
1599
|
+
const res = await fetchCommandCodeUsageQuota(token);
|
|
1600
|
+
quota = res === TERMINAL_QUOTA_FAILURE ? null : res;
|
|
1601
|
+
} else if (provider === "cursor") {
|
|
1602
|
+
const token = await getTokenForAccountQuotaProbe(provider, accountId);
|
|
1603
|
+
const res = await fetchCursorUsageQuota(token);
|
|
1604
|
+
quota = res?.quota ?? null;
|
|
1529
1605
|
}
|
|
1530
1606
|
if (!quota) {
|
|
1531
1607
|
// Preserve last-good bars and mark unavailable; advance TTL so failures
|
|
@@ -1741,8 +1817,9 @@ function parseCommandCodeWindow(value: unknown): { percent: number; resetAt?: nu
|
|
|
1741
1817
|
if (!row) return null;
|
|
1742
1818
|
const cap = toFiniteNumber(row.cap);
|
|
1743
1819
|
const used = toFiniteNumber(row.used);
|
|
1744
|
-
|
|
1745
|
-
|
|
1820
|
+
const percent = cap !== undefined && used !== undefined && cap > 0 && used >= 0
|
|
1821
|
+
? normalizePercent((used / cap) * 100)
|
|
1822
|
+
: normalizePercent(row.percent);
|
|
1746
1823
|
if (percent === undefined) return null;
|
|
1747
1824
|
const resetAt = quotaResetAt(row);
|
|
1748
1825
|
return { percent, ...(resetAt !== undefined ? { resetAt } : {}) };
|
|
@@ -1829,11 +1906,7 @@ async function resolveCommandCodeQuotaBearer(config: OcxProviderConfig): Promise
|
|
|
1829
1906
|
* usage view uses (windowLimits.fiveHour / windowLimits.weekly), plus soft
|
|
1830
1907
|
* whoami (team orgId scoping) and subscription-scoped spend for creditsUsd.
|
|
1831
1908
|
*/
|
|
1832
|
-
async function
|
|
1833
|
-
// Never release credentials to a user-edited or lookalike provider host.
|
|
1834
|
-
if (!isCanonicalCommandCodeBaseUrl(config.baseUrl)) return null;
|
|
1835
|
-
const bearer = await resolveCommandCodeQuotaBearer(config);
|
|
1836
|
-
if (!bearer) return null;
|
|
1909
|
+
async function fetchCommandCodeUsageQuota(bearer: string): Promise<ProviderQuota | null | typeof TERMINAL_QUOTA_FAILURE> {
|
|
1837
1910
|
const whoamiBody = await fetchCommandCodeJson(COMMAND_CODE_WHOAMI_URL, bearer);
|
|
1838
1911
|
const whoami = asRecord(whoamiBody?.data) ?? whoamiBody;
|
|
1839
1912
|
const org = asRecord(whoami?.org);
|
|
@@ -1857,7 +1930,7 @@ async function fetchCommandCodeQuota(provider: string, config: OcxProviderConfig
|
|
|
1857
1930
|
const fiveHour = parseCommandCodeWindow(limits?.fiveHour);
|
|
1858
1931
|
const weekly = parseCommandCodeWindow(limits?.weekly);
|
|
1859
1932
|
const creditsUsd = await fetchCommandCodeSpend(bearer, credits, orgQuery);
|
|
1860
|
-
return
|
|
1933
|
+
return {
|
|
1861
1934
|
...(fiveHour ? {
|
|
1862
1935
|
fiveHourPercent: fiveHour.percent,
|
|
1863
1936
|
...(fiveHour.resetAt !== undefined ? { fiveHourResetAt: fiveHour.resetAt } : {}),
|
|
@@ -1868,18 +1941,21 @@ async function fetchCommandCodeQuota(provider: string, config: OcxProviderConfig
|
|
|
1868
1941
|
} : {}),
|
|
1869
1942
|
...(creditsUsd ? { creditsUsd } : {}),
|
|
1870
1943
|
updatedAt: Date.now(),
|
|
1871
|
-
}
|
|
1944
|
+
};
|
|
1872
1945
|
}
|
|
1873
1946
|
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1947
|
+
async function fetchCommandCodeQuota(provider: string, config: OcxProviderConfig): Promise<ProviderQuotaProbeResult> {
|
|
1948
|
+
// Never release credentials to a user-edited or lookalike provider host.
|
|
1949
|
+
if (!isCanonicalCommandCodeBaseUrl(config.baseUrl)) return null;
|
|
1950
|
+
const bearer = await resolveCommandCodeQuotaBearer(config);
|
|
1951
|
+
if (!bearer) return null;
|
|
1952
|
+
const result = await fetchCommandCodeUsageQuota(bearer);
|
|
1953
|
+
if (!result || result === TERMINAL_QUOTA_FAILURE) return result;
|
|
1954
|
+
return report(provider, "command-code:credits", result);
|
|
1955
|
+
}
|
|
1882
1956
|
|
|
1957
|
+
/** Cursor included usage via api2.cursor.sh (Bearer from OAuth) — unofficial, may change. */
|
|
1958
|
+
async function fetchCursorUsageQuota(accessToken: string): Promise<{ quota: ProviderQuota; source: string } | null> {
|
|
1883
1959
|
const authHeaders = {
|
|
1884
1960
|
Accept: "application/json",
|
|
1885
1961
|
Authorization: `Bearer ${accessToken}`,
|
|
@@ -1939,15 +2015,17 @@ async function fetchCursorQuota(provider: string): Promise<ProviderQuotaReport |
|
|
|
1939
2015
|
}
|
|
1940
2016
|
|
|
1941
2017
|
if (totalPercent !== undefined || customWindows.length > 0) {
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
...(
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
2018
|
+
return {
|
|
2019
|
+
source: "cursor:period-usage",
|
|
2020
|
+
quota: {
|
|
2021
|
+
...(totalPercent !== undefined ? {
|
|
2022
|
+
monthlyPercent: totalPercent,
|
|
2023
|
+
...(resetAt !== undefined ? { monthlyResetAt: resetAt } : {}),
|
|
2024
|
+
} : {}),
|
|
2025
|
+
...(customWindows.length > 0 ? { customWindows } : {}),
|
|
2026
|
+
updatedAt: Date.now(),
|
|
2027
|
+
},
|
|
2028
|
+
};
|
|
1951
2029
|
}
|
|
1952
2030
|
}
|
|
1953
2031
|
}
|
|
@@ -1973,12 +2051,14 @@ async function fetchCursorQuota(provider: string): Promise<ProviderQuotaReport |
|
|
|
1973
2051
|
? normalizePercent((used / limit) * 100)
|
|
1974
2052
|
: undefined);
|
|
1975
2053
|
if (percent !== undefined) {
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
2054
|
+
return {
|
|
2055
|
+
source: "cursor:usage-summary",
|
|
2056
|
+
quota: {
|
|
2057
|
+
monthlyPercent: percent,
|
|
2058
|
+
monthlyResetAt: normalizeResetAt(body?.billingCycleEnd),
|
|
2059
|
+
updatedAt: Date.now(),
|
|
2060
|
+
},
|
|
2061
|
+
};
|
|
1982
2062
|
}
|
|
1983
2063
|
}
|
|
1984
2064
|
}
|
|
@@ -2027,11 +2107,26 @@ async function fetchCursorQuota(provider: string): Promise<ProviderQuotaReport |
|
|
|
2027
2107
|
return Date.UTC(start.getUTCFullYear(), start.getUTCMonth() + 1, start.getUTCDate());
|
|
2028
2108
|
})()
|
|
2029
2109
|
: undefined;
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2110
|
+
return {
|
|
2111
|
+
source: "cursor:auth-usage",
|
|
2112
|
+
quota: {
|
|
2113
|
+
monthlyPercent: percent,
|
|
2114
|
+
...(monthlyResetAt !== undefined ? { monthlyResetAt } : {}),
|
|
2115
|
+
updatedAt: Date.now(),
|
|
2116
|
+
},
|
|
2117
|
+
};
|
|
2118
|
+
}
|
|
2119
|
+
|
|
2120
|
+
async function fetchCursorQuota(provider: string): Promise<ProviderQuotaReport | null> {
|
|
2121
|
+
let accessToken: string;
|
|
2122
|
+
try {
|
|
2123
|
+
accessToken = await getValidAccessToken("cursor");
|
|
2124
|
+
} catch {
|
|
2125
|
+
return null;
|
|
2126
|
+
}
|
|
2127
|
+
const result = await fetchCursorUsageQuota(accessToken);
|
|
2128
|
+
if (!result) return null;
|
|
2129
|
+
const built = report(provider, result.source, result.quota);
|
|
2035
2130
|
return built ? { ...built, reverseEngineered: true } : null;
|
|
2036
2131
|
}
|
|
2037
2132
|
|
|
@@ -2219,6 +2314,19 @@ async function fetchAntigravityQuota(provider: string, config: OcxProviderConfig
|
|
|
2219
2314
|
});
|
|
2220
2315
|
}
|
|
2221
2316
|
|
|
2317
|
+
async function fetchAiStudioQuota(name: string, _provider: OcxProviderConfig): Promise<ProviderQuotaReport | null> {
|
|
2318
|
+
const now = Date.now();
|
|
2319
|
+
return {
|
|
2320
|
+
provider: name,
|
|
2321
|
+
label: "Google AI Studio (Web)",
|
|
2322
|
+
source: "Direct Session",
|
|
2323
|
+
updatedAt: now,
|
|
2324
|
+
quota: {
|
|
2325
|
+
updatedAt: now,
|
|
2326
|
+
},
|
|
2327
|
+
};
|
|
2328
|
+
}
|
|
2329
|
+
|
|
2222
2330
|
async function maybeFetchProviderQuota(
|
|
2223
2331
|
name: string,
|
|
2224
2332
|
provider: OcxProviderConfig,
|
|
@@ -2294,6 +2402,9 @@ async function maybeFetchProviderQuota(
|
|
|
2294
2402
|
if ((provider.authMode ?? "key") === "key" && name === "neuralwatt") {
|
|
2295
2403
|
return fetchNeuralwattQuota(name, provider);
|
|
2296
2404
|
}
|
|
2405
|
+
if (provider.googleMode === "ai-studio-web" || name === "google-aistudio") {
|
|
2406
|
+
return fetchAiStudioQuota(name, provider);
|
|
2407
|
+
}
|
|
2297
2408
|
return null;
|
|
2298
2409
|
} catch {
|
|
2299
2410
|
return null;
|