@slkiser/opencode-quota 3.11.1 → 4.0.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.
Files changed (208) hide show
  1. package/README.md +103 -57
  2. package/dist/bin/opencode-quota.d.ts.map +1 -1
  3. package/dist/bin/opencode-quota.js +24 -7
  4. package/dist/bin/opencode-quota.js.map +1 -1
  5. package/dist/index.d.ts +2 -0
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +2 -0
  8. package/dist/index.js.map +1 -1
  9. package/dist/lib/anthropic.d.ts.map +1 -1
  10. package/dist/lib/anthropic.js +106 -3
  11. package/dist/lib/anthropic.js.map +1 -1
  12. package/dist/lib/atomic-json.d.ts +1 -0
  13. package/dist/lib/atomic-json.d.ts.map +1 -1
  14. package/dist/lib/atomic-json.js +5 -2
  15. package/dist/lib/atomic-json.js.map +1 -1
  16. package/dist/lib/cli-show.d.ts.map +1 -1
  17. package/dist/lib/cli-show.js +11 -7
  18. package/dist/lib/cli-show.js.map +1 -1
  19. package/dist/lib/command-surfaces.d.ts +10 -0
  20. package/dist/lib/command-surfaces.d.ts.map +1 -0
  21. package/dist/lib/command-surfaces.js +9 -0
  22. package/dist/lib/command-surfaces.js.map +1 -0
  23. package/dist/lib/config-file-utils.d.ts +5 -0
  24. package/dist/lib/config-file-utils.d.ts.map +1 -1
  25. package/dist/lib/config-file-utils.js +20 -3
  26. package/dist/lib/config-file-utils.js.map +1 -1
  27. package/dist/lib/config.d.ts +5 -3
  28. package/dist/lib/config.d.ts.map +1 -1
  29. package/dist/lib/config.js +124 -32
  30. package/dist/lib/config.js.map +1 -1
  31. package/dist/lib/copilot.d.ts +19 -12
  32. package/dist/lib/copilot.d.ts.map +1 -1
  33. package/dist/lib/copilot.js +462 -566
  34. package/dist/lib/copilot.js.map +1 -1
  35. package/dist/lib/display-sanitize.d.ts.map +1 -1
  36. package/dist/lib/display-sanitize.js +13 -0
  37. package/dist/lib/display-sanitize.js.map +1 -1
  38. package/dist/lib/entries.d.ts +53 -4
  39. package/dist/lib/entries.d.ts.map +1 -1
  40. package/dist/lib/entries.js.map +1 -1
  41. package/dist/lib/init-installer.d.ts +11 -1
  42. package/dist/lib/init-installer.d.ts.map +1 -1
  43. package/dist/lib/init-installer.js +542 -154
  44. package/dist/lib/init-installer.js.map +1 -1
  45. package/dist/lib/openai.d.ts +9 -12
  46. package/dist/lib/openai.d.ts.map +1 -1
  47. package/dist/lib/openai.js +69 -40
  48. package/dist/lib/openai.js.map +1 -1
  49. package/dist/lib/opencode-config-editor.d.ts +53 -0
  50. package/dist/lib/opencode-config-editor.d.ts.map +1 -0
  51. package/dist/lib/opencode-config-editor.js +274 -0
  52. package/dist/lib/opencode-config-editor.js.map +1 -0
  53. package/dist/lib/opencode-config-providers.d.ts +18 -0
  54. package/dist/lib/opencode-config-providers.d.ts.map +1 -1
  55. package/dist/lib/opencode-config-providers.js +75 -4
  56. package/dist/lib/opencode-config-providers.js.map +1 -1
  57. package/dist/lib/opencode-runtime-paths.d.ts.map +1 -1
  58. package/dist/lib/opencode-runtime-paths.js +10 -3
  59. package/dist/lib/opencode-runtime-paths.js.map +1 -1
  60. package/dist/lib/opencode-storage.d.ts +10 -0
  61. package/dist/lib/opencode-storage.d.ts.map +1 -1
  62. package/dist/lib/opencode-storage.js +75 -0
  63. package/dist/lib/opencode-storage.js.map +1 -1
  64. package/dist/lib/provider-add-command.d.ts +35 -0
  65. package/dist/lib/provider-add-command.d.ts.map +1 -0
  66. package/dist/lib/provider-add-command.js +185 -0
  67. package/dist/lib/provider-add-command.js.map +1 -0
  68. package/dist/lib/provider-add.d.ts +21 -0
  69. package/dist/lib/provider-add.d.ts.map +1 -0
  70. package/dist/lib/provider-add.js +210 -0
  71. package/dist/lib/provider-add.js.map +1 -0
  72. package/dist/lib/provider-metadata.d.ts +1 -1
  73. package/dist/lib/provider-metadata.d.ts.map +1 -1
  74. package/dist/lib/provider-metadata.js +11 -5
  75. package/dist/lib/provider-metadata.js.map +1 -1
  76. package/dist/lib/quota-command-format.d.ts +2 -0
  77. package/dist/lib/quota-command-format.d.ts.map +1 -1
  78. package/dist/lib/quota-command-format.js +94 -26
  79. package/dist/lib/quota-command-format.js.map +1 -1
  80. package/dist/lib/quota-dialog-commands.d.ts.map +1 -1
  81. package/dist/lib/quota-dialog-commands.js +8 -4
  82. package/dist/lib/quota-dialog-commands.js.map +1 -1
  83. package/dist/lib/quota-export-types.d.ts +48 -27
  84. package/dist/lib/quota-export-types.d.ts.map +1 -1
  85. package/dist/lib/quota-export-types.js +0 -7
  86. package/dist/lib/quota-export-types.js.map +1 -1
  87. package/dist/lib/quota-export.d.ts.map +1 -1
  88. package/dist/lib/quota-export.js +63 -16
  89. package/dist/lib/quota-export.js.map +1 -1
  90. package/dist/lib/quota-providers-local.d.ts +55 -0
  91. package/dist/lib/quota-providers-local.d.ts.map +1 -0
  92. package/dist/lib/quota-providers-local.js +313 -0
  93. package/dist/lib/quota-providers-local.js.map +1 -0
  94. package/dist/lib/quota-providers-remote.d.ts +23 -0
  95. package/dist/lib/quota-providers-remote.d.ts.map +1 -0
  96. package/dist/lib/quota-providers-remote.js +318 -0
  97. package/dist/lib/quota-providers-remote.js.map +1 -0
  98. package/dist/lib/quota-providers.d.ts +77 -0
  99. package/dist/lib/quota-providers.d.ts.map +1 -0
  100. package/dist/lib/quota-providers.js +630 -0
  101. package/dist/lib/quota-providers.js.map +1 -0
  102. package/dist/lib/quota-render-data.d.ts +1 -0
  103. package/dist/lib/quota-render-data.d.ts.map +1 -1
  104. package/dist/lib/quota-render-data.js +35 -16
  105. package/dist/lib/quota-render-data.js.map +1 -1
  106. package/dist/lib/quota-runtime-context.d.ts.map +1 -1
  107. package/dist/lib/quota-runtime-context.js +3 -4
  108. package/dist/lib/quota-runtime-context.js.map +1 -1
  109. package/dist/lib/quota-state.d.ts +5 -2
  110. package/dist/lib/quota-state.d.ts.map +1 -1
  111. package/dist/lib/quota-state.js +268 -51
  112. package/dist/lib/quota-state.js.map +1 -1
  113. package/dist/lib/quota-status.d.ts +2 -1
  114. package/dist/lib/quota-status.d.ts.map +1 -1
  115. package/dist/lib/quota-status.js +247 -69
  116. package/dist/lib/quota-status.js.map +1 -1
  117. package/dist/lib/qwen-local-quota.d.ts +12 -11
  118. package/dist/lib/qwen-local-quota.d.ts.map +1 -1
  119. package/dist/lib/qwen-local-quota.js +82 -87
  120. package/dist/lib/qwen-local-quota.js.map +1 -1
  121. package/dist/lib/scoped-update.d.ts +63 -0
  122. package/dist/lib/scoped-update.d.ts.map +1 -0
  123. package/dist/lib/scoped-update.js +311 -0
  124. package/dist/lib/scoped-update.js.map +1 -0
  125. package/dist/lib/tui-runtime.d.ts +2 -0
  126. package/dist/lib/tui-runtime.d.ts.map +1 -1
  127. package/dist/lib/tui-runtime.js +33 -9
  128. package/dist/lib/tui-runtime.js.map +1 -1
  129. package/dist/lib/types.d.ts +51 -15
  130. package/dist/lib/types.d.ts.map +1 -1
  131. package/dist/lib/types.js +2 -1
  132. package/dist/lib/types.js.map +1 -1
  133. package/dist/plugin.d.ts.map +1 -1
  134. package/dist/plugin.js +75 -100
  135. package/dist/plugin.js.map +1 -1
  136. package/dist/providers/alibaba-coding-plan.d.ts.map +1 -1
  137. package/dist/providers/alibaba-coding-plan.js +35 -4
  138. package/dist/providers/alibaba-coding-plan.js.map +1 -1
  139. package/dist/providers/anthropic.d.ts.map +1 -1
  140. package/dist/providers/anthropic.js +13 -1
  141. package/dist/providers/anthropic.js.map +1 -1
  142. package/dist/providers/chutes.d.ts.map +1 -1
  143. package/dist/providers/chutes.js +6 -0
  144. package/dist/providers/chutes.js.map +1 -1
  145. package/dist/providers/copilot.d.ts +2 -1
  146. package/dist/providers/copilot.d.ts.map +1 -1
  147. package/dist/providers/copilot.js +143 -60
  148. package/dist/providers/copilot.js.map +1 -1
  149. package/dist/providers/cursor.d.ts.map +1 -1
  150. package/dist/providers/cursor.js +30 -1
  151. package/dist/providers/cursor.js.map +1 -1
  152. package/dist/providers/deepseek.d.ts.map +1 -1
  153. package/dist/providers/deepseek.js +13 -1
  154. package/dist/providers/deepseek.js.map +1 -1
  155. package/dist/providers/google-agy.d.ts.map +1 -1
  156. package/dist/providers/google-agy.js +7 -1
  157. package/dist/providers/google-agy.js.map +1 -1
  158. package/dist/providers/google-antigravity.d.ts.map +1 -1
  159. package/dist/providers/google-antigravity.js +10 -2
  160. package/dist/providers/google-antigravity.js.map +1 -1
  161. package/dist/providers/google-gemini-cli.d.ts.map +1 -1
  162. package/dist/providers/google-gemini-cli.js +8 -2
  163. package/dist/providers/google-gemini-cli.js.map +1 -1
  164. package/dist/providers/kimi-code.d.ts.map +1 -1
  165. package/dist/providers/kimi-code.js +6 -0
  166. package/dist/providers/kimi-code.js.map +1 -1
  167. package/dist/providers/minimax-coding-plan.d.ts.map +1 -1
  168. package/dist/providers/minimax-coding-plan.js +12 -4
  169. package/dist/providers/minimax-coding-plan.js.map +1 -1
  170. package/dist/providers/nanogpt.d.ts.map +1 -1
  171. package/dist/providers/nanogpt.js +19 -1
  172. package/dist/providers/nanogpt.js.map +1 -1
  173. package/dist/providers/ollama-cloud.d.ts.map +1 -1
  174. package/dist/providers/ollama-cloud.js +12 -0
  175. package/dist/providers/ollama-cloud.js.map +1 -1
  176. package/dist/providers/openai.d.ts.map +1 -1
  177. package/dist/providers/openai.js +7 -0
  178. package/dist/providers/openai.js.map +1 -1
  179. package/dist/providers/opencode-go.d.ts.map +1 -1
  180. package/dist/providers/opencode-go.js +9 -1
  181. package/dist/providers/opencode-go.js.map +1 -1
  182. package/dist/providers/quota-providers.d.ts +6 -0
  183. package/dist/providers/quota-providers.d.ts.map +1 -0
  184. package/dist/providers/quota-providers.js +276 -0
  185. package/dist/providers/quota-providers.js.map +1 -0
  186. package/dist/providers/qwen-code.d.ts.map +1 -1
  187. package/dist/providers/qwen-code.js +29 -3
  188. package/dist/providers/qwen-code.js.map +1 -1
  189. package/dist/providers/registry.d.ts.map +1 -1
  190. package/dist/providers/registry.js +2 -0
  191. package/dist/providers/registry.js.map +1 -1
  192. package/dist/providers/result-helpers.d.ts +2 -1
  193. package/dist/providers/result-helpers.d.ts.map +1 -1
  194. package/dist/providers/result-helpers.js +6 -1
  195. package/dist/providers/result-helpers.js.map +1 -1
  196. package/dist/providers/synthetic.d.ts.map +1 -1
  197. package/dist/providers/synthetic.js +7 -1
  198. package/dist/providers/synthetic.js.map +1 -1
  199. package/dist/providers/zai.d.ts.map +1 -1
  200. package/dist/providers/zai.js +7 -1
  201. package/dist/providers/zai.js.map +1 -1
  202. package/dist/providers/zhipu.d.ts.map +1 -1
  203. package/dist/providers/zhipu.js +7 -1
  204. package/dist/providers/zhipu.js.map +1 -1
  205. package/dist/tui.d.ts.map +1 -1
  206. package/dist/tui.js +148 -122
  207. package/dist/tui.tsx +122 -114
  208. package/package.json +29 -21
@@ -1,4 +1,4 @@
1
- import { stat } from "fs/promises";
1
+ import { readFile, stat } from "fs/promises";
2
2
  import { getAuthPath, getAuthPaths, readAuthFileCached } from "./opencode-auth.js";
3
3
  import { getOpencodeRuntimeDirs } from "./opencode-runtime-paths.js";
4
4
  import { getGoogleTokenCachePath } from "./google-token-cache.js";
@@ -14,7 +14,7 @@ import { getNanoGptKeyDiagnostics, queryNanoGptQuota } from "./nanogpt.js";
14
14
  import { getDeepSeekKeyDiagnostics } from "./deepseek.js";
15
15
  import { getSyntheticKeyDiagnostics } from "./synthetic.js";
16
16
  import { getCopilotQuotaAuthDiagnostics } from "./copilot.js";
17
- import { computeAlibabaCodingPlanQuota, computeQwenQuota, getAlibabaCodingPlanQuotaPath, getQwenLocalQuotaPath, readAlibabaCodingPlanQuotaState, readQwenLocalQuotaState, } from "./qwen-local-quota.js";
17
+ import { ALIBABA_CODING_PLAN_STATE_VERSION, QWEN_LOCAL_QUOTA_STATE_VERSION, getAlibabaCodingPlanQuotaPath, getQwenLocalQuotaPath, } from "./qwen-local-quota.js";
18
18
  import { DEFAULT_ALIBABA_AUTH_CACHE_MAX_AGE_MS, getAlibabaCodingPlanAuthDiagnostics, resolveAlibabaCodingPlanAuthCached, } from "./alibaba-auth.js";
19
19
  import { hasQwenOAuthAuth, resolveQwenLocalPlan } from "./qwen-auth.js";
20
20
  import { resolveOpenAIOAuth } from "./openai.js";
@@ -38,6 +38,8 @@ import { sanitizeSingleLineDisplaySnippet, sanitizeSingleLineDisplayText, saniti
38
38
  import { QUOTA_TOAST_SETTING_SOURCE_KEYS, } from "./config.js";
39
39
  import { getCursorPlanDisplayName, getEffectiveCursorIncludedApiUsd } from "./cursor-pricing.js";
40
40
  import { getQuotaProviderDisplayLabel } from "./provider-metadata.js";
41
+ import { isMaintainedQuotaProviderTuning } from "./quota-providers.js";
42
+ import { inspectLocalQuotaProviderState } from "./quota-providers-local.js";
41
43
  import { isValueEntry } from "./entries.js";
42
44
  import { queryMiniMaxQuota } from "../providers/minimax-coding-plan.js";
43
45
  import { queryZaiQuota } from "./zai.js";
@@ -53,6 +55,37 @@ async function pathExists(path) {
53
55
  return false;
54
56
  }
55
57
  }
58
+ async function inspectGeneratedCounterFile(path, expectedVersion) {
59
+ try {
60
+ const parsed = JSON.parse(await readFile(path, "utf8"));
61
+ const record = parsed && typeof parsed === "object" && !Array.isArray(parsed)
62
+ ? parsed
63
+ : null;
64
+ const version = typeof record?.version === "number" ? record.version : null;
65
+ const updatedAt = typeof record?.updatedAt === "number" && Number.isFinite(record.updatedAt)
66
+ ? record.updatedAt
67
+ : null;
68
+ return {
69
+ exists: true,
70
+ health: !record || version === null || updatedAt === null
71
+ ? "malformed"
72
+ : version === expectedVersion
73
+ ? "healthy"
74
+ : "version_mismatch",
75
+ version,
76
+ lastUpdatedAt: updatedAt,
77
+ };
78
+ }
79
+ catch (error) {
80
+ if (error &&
81
+ typeof error === "object" &&
82
+ "code" in error &&
83
+ String(error.code) === "ENOENT") {
84
+ return { exists: false, health: "missing", version: null, lastUpdatedAt: null };
85
+ }
86
+ return { exists: true, health: "malformed", version: null, lastUpdatedAt: null };
87
+ }
88
+ }
56
89
  function fmtInt(n) {
57
90
  return Math.trunc(n).toLocaleString("en-US");
58
91
  }
@@ -78,7 +111,9 @@ function isDefaultOpenCodeGoStatusWindowSelection(windows) {
78
111
  OPENCODE_GO_STATUS_WINDOW_ORDER.every((window) => selected.has(window)));
79
112
  }
80
113
  function formatOpenCodeGoMissingWindows(windows) {
81
- return windows.map((window) => `${window} (${OPENCODE_GO_STATUS_WINDOW_FIELDS[window]})`).join(", ");
114
+ return windows
115
+ .map((window) => `${window} (${OPENCODE_GO_STATUS_WINDOW_FIELDS[window]})`)
116
+ .join(", ");
82
117
  }
83
118
  function formatOpenCodeGoUsage(window) {
84
119
  return `percent_used=${window.usagePercent} percent_remaining=${window.percentRemaining} reset_in_sec=${window.resetInSec} reset_at=${window.resetTimeIso}`;
@@ -148,6 +183,17 @@ function isRedundantLiveProbeDescriptor(providerId, value) {
148
183
  function findProviderLiveProbe(providerId, probes) {
149
184
  return probes?.find((probe) => probe.providerId === providerId);
150
185
  }
186
+ function getLiveProbeState(probe) {
187
+ if (!probe)
188
+ return "unavailable";
189
+ if (probe.result.entries.length > 0 && probe.result.errors.length > 0)
190
+ return "partial";
191
+ if (probe.result.entries.length > 0)
192
+ return "success";
193
+ if (probe.result.errors.length > 0)
194
+ return "error";
195
+ return "no_data";
196
+ }
151
197
  function appendProviderCompactLiveProbeRows(rows, providerId, probes) {
152
198
  appendCompactLiveProbeRows(rows, providerId, findProviderLiveProbe(providerId, probes));
153
199
  }
@@ -203,13 +249,113 @@ function formatCompactLiveProbeError(providerId, error) {
203
249
  const message = sanitizeSingleLineDisplayText(error.message);
204
250
  return sanitizeSingleLineDisplaySnippet(label ? `${label}: ${message}` : message, STATUS_LIVE_ROW_MAX_LENGTH);
205
251
  }
252
+ function getQuotaProviderCredentialCategory(source) {
253
+ switch (source) {
254
+ case "explicit_env":
255
+ return "environment";
256
+ case "global_opencode_json":
257
+ case "global_opencode_jsonc":
258
+ return "trusted_global_config";
259
+ case "auth_json":
260
+ return "auth_json";
261
+ default:
262
+ return "none";
263
+ }
264
+ }
265
+ async function createQuotaProvidersSection(params) {
266
+ if (params.definitions.length === 0)
267
+ return null;
268
+ const diagnostics = findProviderLiveProbe("quota-providers", params.probes)?.result.diagnostics ?? [];
269
+ const diagnosticsBySource = new Map(diagnostics.map((diagnostic) => [diagnostic.sourceId, diagnostic]));
270
+ const rows = [];
271
+ for (const definition of params.definitions) {
272
+ const diagnostic = diagnosticsBySource.get(definition.id);
273
+ const coverage = definition.modelIds ? definition.modelIds.join(",") : "all_models";
274
+ if (definition.mode === "local-estimate" && isMaintainedQuotaProviderTuning(definition)) {
275
+ const maintained = definition.id === "qwen-code"
276
+ ? {
277
+ path: getQwenLocalQuotaPath(),
278
+ version: QWEN_LOCAL_QUOTA_STATE_VERSION,
279
+ }
280
+ : {
281
+ path: getAlibabaCodingPlanQuotaPath(),
282
+ version: ALIBABA_CODING_PLAN_STATE_VERSION,
283
+ };
284
+ const state = await inspectGeneratedCounterFile(maintained.path, maintained.version);
285
+ const probe = findProviderLiveProbe(definition.id, params.probes);
286
+ rows.push({
287
+ key: `provider_${definition.id}`,
288
+ value: [
289
+ `provider_id=${definition.providerId}`,
290
+ "mode=local-estimate",
291
+ `coverage=${coverage}`,
292
+ `outcome=${getLiveProbeState(probe)}`,
293
+ `limits=${definition.windows.map((window) => `${window.id}:${window.requestLimit}`).join(",")}`,
294
+ `state_path=${maintained.path}`,
295
+ `state_exists=${state.exists ? "true" : "false"}`,
296
+ `state_health=${state.health}`,
297
+ `state_version=${state.version ?? "(none)"}`,
298
+ `state_last_update=${state.lastUpdatedAt === null ? "(none)" : new Date(state.lastUpdatedAt).toISOString()}`,
299
+ ]
300
+ .map((part) => sanitizeSingleLineDisplayText(part))
301
+ .join(" "),
302
+ });
303
+ continue;
304
+ }
305
+ if (definition.mode === "local-estimate") {
306
+ const state = await inspectLocalQuotaProviderState(definition);
307
+ rows.push({
308
+ key: `provider_${definition.id}`,
309
+ value: [
310
+ `provider_id=${definition.providerId}`,
311
+ "mode=local-estimate",
312
+ `coverage=${coverage}`,
313
+ `outcome=${diagnostic?.outcome ?? "unavailable"}`,
314
+ `state_path=${state.path}`,
315
+ `state_exists=${state.exists ? "true" : "false"}`,
316
+ `state_health=${state.health}`,
317
+ `state_version=${state.version ?? "(none)"}`,
318
+ `state_last_update=${state.lastUpdatedAt === null ? "(none)" : new Date(state.lastUpdatedAt).toISOString()}`,
319
+ ]
320
+ .map((part) => sanitizeSingleLineDisplayText(part))
321
+ .join(" "),
322
+ });
323
+ continue;
324
+ }
325
+ const checkedPaths = diagnostic
326
+ ? [...new Set([...diagnostic.checkedPaths, ...diagnostic.authPaths])]
327
+ : [];
328
+ rows.push({
329
+ key: `provider_${definition.id}`,
330
+ value: [
331
+ `provider_id=${definition.providerId}`,
332
+ "mode=remote-api",
333
+ `format=${definition.format}`,
334
+ `coverage=${coverage}`,
335
+ `outcome=${diagnostic?.outcome ?? "unavailable"}`,
336
+ `credential_category=${getQuotaProviderCredentialCategory(diagnostic?.credentialSource ?? null)}`,
337
+ `env_name=${definition.apiKeyEnv ?? "(none)"}`,
338
+ `checked_paths=${checkedPaths.length > 0 ? checkedPaths.join(" | ") : "(none)"}`,
339
+ ]
340
+ .map((part) => sanitizeSingleLineDisplayText(part))
341
+ .join(" "),
342
+ });
343
+ }
344
+ return createKvSection("quota_providers", "quota_providers:", rows);
345
+ }
206
346
  function appendCompactLiveProbeRows(rows, providerId, probe) {
207
347
  if (!probe)
208
348
  return;
209
349
  const result = sanitizeQuotaProviderResult(probe.result);
210
350
  const entryCount = Math.min(result.entries.length, STATUS_LIVE_ENTRY_LIMIT);
211
351
  const errorCount = Math.min(result.errors.length, STATUS_LIVE_ERROR_LIMIT);
212
- const state = result.entries.length > 0 ? "success" : result.errors.length > 0 ? "error" : "no_data";
352
+ const state = result.entries.length > 0 && result.errors.length > 0
353
+ ? "partial"
354
+ : result.entries.length > 0
355
+ ? "success"
356
+ : result.errors.length > 0
357
+ ? "error"
358
+ : "no_data";
213
359
  rows.push({ key: "live_probe", value: state });
214
360
  for (let index = 0; index < entryCount; index += 1) {
215
361
  rows.push({
@@ -223,7 +369,8 @@ function appendCompactLiveProbeRows(rows, providerId, probe) {
223
369
  value: formatCompactLiveProbeError(providerId, result.errors[index]),
224
370
  });
225
371
  }
226
- const suppressedCount = Math.max(0, result.entries.length - entryCount) + Math.max(0, result.errors.length - errorCount);
372
+ const suppressedCount = Math.max(0, result.entries.length - entryCount) +
373
+ Math.max(0, result.errors.length - errorCount);
227
374
  if (suppressedCount > 0) {
228
375
  rows.push({
229
376
  key: "live_more",
@@ -452,6 +599,13 @@ export async function buildQuotaStatusReport(params) {
452
599
  toastLines.push(` - ${p.id}: ${bits.join(" ")}`);
453
600
  }
454
601
  sections.push(createLinesSection("toast", "toast:", toastLines));
602
+ const quotaProvidersSection = await createQuotaProvidersSection({
603
+ definitions: params.quotaProviders ?? [],
604
+ probes: params.providerLiveProbes,
605
+ });
606
+ if (quotaProvidersSection) {
607
+ sections.push(quotaProvidersSection);
608
+ }
455
609
  if (params.maintainerAnnouncements) {
456
610
  const announcements = params.maintainerAnnouncements;
457
611
  const summary = announcements.summary;
@@ -493,13 +647,16 @@ export async function buildQuotaStatusReport(params) {
493
647
  const openaiAuth = resolveOpenAIOAuth(authData);
494
648
  const alibabaAuthDiagnostics = await getAlibabaCodingPlanAuthDiagnostics({
495
649
  maxAgeMs: DEFAULT_ALIBABA_AUTH_CACHE_MAX_AGE_MS,
496
- fallbackTier: params.alibabaCodingPlanTier,
650
+ fallbackTier: "lite",
497
651
  });
498
652
  const alibabaCodingPlanAuth = await resolveAlibabaCodingPlanAuthCached({
499
653
  maxAgeMs: DEFAULT_ALIBABA_AUTH_CACHE_MAX_AGE_MS,
500
- fallbackTier: params.alibabaCodingPlanTier,
654
+ fallbackTier: "lite",
655
+ });
656
+ pathsRows.push({
657
+ key: "qwen oauth auth configured",
658
+ value: qwenAuthConfigured ? "true" : "false",
501
659
  });
502
- pathsRows.push({ key: "qwen oauth auth configured", value: qwenAuthConfigured ? "true" : "false" });
503
660
  pathsRows.push({
504
661
  key: "qwen_oauth_source",
505
662
  value: qwenLocalPlan.state === "qwen_free" ? qwenLocalPlan.sourceKey : "(none)",
@@ -512,7 +669,10 @@ export async function buildQuotaStatusReport(params) {
512
669
  key: "alibaba auth configured",
513
670
  value: alibabaAuthDiagnostics.state === "none" ? "false" : "true",
514
671
  });
515
- pathsRows.push({ key: "alibaba_api_key_source", value: alibabaAuthDiagnostics.source ?? "(none)" });
672
+ pathsRows.push({
673
+ key: "alibaba_api_key_source",
674
+ value: alibabaAuthDiagnostics.source ?? "(none)",
675
+ });
516
676
  pathsRows.push({
517
677
  key: "alibaba_api_key_checked_paths",
518
678
  value: joinOrNone(alibabaAuthDiagnostics.checkedPaths),
@@ -521,10 +681,6 @@ export async function buildQuotaStatusReport(params) {
521
681
  key: "alibaba_api_key_auth_paths",
522
682
  value: joinOrNone(alibabaAuthDiagnostics.authPaths),
523
683
  });
524
- pathsRows.push({
525
- key: "alibaba coding plan fallback tier",
526
- value: params.alibabaCodingPlanTier,
527
- });
528
684
  pathsRows.push({
529
685
  key: "alibaba_coding_plan",
530
686
  value: alibabaAuthDiagnostics.state === "configured"
@@ -651,14 +807,20 @@ export async function buildQuotaStatusReport(params) {
651
807
  if (cursorAuth.error) {
652
808
  cursorRows.push({ key: "auth_error", value: cursorAuth.error });
653
809
  }
654
- cursorRows.push({ key: "plugin_enabled", value: cursorIntegration.pluginEnabled ? "true" : "false" });
810
+ cursorRows.push({
811
+ key: "plugin_enabled",
812
+ value: cursorIntegration.pluginEnabled ? "true" : "false",
813
+ });
655
814
  cursorRows.push({ key: "canonical_plugin_package", value: CURSOR_CANONICAL_PLUGIN_PACKAGE });
656
815
  cursorRows.push({
657
816
  key: "provider_configured",
658
817
  value: cursorIntegration.providerConfigured ? "true" : "false",
659
818
  });
660
819
  cursorRows.push({ key: "config_matches", value: joinOrNone(cursorIntegration.matchedPaths) });
661
- cursorRows.push({ key: "config_checked_paths", value: joinOrNone(cursorIntegration.checkedPaths) });
820
+ cursorRows.push({
821
+ key: "config_checked_paths",
822
+ value: joinOrNone(cursorIntegration.checkedPaths),
823
+ });
662
824
  try {
663
825
  const cursorUsage = await getCurrentCursorUsageSummary({
664
826
  billingCycleStartDay: params.cursorBillingCycleStartDay,
@@ -677,56 +839,40 @@ export async function buildQuotaStatusReport(params) {
677
839
  key: "total_cursor_usage",
678
840
  value: `${fmtUsdAmount(cursorUsage.total.costUsd)} across ${fmtInt(cursorUsage.total.messageCount)} messages`,
679
841
  });
680
- cursorRows.push({ key: "unknown_cursor_models", value: fmtInt(cursorUsage.unknownModels.length) });
842
+ cursorRows.push({
843
+ key: "unknown_cursor_models",
844
+ value: fmtInt(cursorUsage.unknownModels.length),
845
+ });
681
846
  }
682
847
  catch (err) {
683
848
  const msg = err instanceof Error ? err.message : String(err);
684
849
  cursorRows.push({ key: "usage_error", value: msg });
685
850
  }
686
851
  const qwenLocalQuotaPath = getQwenLocalQuotaPath();
687
- const qwenLocalQuotaExists = await pathExists(qwenLocalQuotaPath);
852
+ const qwenCounter = await inspectGeneratedCounterFile(qwenLocalQuotaPath, QWEN_LOCAL_QUOTA_STATE_VERSION);
688
853
  cursorRows.push({
689
854
  key: "qwen free local quota",
690
- value: `path=${qwenLocalQuotaPath} exists=${qwenLocalQuotaExists ? "true" : "false"}`,
855
+ value: [
856
+ `path=${qwenLocalQuotaPath}`,
857
+ `exists=${qwenCounter.exists ? "true" : "false"}`,
858
+ `health=${qwenCounter.health}`,
859
+ `version=${qwenCounter.version ?? "(none)"}`,
860
+ `last_update=${qwenCounter.lastUpdatedAt === null ? "(none)" : new Date(qwenCounter.lastUpdatedAt).toISOString()}`,
861
+ ].join(" "),
691
862
  });
692
- try {
693
- const qwenState = await readQwenLocalQuotaState();
694
- const qwenQuota = computeQwenQuota({ state: qwenState });
695
- const qwenUsageSuffix = qwenLocalQuotaExists ? "" : " (default state)";
696
- cursorRows.push({
697
- key: "qwen free local usage",
698
- value: `daily=${qwenQuota.day.used}/${qwenQuota.day.limit} rpm=${qwenQuota.rpm.used}/${qwenQuota.rpm.limit}${qwenUsageSuffix}`,
699
- });
700
- }
701
- catch (err) {
702
- const msg = err instanceof Error ? err.message : String(err);
703
- cursorRows.push({ key: "qwen free local usage", value: `error (${msg})` });
704
- }
705
863
  const alibabaLocalQuotaPath = getAlibabaCodingPlanQuotaPath();
706
- const alibabaLocalQuotaExists = await pathExists(alibabaLocalQuotaPath);
864
+ const alibabaCounter = await inspectGeneratedCounterFile(alibabaLocalQuotaPath, ALIBABA_CODING_PLAN_STATE_VERSION);
707
865
  cursorRows.push({
708
866
  key: "alibaba coding plan local quota",
709
- value: `path=${alibabaLocalQuotaPath} exists=${alibabaLocalQuotaExists ? "true" : "false"}`,
867
+ value: [
868
+ `path=${alibabaLocalQuotaPath}`,
869
+ `exists=${alibabaCounter.exists ? "true" : "false"}`,
870
+ `health=${alibabaCounter.health}`,
871
+ `version=${alibabaCounter.version ?? "(none)"}`,
872
+ `last_update=${alibabaCounter.lastUpdatedAt === null ? "(none)" : new Date(alibabaCounter.lastUpdatedAt).toISOString()}`,
873
+ ].join(" "),
710
874
  });
711
- if (alibabaCodingPlanAuth.state === "configured") {
712
- try {
713
- const alibabaState = await readAlibabaCodingPlanQuotaState();
714
- const alibabaQuota = computeAlibabaCodingPlanQuota({
715
- state: alibabaState,
716
- tier: alibabaCodingPlanAuth.tier,
717
- });
718
- const alibabaUsageSuffix = alibabaLocalQuotaExists ? "" : " (default state)";
719
- cursorRows.push({
720
- key: "alibaba coding plan usage",
721
- value: `tier=${alibabaCodingPlanAuth.tier} 5h=${alibabaQuota.fiveHour.used}/${alibabaQuota.fiveHour.limit} weekly=${alibabaQuota.weekly.used}/${alibabaQuota.weekly.limit} monthly=${alibabaQuota.monthly.used}/${alibabaQuota.monthly.limit}${alibabaUsageSuffix}`,
722
- });
723
- }
724
- catch (err) {
725
- const msg = err instanceof Error ? err.message : String(err);
726
- cursorRows.push({ key: "alibaba coding plan usage", value: `error (${msg})` });
727
- }
728
- }
729
- else if (alibabaCodingPlanAuth.state === "invalid") {
875
+ if (alibabaCodingPlanAuth.state === "invalid") {
730
876
  cursorRows.push({ key: "alibaba coding plan error", value: alibabaCodingPlanAuth.error });
731
877
  }
732
878
  appendProviderCompactLiveProbeRows(cursorRows, "cursor", params.providerLiveProbes);
@@ -881,7 +1027,10 @@ export async function buildQuotaStatusReport(params) {
881
1027
  if (openCodeGoDiag.error) {
882
1028
  openCodeGoRows.push({ key: "config_error", value: sanitizeDisplayText(openCodeGoDiag.error) });
883
1029
  }
884
- openCodeGoRows.push({ key: "config_checked_paths", value: joinOrNone(openCodeGoDiag.checkedPaths) });
1030
+ openCodeGoRows.push({
1031
+ key: "config_checked_paths",
1032
+ value: joinOrNone(openCodeGoDiag.checkedPaths),
1033
+ });
885
1034
  const openCodeGoSelectedWindows = params.opencodeGoWindows ?? OPENCODE_GO_STATUS_WINDOW_ORDER;
886
1035
  openCodeGoRows.push({
887
1036
  key: "selected_windows",
@@ -947,7 +1096,10 @@ export async function buildQuotaStatusReport(params) {
947
1096
  if (zaiAuth.state === "configured") {
948
1097
  const zaiQuota = await queryZaiQuota();
949
1098
  if (!zaiQuota) {
950
- zaiRows.push({ key: "live_fetch_error", value: "Z.ai API key became unavailable before fetch" });
1099
+ zaiRows.push({
1100
+ key: "live_fetch_error",
1101
+ value: "Z.ai API key became unavailable before fetch",
1102
+ });
951
1103
  }
952
1104
  else if (!zaiQuota.success) {
953
1105
  zaiRows.push({ key: "live_fetch_error", value: zaiQuota.error });
@@ -997,7 +1149,10 @@ export async function buildQuotaStatusReport(params) {
997
1149
  if (zhipuAuth.state === "configured") {
998
1150
  const zhipuQuota = await queryZhipuQuota();
999
1151
  if (!zhipuQuota) {
1000
- zhipuRows.push({ key: "live_fetch_error", value: "Zhipu API key became unavailable before fetch" });
1152
+ zhipuRows.push({
1153
+ key: "live_fetch_error",
1154
+ value: "Zhipu API key became unavailable before fetch",
1155
+ });
1001
1156
  }
1002
1157
  else if (!zhipuQuota.success) {
1003
1158
  zhipuRows.push({ key: "live_fetch_error", value: zhipuQuota.error });
@@ -1106,7 +1261,10 @@ export async function buildQuotaStatusReport(params) {
1106
1261
  value: nanoGptQuota.subscription.currentPeriodEndIso ?? "(none)",
1107
1262
  });
1108
1263
  if (nanoGptQuota.subscription.graceUntilIso) {
1109
- nanoGptRows.push({ key: "grace_until", value: nanoGptQuota.subscription.graceUntilIso });
1264
+ nanoGptRows.push({
1265
+ key: "grace_until",
1266
+ value: nanoGptQuota.subscription.graceUntilIso,
1267
+ });
1110
1268
  }
1111
1269
  }
1112
1270
  nanoGptRows.push({
@@ -1115,7 +1273,10 @@ export async function buildQuotaStatusReport(params) {
1115
1273
  ? fmtUsdAmount(nanoGptQuota.balance.usdBalance)
1116
1274
  : "(none)",
1117
1275
  });
1118
- nanoGptRows.push({ key: "balance_nano", value: nanoGptQuota.balance?.nanoBalanceRaw ?? "(none)" });
1276
+ nanoGptRows.push({
1277
+ key: "balance_nano",
1278
+ value: nanoGptQuota.balance?.nanoBalanceRaw ?? "(none)",
1279
+ });
1119
1280
  for (const entry of nanoGptQuota.endpointErrors ?? []) {
1120
1281
  nanoGptRows.push({ key: `live_error_${entry.endpoint}`, value: entry.message });
1121
1282
  }
@@ -1140,6 +1301,9 @@ export async function buildQuotaStatusReport(params) {
1140
1301
  if (copilotDiag.pat.config?.tier) {
1141
1302
  copilotRows.push({ key: "pat_tier", value: copilotDiag.pat.config.tier });
1142
1303
  }
1304
+ if (copilotDiag.billingModel) {
1305
+ copilotRows.push({ key: "billing_model", value: copilotDiag.billingModel });
1306
+ }
1143
1307
  if (copilotDiag.pat.config?.organization) {
1144
1308
  copilotRows.push({ key: "pat_organization", value: copilotDiag.pat.config.organization });
1145
1309
  }
@@ -1149,6 +1313,7 @@ export async function buildQuotaStatusReport(params) {
1149
1313
  copilotRows.push({ key: "billing_mode", value: copilotDiag.billingMode });
1150
1314
  copilotRows.push({ key: "billing_scope", value: copilotDiag.billingScope });
1151
1315
  copilotRows.push({ key: "quota_api", value: copilotDiag.quotaApi });
1316
+ copilotRows.push({ key: "budget_api", value: copilotDiag.budgetApi });
1152
1317
  copilotRows.push({
1153
1318
  key: "billing_api_access_likely",
1154
1319
  value: copilotDiag.billingApiAccessLikely ? "true" : "false",
@@ -1166,41 +1331,47 @@ export async function buildQuotaStatusReport(params) {
1166
1331
  if (copilotDiag.billingMode === "organization_usage") {
1167
1332
  copilotRows.push({
1168
1333
  key: "billing_usage_note",
1169
- value: "organization premium usage for the current billing period",
1334
+ value: "organization AI Credit usage for the current UTC calendar month",
1170
1335
  });
1171
1336
  copilotRows.push({
1172
1337
  key: "remaining_quota_note",
1173
- value: "valid PAT access can query billing usage, but pooled org usage does not provide a true per-user remaining quota",
1338
+ value: "the usage report exposes included-pool consumption and billed usage, but no included-pool denominator; percentages require a real budget",
1174
1339
  });
1175
1340
  }
1176
1341
  if (copilotDiag.billingMode === "enterprise_usage") {
1177
1342
  copilotRows.push({
1178
1343
  key: "billing_usage_note",
1179
- value: "enterprise premium usage for the current billing period",
1344
+ value: "enterprise AI Credit usage for the current UTC calendar month",
1180
1345
  });
1181
1346
  copilotRows.push({
1182
1347
  key: "remaining_quota_note",
1183
- value: "valid enterprise billing access can query pooled enterprise usage, but it does not provide a true per-user remaining quota",
1348
+ value: "the usage report exposes included-pool consumption and billed usage, but no included-pool denominator; percentages require a real budget",
1184
1349
  });
1185
1350
  }
1186
1351
  if (copilotDiag.billingTargetError) {
1187
1352
  copilotRows.push({ key: "billing_target_error", value: copilotDiag.billingTargetError });
1188
1353
  }
1189
1354
  if (copilotDiag.tokenCompatibilityError) {
1190
- copilotRows.push({ key: "token_compatibility_error", value: copilotDiag.tokenCompatibilityError });
1355
+ copilotRows.push({
1356
+ key: "token_compatibility_error",
1357
+ value: copilotDiag.tokenCompatibilityError,
1358
+ });
1191
1359
  }
1192
1360
  if (copilotDiag.pat.error) {
1193
1361
  copilotRows.push({ key: "pat_error", value: copilotDiag.pat.error });
1194
1362
  }
1195
1363
  copilotRows.push({
1196
1364
  key: "pat_checked_paths",
1197
- value: copilotDiag.pat.checkedPaths.length ? copilotDiag.pat.checkedPaths.join(" | ") : "(none)",
1365
+ value: copilotDiag.pat.checkedPaths.length
1366
+ ? copilotDiag.pat.checkedPaths.join(" | ")
1367
+ : "(none)",
1198
1368
  });
1199
1369
  copilotRows.push({
1200
1370
  key: "oauth_configured",
1201
1371
  value: `${copilotDiag.oauth.configured ? "true" : "false"} key=${copilotDiag.oauth.keyName ?? "(none)"} refresh=${copilotDiag.oauth.hasRefreshToken ? "true" : "false"} access=${copilotDiag.oauth.hasAccessToken ? "true" : "false"}`,
1202
1372
  });
1203
1373
  copilotRows.push({ key: "effective_source", value: copilotDiag.effectiveSource });
1374
+ copilotRows.push({ key: "oauth_accounting_state", value: copilotDiag.oauthAccountingState });
1204
1375
  copilotRows.push({ key: "override", value: copilotDiag.override });
1205
1376
  appendProviderCompactLiveProbeRows(copilotRows, "copilot", params.providerLiveProbes);
1206
1377
  sections.push(createKvSection("copilot_quota_auth", "copilot_quota_auth:", copilotRows));
@@ -1226,7 +1397,7 @@ export async function buildQuotaStatusReport(params) {
1226
1397
  {
1227
1398
  key: "companion_package_path",
1228
1399
  value: googleCompanionPresence.state === "present" || googleCompanionPresence.state === "invalid"
1229
- ? googleCompanionPresence.resolvedPath ?? "(none)"
1400
+ ? (googleCompanionPresence.resolvedPath ?? "(none)")
1230
1401
  : "(none)",
1231
1402
  },
1232
1403
  ];
@@ -1260,13 +1431,17 @@ export async function buildQuotaStatusReport(params) {
1260
1431
  { key: "companion_package_state", value: geminiCliCompanionPresence.state },
1261
1432
  {
1262
1433
  key: "companion_package_path",
1263
- value: geminiCliCompanionPresence.state === "present" || geminiCliCompanionPresence.state === "invalid"
1264
- ? geminiCliCompanionPresence.resolvedPath ?? "(none)"
1434
+ value: geminiCliCompanionPresence.state === "present" ||
1435
+ geminiCliCompanionPresence.state === "invalid"
1436
+ ? (geminiCliCompanionPresence.resolvedPath ?? "(none)")
1265
1437
  : "(none)",
1266
1438
  },
1267
1439
  ];
1268
1440
  if (geminiCliAuthPresence.state === "invalid") {
1269
- geminiCliRows.push({ key: "auth_error", value: sanitizeDisplayText(geminiCliAuthPresence.error) });
1441
+ geminiCliRows.push({
1442
+ key: "auth_error",
1443
+ value: sanitizeDisplayText(geminiCliAuthPresence.error),
1444
+ });
1270
1445
  }
1271
1446
  if (geminiCliCompanionPresence.state !== "present") {
1272
1447
  geminiCliRows.push({
@@ -1288,7 +1463,7 @@ export async function buildQuotaStatusReport(params) {
1288
1463
  {
1289
1464
  key: "companion_package_path",
1290
1465
  value: agyCompanionPresence.state === "present" || agyCompanionPresence.state === "invalid"
1291
- ? agyCompanionPresence.resolvedPath ?? "(none)"
1466
+ ? (agyCompanionPresence.resolvedPath ?? "(none)")
1292
1467
  : "(none)",
1293
1468
  },
1294
1469
  ];
@@ -1327,7 +1502,10 @@ export async function buildQuotaStatusReport(params) {
1327
1502
  { key: "error", value: params.sessionTokenError.error },
1328
1503
  ];
1329
1504
  if (params.sessionTokenError.checkedPath) {
1330
- sessionTokenErrorRows.push({ key: "checked_path", value: params.sessionTokenError.checkedPath });
1505
+ sessionTokenErrorRows.push({
1506
+ key: "checked_path",
1507
+ value: params.sessionTokenError.checkedPath,
1508
+ });
1331
1509
  }
1332
1510
  sections.push(createKvSection("session_tokens_error", "session_tokens_error:", sessionTokenErrorRows));
1333
1511
  }