@bitkyc08/opencodex 2.52.0-preview.20260911 → 2.52.0-preview.20260912

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (166) hide show
  1. package/gui/dist/assets/index-D_t6sCWs.js +115 -0
  2. package/gui/dist/assets/index-EdoPnm9_.css +1 -0
  3. package/gui/dist/index.html +2 -2
  4. package/gui/dist/provider-icons/devin.svg +49 -0
  5. package/gui/dist/provider-icons/omo.svg +42 -0
  6. package/package.json +3 -1
  7. package/src/AGENTS.md +1 -1
  8. package/src/adapters/cline-pass-deepseek-v4-tool-replay.ts +0 -1
  9. package/src/adapters/command-code.ts +0 -1
  10. package/src/adapters/cursor/checkpoint-store.ts +37 -0
  11. package/src/adapters/cursor/live-transport.ts +74 -2
  12. package/src/adapters/cursor.ts +6 -0
  13. package/src/adapters/devin/cloud-direct/auth.ts +264 -0
  14. package/src/adapters/devin/cloud-direct/catalog.ts +306 -0
  15. package/src/adapters/devin/cloud-direct/chat.ts +1274 -0
  16. package/src/adapters/devin/cloud-direct/index.ts +65 -0
  17. package/src/adapters/devin/cloud-direct/metadata.ts +134 -0
  18. package/src/adapters/devin/cloud-direct/wire.ts +206 -0
  19. package/src/adapters/devin/live-models.ts +133 -0
  20. package/src/adapters/devin-cli/acp.ts +204 -0
  21. package/src/adapters/devin-cli/adapter.ts +345 -0
  22. package/src/adapters/devin-cli/binary.ts +69 -0
  23. package/src/adapters/devin-cli/models.ts +57 -0
  24. package/src/adapters/devin.ts +326 -0
  25. package/src/adapters/google.ts +1 -1
  26. package/src/adapters/openai-chat.ts +31 -10
  27. package/src/adapters/openai-responses.ts +16 -1
  28. package/src/adapters/registry.ts +25 -1
  29. package/src/bridge.ts +8 -2
  30. package/src/claude/inbound-cache-stabilize.ts +130 -0
  31. package/src/claude/inbound.ts +45 -5
  32. package/src/cli/account-auth.ts +60 -1
  33. package/src/cli/account-extended.ts +23 -30
  34. package/src/cli/account.ts +2 -1
  35. package/src/cli/capabilities.ts +50 -8
  36. package/src/cli/config-command.ts +2 -2
  37. package/src/cli/dispatch.ts +14 -2
  38. package/src/cli/export-command.ts +11 -25
  39. package/src/cli/help.ts +2 -2
  40. package/src/cli/opencode.ts +5 -0
  41. package/src/cli/registry.ts +15 -4
  42. package/src/clients/config-export/cline.ts +71 -0
  43. package/src/clients/config-export/contracts.ts +10 -1
  44. package/src/clients/config-export/model-metadata.ts +33 -0
  45. package/src/clients/config-export/zcode.ts +23 -12
  46. package/src/clients/config-export.ts +156 -4
  47. package/src/codex/account-store.ts +7 -2
  48. package/src/codex/auth-context.ts +1 -1
  49. package/src/codex/catalog/effort.ts +4 -3
  50. package/src/codex/catalog/metadata.ts +8 -4
  51. package/src/codex/catalog/native-models.ts +24 -4
  52. package/src/codex/catalog/parsing.ts +19 -1
  53. package/src/codex/catalog/provider-fetch.ts +57 -0
  54. package/src/codex/catalog/sync.ts +1 -1
  55. package/src/codex/context-compat.ts +97 -0
  56. package/src/codex/context-owner.ts +201 -0
  57. package/src/codex/history-provider.ts +161 -14
  58. package/src/codex/inject-coordination.ts +3 -2
  59. package/src/codex/inject.ts +128 -9
  60. package/src/codex/pool-rotation.ts +8 -292
  61. package/src/codex/quota.ts +41 -12
  62. package/src/codex/retired-model-migration.ts +41 -0
  63. package/src/codex/routing.ts +327 -22
  64. package/src/codex/warmup.ts +2 -2
  65. package/src/combos/failover.ts +5 -0
  66. package/src/combos/resolve.ts +11 -15
  67. package/src/config.ts +46 -14
  68. package/src/generated/compatibility-version.json +293 -113
  69. package/src/grok/grpc-web.ts +120 -0
  70. package/src/grok/reset-coupon-ledger.ts +139 -0
  71. package/src/grok/reset-coupons.ts +278 -0
  72. package/src/integrations/catalog-refresh.ts +1 -1
  73. package/src/integrations/cline-document.ts +73 -0
  74. package/src/integrations/cline-io.ts +149 -0
  75. package/src/integrations/cline-transaction.ts +42 -0
  76. package/src/integrations/config-io.ts +21 -2
  77. package/src/integrations/journal.ts +43 -1
  78. package/src/integrations/omp-yaml-source.ts +123 -4
  79. package/src/integrations/ownership-policy.ts +7 -0
  80. package/src/integrations/ownership.ts +36 -0
  81. package/src/integrations/registry.ts +27 -0
  82. package/src/integrations/state.ts +5 -2
  83. package/src/integrations/store.ts +6 -0
  84. package/src/integrations/writer.ts +53 -9
  85. package/src/lab/subject/behavior-fingerprint.ts +1 -1
  86. package/src/lib/abort.ts +36 -0
  87. package/src/lib/local-destinations.ts +1 -1
  88. package/src/lib/upstream-retry.ts +36 -1
  89. package/src/oauth/account-quota-rank.ts +11 -0
  90. package/src/oauth/callback-server.ts +10 -5
  91. package/src/oauth/devin/api-base.ts +63 -0
  92. package/src/oauth/devin/login.ts +1 -0
  93. package/src/oauth/devin/register-user.ts +186 -0
  94. package/src/oauth/devin/types.ts +71 -0
  95. package/src/oauth/devin-cli.ts +149 -0
  96. package/src/oauth/devin.ts +170 -0
  97. package/src/oauth/generic-account-failover.ts +169 -1
  98. package/src/oauth/index.ts +20 -1
  99. package/src/oauth/login-cli.ts +19 -5
  100. package/src/oauth/pool-kernel.ts +321 -0
  101. package/src/oauth/pool-settings-capability.ts +127 -9
  102. package/src/oauth/store.ts +7 -3
  103. package/src/oauth/token-guardian.ts +1 -1
  104. package/src/providers/codebuddy-models.ts +0 -3
  105. package/src/providers/command-code-efforts.ts +23 -4
  106. package/src/providers/default-aliases.ts +4 -0
  107. package/src/providers/derive.ts +8 -0
  108. package/src/providers/devin-cli-authmode-migration.ts +57 -0
  109. package/src/providers/key-failover.ts +175 -0
  110. package/src/providers/model-rename-startup.ts +21 -1
  111. package/src/providers/qoder-models.ts +0 -1
  112. package/src/providers/quota-key-accounts.ts +50 -0
  113. package/src/providers/quota-routing-cache.ts +65 -6
  114. package/src/providers/quota-types.ts +7 -0
  115. package/src/providers/quota.ts +113 -30
  116. package/src/providers/registry.ts +237 -77
  117. package/src/providers/stale-context-window-migration.ts +92 -0
  118. package/src/providers/zai-responses-migration.ts +45 -0
  119. package/src/quota/reset-observer.ts +2 -1
  120. package/src/quota/reset-seen-store.ts +9 -1
  121. package/src/remote-control/crypto.ts +442 -0
  122. package/src/remote-control/host.ts +175 -0
  123. package/src/remote-control/index.ts +100 -0
  124. package/src/remote-control/protocol.ts +200 -0
  125. package/src/remote-control/relay.ts +162 -0
  126. package/src/remote-control/workspace-agent-protocol.ts +246 -0
  127. package/src/remote-control/workspace-rpc-framing.ts +128 -0
  128. package/src/remote-control/workspace-tools.ts +237 -0
  129. package/src/remote-control/workspace-utf8.ts +24 -0
  130. package/src/responses/custom-tool-compat.ts +23 -0
  131. package/src/router.ts +6 -1
  132. package/src/routing/compatibility/behavior.ts +3 -0
  133. package/src/server/adapter-resolve.ts +6 -2
  134. package/src/server/auth-cors.ts +71 -6
  135. package/src/server/chat-completions.ts +5 -3
  136. package/src/server/chat-native.ts +9 -0
  137. package/src/server/claude-messages.ts +25 -30
  138. package/src/server/context-history.ts +207 -0
  139. package/src/server/images.ts +28 -1
  140. package/src/server/index.ts +42 -22
  141. package/src/server/live.ts +2 -1
  142. package/src/server/management/agent-settings-routes.ts +7 -1
  143. package/src/server/management/config-routes.ts +3 -3
  144. package/src/server/management/grok-coupon-routes.ts +287 -0
  145. package/src/server/management/integration-routes.ts +6 -1
  146. package/src/server/management/oauth-account-routes.ts +124 -7
  147. package/src/server/management/provider-routes.ts +77 -2
  148. package/src/server/management/route-registry.ts +6 -1
  149. package/src/server/management-api.ts +7 -0
  150. package/src/server/request-log.ts +4 -0
  151. package/src/server/responses/codex-ws-exchange.ts +90 -14
  152. package/src/server/responses/codex-ws-wire.ts +51 -1
  153. package/src/server/responses/compact.ts +8 -1
  154. package/src/server/responses/core.ts +188 -22
  155. package/src/server/responses/ws-upstream.ts +1 -1
  156. package/src/server/responses-undeclared-tool-guard.ts +261 -12
  157. package/src/server/zai-responses-startup.ts +21 -0
  158. package/src/types/config.ts +33 -3
  159. package/src/types/provider.ts +54 -4
  160. package/src/types/request.ts +1 -1
  161. package/src/types/tools.ts +36 -6
  162. package/src/update/job.ts +33 -11
  163. package/src/vision/plan.ts +40 -37
  164. package/src/web-search/index.ts +1 -0
  165. package/gui/dist/assets/index-BoBRSehJ.css +0 -1
  166. package/gui/dist/assets/index-Dx0xv2EA.js +0 -115
@@ -39,7 +39,9 @@ import {
39
39
  } from "./quota-wire";
40
40
  import {
41
41
  clearCachedProviderQuotas,
42
+ providerQuotaRoutingBinding,
42
43
  replaceCachedProviderQuotas,
44
+ type ProviderQuotaRoutingEvidence,
43
45
  } from "./quota-routing-cache";
44
46
  import {
45
47
  aggregateCodexPoolCapacity,
@@ -52,6 +54,7 @@ import type {
52
54
  ProviderQuota,
53
55
  ProviderQuotaCreditsUsd,
54
56
  ProviderQuotaWindow,
57
+ ProviderRoutingQuota,
55
58
  } from "./quota-types";
56
59
  import {
57
60
  clearKiroAccountUsageState,
@@ -103,6 +106,7 @@ const XAI_CREDITS_URL = `${XAI_BILLING_URL}?format=credits`;
103
106
  const LAST_GOOD_MAX_AGE_MS = CODEX_CAPACITY_MAX_QUOTA_AGE_MS;
104
107
  const nativeMainReportGenerations = new WeakMap<ProviderQuotaReport, number>();
105
108
  const accountReportCurrent = new WeakMap<ProviderQuotaReport, () => boolean>();
109
+ const routingEvidence = new WeakMap<ProviderQuotaReport, ProviderQuotaRoutingEvidence>();
106
110
  let providerQuotaBeforePublishForTests: (() => void | Promise<void>) | null = null;
107
111
 
108
112
  /** Test-only seam for identity/config invalidation after probes but before publication. */
@@ -136,6 +140,8 @@ export interface ProviderQuotaReport {
136
140
  source: string;
137
141
  quota: ProviderQuota;
138
142
  updatedAt: number;
143
+ /** Added by the management response projection, never stored on a cached report. */
144
+ routingQuota?: ProviderRoutingQuota;
139
145
  reverseEngineered?: boolean;
140
146
  /**
141
147
  * The row was OBSERVED in-band on a streaming turn rather than probed.
@@ -345,14 +351,26 @@ function isCanonicalOllamaCloudBaseUrl(baseUrl?: string): boolean {
345
351
  }
346
352
  }
347
353
 
354
+ function zaiQuotaMonitorHost(baseUrl: string): string | null {
355
+ // Admission and destination selection must share one mapping: admitting a new
356
+ // international wire must never fall through to the CN host/authentication scheme.
357
+ switch (normalizedBaseUrl(baseUrl)) {
358
+ case ZAI_BASE_URL:
359
+ case `${ZAI_BASE_URL}/api/coding/paas/v4`:
360
+ case `${ZAI_BASE_URL}/api/anthropic`:
361
+ case `${ZAI_BASE_URL}/api/v1`:
362
+ return ZAI_BASE_URL;
363
+ case ZAI_CN_BASE_URL:
364
+ case `${ZAI_CN_BASE_URL}/api/coding/paas/v4`:
365
+ case `${ZAI_CN_BASE_URL}/api/v1`:
366
+ return ZAI_CN_BASE_URL;
367
+ default:
368
+ return null;
369
+ }
370
+ }
371
+
348
372
  function isCanonicalZaiBaseUrl(baseUrl: string): boolean {
349
- const normalized = normalizedBaseUrl(baseUrl);
350
- return normalized === ZAI_BASE_URL
351
- || normalized === `${ZAI_BASE_URL}/api/coding/paas/v4`
352
- || normalized === ZAI_CN_BASE_URL
353
- || normalized === `${ZAI_CN_BASE_URL}/api/coding/paas/v4`
354
- // BigModel serves the same GLM Coding Plan on the OpenAI Responses wire at /api/v1.
355
- || normalized === `${ZAI_CN_BASE_URL}/api/v1`;
373
+ return zaiQuotaMonitorHost(baseUrl) !== null;
356
374
  }
357
375
 
358
376
  function isCanonicalMinimaxBaseUrl(baseUrl: string): boolean {
@@ -435,7 +453,9 @@ async function fetchA6apiQuota(provider: string, config: OcxProviderConfig): Pro
435
453
  ? { expiresAt: normalizedExpiry }
436
454
  : {};
437
455
  if (unlimited) {
438
- return report(provider, "a6api:billing", {
456
+ // Every row is an API-credit constraint on inference, so the display quota is also
457
+ // the routing projection. Passing it explicitly is the opt-in.
458
+ const quota: ProviderQuota = {
439
459
  creditsUsd: {
440
460
  used: 0,
441
461
  limit: 0,
@@ -446,7 +466,8 @@ async function fetchA6apiQuota(provider: string, config: OcxProviderConfig): Pro
446
466
  },
447
467
  customWindows: [{ label: "Unlimited API credits", percent: 0 }],
448
468
  updatedAt: Date.now(),
449
- });
469
+ };
470
+ return keyReport(provider, "a6api:billing", quota, config, apiKey, quota);
450
471
  }
451
472
  const limitUsd = firstFinite(subscription, ["hard_limit_usd"]);
452
473
  const grantedUnits = firstFinite(token, ["total_granted"]);
@@ -469,7 +490,7 @@ async function fetchA6apiQuota(provider: string, config: OcxProviderConfig): Pro
469
490
  const percent = normalizePercent((usedUsd / limitUsd) * 100);
470
491
  if (percent === undefined) return TERMINAL_QUOTA_FAILURE;
471
492
  const label = `API credits ($${remainingUsd.toFixed(2)} of $${limitUsd.toFixed(2)} remaining)`;
472
- return report(provider, "a6api:billing", {
493
+ const quota: ProviderQuota = {
473
494
  creditsUsd: {
474
495
  used: usedUsd,
475
496
  limit: limitUsd,
@@ -479,7 +500,9 @@ async function fetchA6apiQuota(provider: string, config: OcxProviderConfig): Pro
479
500
  },
480
501
  customWindows: [{ label, percent }],
481
502
  updatedAt: Date.now(),
482
- });
503
+ };
504
+ // The credit balance funds inference itself, so display and routing scope agree.
505
+ return keyReport(provider, "a6api:billing", quota, config, apiKey, quota);
483
506
  }
484
507
 
485
508
  function parseOpenCodeGoUsageWindow(value: unknown): { percent: number; resetAt?: number } | null {
@@ -527,7 +550,7 @@ async function fetchOpenCodeGoQuota(provider: string, config: OcxProviderConfig)
527
550
  } : {}),
528
551
  updatedAt: Date.now(),
529
552
  };
530
- return report(provider, "opencode-go:usage", quota);
553
+ return keyReport(provider, "opencode-go:usage", quota, config, apiKey, quota);
531
554
  }
532
555
 
533
556
  /**
@@ -571,10 +594,13 @@ async function fetchOpenRouterQuota(provider: string, config: OcxProviderConfig)
571
594
  if (percent === undefined) return null;
572
595
  const remaining = Math.max(0, limit - used);
573
596
  const label = `API credits ($${remaining.toFixed(2)} of $${limit.toFixed(2)} remaining)`;
574
- return report(provider, "openrouter:key-info", {
597
+ // The per-key spending cap stops every request this credential can make, so the
598
+ // whole report is inference-wide routing evidence.
599
+ const quota: ProviderQuota = {
575
600
  customWindows: [{ label, percent }],
576
601
  updatedAt: Date.now(),
577
- });
602
+ };
603
+ return keyReport(provider, "openrouter:key-info", quota, config, apiKey, quota);
578
604
  }
579
605
 
580
606
  /**
@@ -673,7 +699,7 @@ async function fetchClineQuota(provider: string, config: OcxProviderConfig): Pro
673
699
  windows += 1;
674
700
  }
675
701
  }
676
- return windows > 0 ? report(provider, "cline:plan-usage-limits", quota) : null;
702
+ return windows > 0 ? keyReport(provider, "cline:plan-usage-limits", quota, config, apiKey, quota) : null;
677
703
  }
678
704
 
679
705
  /**
@@ -745,7 +771,7 @@ async function fetchOllamaCloudQuota(provider: string, config: OcxProviderConfig
745
771
  }
746
772
  const body = asRecord(await readQuotaJson(response));
747
773
  const quota = parseOllamaCloudQuota(body);
748
- return quota ? report(provider, "ollama-cloud:usage", quota) : null;
774
+ return quota ? keyReport(provider, "ollama-cloud:usage", quota, config, apiKey, quota) : null;
749
775
  }
750
776
 
751
777
  /**
@@ -851,13 +877,10 @@ function parseZaiQuotaLegacyFields(data: Record<string, unknown> | null): Provid
851
877
  * host or follow a redirect off-origin.
852
878
  */
853
879
  async function fetchZaiQuota(provider: string, config: OcxProviderConfig): Promise<ProviderQuotaProbeResult> {
854
- if (!isCanonicalZaiBaseUrl(config.baseUrl)) return null;
880
+ const monitorHost = zaiQuotaMonitorHost(config.baseUrl);
881
+ if (!monitorHost) return null;
855
882
  const apiKey = resolveProviderApiKey(config.apiKey)?.trim();
856
883
  if (!apiKey) return null;
857
- const normalized = normalizedBaseUrl(config.baseUrl);
858
- const monitorHost = normalized === ZAI_BASE_URL || normalized === `${ZAI_BASE_URL}/api/coding/paas/v4`
859
- ? ZAI_BASE_URL
860
- : ZAI_CN_BASE_URL;
861
884
  const authorization = monitorHost === ZAI_CN_BASE_URL ? apiKey : `Bearer ${apiKey}`;
862
885
  const response = await fetch(`${monitorHost}/api/monitor/usage/quota/limit`, {
863
886
  headers: { Accept: "application/json", Authorization: authorization },
@@ -878,10 +901,18 @@ async function fetchZaiQuota(provider: string, config: OcxProviderConfig): Promi
878
901
  // model window — for example a plan reporting only the monthly MCP `TIME_LIMIT` row.
879
902
  // Returning `null` here would preserve the previous token windows for up to 30 minutes
880
903
  // and keep quota-aware routing acting on a report the provider has already superseded.
881
- return quota ? report(provider, "zai:quota-limit", quota) : AUTHORITATIVE_EMPTY_QUOTA;
904
+ return quota
905
+ ? keyReport(provider, "zai:quota-limit", quota, config, apiKey, quota)
906
+ : AUTHORITATIVE_EMPTY_QUOTA;
882
907
  }
883
908
  const legacy = parseZaiQuotaLegacyFields(data);
884
- return legacy ? report(provider, "zai:quota-limit", legacy) : null;
909
+ if (!legacy) return null;
910
+ // The legacy monthly figure also carries MCP usage; it is display evidence, not
911
+ // proof that model inference is unavailable. Modern TOKEN_LIMIT rows above are scoped.
912
+ const inferenceQuota = { ...legacy };
913
+ delete inferenceQuota.monthlyPercent;
914
+ delete inferenceQuota.monthlyResetAt;
915
+ return keyReport(provider, "zai:quota-limit", legacy, config, apiKey, inferenceQuota);
885
916
  }
886
917
 
887
918
  /**
@@ -1064,7 +1095,9 @@ async function fetchSyntheticQuota(provider: string, config: OcxProviderConfig):
1064
1095
  quota.customWindows = [...(quota.customWindows ?? []), { label: "Search hourly", percent: searchHourly }];
1065
1096
  windows += 1;
1066
1097
  }
1067
- return windows > 0 ? report(provider, "synthetic:quotas", quota) : null;
1098
+ const inferenceQuota = { ...quota };
1099
+ delete inferenceQuota.customWindows; // search.hourly does not constrain model inference.
1100
+ return windows > 0 ? keyReport(provider, "synthetic:quotas", quota, config, apiKey, inferenceQuota) : null;
1068
1101
  }
1069
1102
 
1070
1103
  /**
@@ -1176,6 +1209,31 @@ function report(
1176
1209
  };
1177
1210
  }
1178
1211
 
1212
+ /**
1213
+ * Publish a credential-bound report, and routing evidence only when the producer
1214
+ * hands over its inference-only projection.
1215
+ *
1216
+ * The projection is deliberately not defaulted to the display quota. A producer must
1217
+ * decide that its rows really do constrain inference on the probed credential; omitting
1218
+ * the argument leaves the report display-only, so a new producer cannot inherit
1219
+ * provider-veto authority merely by calling this helper. Ownership alone is not the
1220
+ * scope decision: providerQuotaRoutingBinding resolving is necessary, never sufficient.
1221
+ */
1222
+ function keyReport(
1223
+ provider: string,
1224
+ source: string,
1225
+ quota: ProviderQuota,
1226
+ config: OcxProviderConfig,
1227
+ probedCredential: string,
1228
+ inferenceQuota?: ProviderQuota,
1229
+ ): ProviderQuotaReport | null {
1230
+ const result = report(provider, source, quota);
1231
+ if (!result || !inferenceQuota) return result;
1232
+ const binding = providerQuotaRoutingBinding(provider, config, probedCredential);
1233
+ if (binding) routingEvidence.set(result, { quota: inferenceQuota, binding });
1234
+ return result;
1235
+ }
1236
+
1179
1237
  function tagNativeMainReport(
1180
1238
  value: ProviderQuotaReport | null,
1181
1239
  generation: number,
@@ -1184,6 +1242,27 @@ function tagNativeMainReport(
1184
1242
  return value;
1185
1243
  }
1186
1244
 
1245
+ /**
1246
+ * Test-only seam: publish exactly as a credential-bound producer does, and hand back the
1247
+ * routing evidence the publication actually attached.
1248
+ *
1249
+ * Live producers all pass a projection today, so no probe fixture can prove the OTHER half
1250
+ * of the contract: that omitting it stays display-only. Routing an omitted argument through
1251
+ * the real helper keeps that provable, and a re-introduced `= quota` default would be
1252
+ * observed here (a defaulted parameter also fires for an explicitly undefined argument).
1253
+ */
1254
+ export function publishKeyReportForTests(
1255
+ provider: string,
1256
+ source: string,
1257
+ quota: ProviderQuota,
1258
+ config: OcxProviderConfig,
1259
+ probedCredential: string,
1260
+ inferenceQuota?: ProviderQuota,
1261
+ ): { report: ProviderQuotaReport | null; routing: ProviderQuotaRoutingEvidence | undefined } {
1262
+ const result = keyReport(provider, source, quota, config, probedCredential, inferenceQuota);
1263
+ return { report: result, routing: result ? routingEvidence.get(result) : undefined };
1264
+ }
1265
+
1187
1266
  function isProviderQuotaReportCurrent(value: ProviderQuotaReport): boolean {
1188
1267
  const generation = nativeMainReportGenerations.get(value);
1189
1268
  return (generation === undefined || isMainAccountIdentityGenerationLive(generation))
@@ -1879,7 +1958,7 @@ export function reconcileProviderAccountQuotaRows(context: GenerationContext): n
1879
1958
  const reports = cache.response.reports.filter(report => context.providerNames.has(report.provider));
1880
1959
  removed += cache.response.reports.length - reports.length;
1881
1960
  cache = { ...cache, response: { ...cache.response, reports } };
1882
- replaceCachedProviderQuotas(reports);
1961
+ replaceCachedProviderQuotas(reports, routingEvidence);
1883
1962
  }
1884
1963
  liveAccountQuotaKeys = new Set(context.oauthAccountKeys);
1885
1964
  liveProviderQuotaKeys = new Set(context.providerNames);
@@ -2308,7 +2387,7 @@ async function fetchKimiQuota(provider: string, config: OcxProviderConfig, acces
2308
2387
  });
2309
2388
  if (!response.ok) return null;
2310
2389
  const quota = parseKimiQuotaPayload(await readQuotaJson(response));
2311
- return quota ? report(provider, "kimi:usages", quota) : null;
2390
+ return quota ? keyReport(provider, "kimi:usages", quota, config, accessToken, quota) : null;
2312
2391
  }
2313
2392
 
2314
2393
  /**
@@ -2435,7 +2514,7 @@ async function fetchCommandCodeQuota(provider: string, config: OcxProviderConfig
2435
2514
  const fiveHour = parseCommandCodeWindow(limits?.fiveHour);
2436
2515
  const weekly = parseCommandCodeWindow(limits?.weekly);
2437
2516
  const creditsUsd = await fetchCommandCodeSpend(bearer, credits, orgQuery);
2438
- return report(provider, "command-code:credits", {
2517
+ const quota: ProviderQuota = {
2439
2518
  ...(fiveHour ? {
2440
2519
  fiveHourPercent: fiveHour.percent,
2441
2520
  ...(fiveHour.resetAt !== undefined ? { fiveHourResetAt: fiveHour.resetAt } : {}),
@@ -2446,7 +2525,9 @@ async function fetchCommandCodeQuota(provider: string, config: OcxProviderConfig
2446
2525
  } : {}),
2447
2526
  ...(creditsUsd ? { creditsUsd } : {}),
2448
2527
  updatedAt: Date.now(),
2449
- });
2528
+ };
2529
+ // Rolling windows and the credit balance both gate inference on this bearer.
2530
+ return keyReport(provider, "command-code:credits", quota, config, bearer, quota);
2450
2531
  }
2451
2532
 
2452
2533
  /** Cursor included usage via api2.cursor.sh (Bearer from OAuth) — unofficial, may change. */
@@ -2955,7 +3036,9 @@ async function maybeFetchProviderQuota(
2955
3036
  // probe to run — the row is the active account's last in-band observation.
2956
3037
  if (provider.authMode === "oauth" && hasPassiveAccountQuota(name)) return fetchPassiveProviderQuota(name);
2957
3038
  const reader = keyQuotaReaderForProvider(name, provider);
2958
- return reader ? reader(name, provider) : null;
3039
+ // Keep destination/auth fields bound to the same request as the reader's captured
3040
+ // bearer, even if the live provider object changes while the quota probe awaits.
3041
+ return reader ? reader(name, { ...provider }) : null;
2959
3042
  } catch {
2960
3043
  return null;
2961
3044
  }
@@ -3142,7 +3225,7 @@ export async function fetchProviderQuotaReports(config: OcxConfig, forceRefresh
3142
3225
  ) {
3143
3226
  const reports = response.reports.filter(item => mayCommitProviderQuotaKey(item.provider, writerGeneration));
3144
3227
  cache = { key, ts: Date.now(), response: { ...response, reports } };
3145
- replaceCachedProviderQuotas(reports);
3228
+ replaceCachedProviderQuotas(reports, routingEvidence);
3146
3229
  notifyProviderQuotaSnapshot(reports, config);
3147
3230
  }
3148
3231
  return response;