@slkiser/opencode-quota 2.16.0 → 3.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.
- package/README.md +145 -49
- package/dist/bin/opencode-quota.d.ts +3 -0
- package/dist/bin/opencode-quota.d.ts.map +1 -0
- package/dist/bin/opencode-quota.js +37 -0
- package/dist/bin/opencode-quota.js.map +1 -0
- package/dist/lib/config-file-utils.d.ts +18 -0
- package/dist/lib/config-file-utils.d.ts.map +1 -0
- package/dist/lib/config-file-utils.js +88 -0
- package/dist/lib/config-file-utils.js.map +1 -0
- package/dist/lib/config.d.ts +10 -7
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +111 -31
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/cursor-detection.d.ts +1 -0
- package/dist/lib/cursor-detection.d.ts.map +1 -1
- package/dist/lib/cursor-detection.js +16 -8
- package/dist/lib/cursor-detection.js.map +1 -1
- package/dist/lib/display-sanitize.d.ts +7 -0
- package/dist/lib/display-sanitize.d.ts.map +1 -1
- package/dist/lib/display-sanitize.js +49 -0
- package/dist/lib/display-sanitize.js.map +1 -1
- package/dist/lib/entries.d.ts +1 -1
- package/dist/lib/entries.d.ts.map +1 -1
- package/dist/lib/format.js +1 -1
- package/dist/lib/format.js.map +1 -1
- package/dist/lib/google-antigravity-companion.d.ts +29 -0
- package/dist/lib/google-antigravity-companion.d.ts.map +1 -0
- package/dist/lib/google-antigravity-companion.js +122 -0
- package/dist/lib/google-antigravity-companion.js.map +1 -0
- package/dist/lib/google.d.ts +1 -0
- package/dist/lib/google.d.ts.map +1 -1
- package/dist/lib/google.js +54 -16
- package/dist/lib/google.js.map +1 -1
- package/dist/lib/grouped-entry-normalization.d.ts.map +1 -1
- package/dist/lib/grouped-entry-normalization.js +83 -23
- package/dist/lib/grouped-entry-normalization.js.map +1 -1
- package/dist/lib/init-installer.d.ts +101 -0
- package/dist/lib/init-installer.d.ts.map +1 -0
- package/dist/lib/init-installer.js +507 -0
- package/dist/lib/init-installer.js.map +1 -0
- package/dist/lib/provider-metadata.d.ts +1 -0
- package/dist/lib/provider-metadata.d.ts.map +1 -1
- package/dist/lib/provider-metadata.js +5 -0
- package/dist/lib/provider-metadata.js.map +1 -1
- package/dist/lib/quota-render-data.d.ts +72 -0
- package/dist/lib/quota-render-data.d.ts.map +1 -0
- package/dist/lib/quota-render-data.js +315 -0
- package/dist/lib/quota-render-data.js.map +1 -0
- package/dist/lib/quota-status.d.ts +9 -0
- package/dist/lib/quota-status.d.ts.map +1 -1
- package/dist/lib/quota-status.js +39 -1
- package/dist/lib/quota-status.js.map +1 -1
- package/dist/lib/session-tokens-format.d.ts +16 -3
- package/dist/lib/session-tokens-format.d.ts.map +1 -1
- package/dist/lib/session-tokens-format.js +65 -11
- package/dist/lib/session-tokens-format.js.map +1 -1
- package/dist/lib/toast-format-grouped.js +1 -1
- package/dist/lib/toast-format-grouped.js.map +1 -1
- package/dist/lib/tui-config-diagnostics.d.ts +12 -0
- package/dist/lib/tui-config-diagnostics.d.ts.map +1 -0
- package/dist/lib/tui-config-diagnostics.js +49 -0
- package/dist/lib/tui-config-diagnostics.js.map +1 -0
- package/dist/lib/tui-line-style.d.ts +3 -0
- package/dist/lib/tui-line-style.d.ts.map +1 -0
- package/dist/lib/tui-line-style.js +7 -0
- package/dist/lib/tui-line-style.js.map +1 -0
- package/dist/lib/tui-panel-state.d.ts +7 -0
- package/dist/lib/tui-panel-state.d.ts.map +1 -0
- package/dist/lib/tui-panel-state.js +13 -0
- package/dist/lib/tui-panel-state.js.map +1 -0
- package/dist/lib/tui-runtime.d.ts +11 -0
- package/dist/lib/tui-runtime.d.ts.map +1 -0
- package/dist/lib/tui-runtime.js +107 -0
- package/dist/lib/tui-runtime.js.map +1 -0
- package/dist/lib/tui-sidebar-format.d.ts +13 -0
- package/dist/lib/tui-sidebar-format.d.ts.map +1 -0
- package/dist/lib/tui-sidebar-format.js +29 -0
- package/dist/lib/tui-sidebar-format.js.map +1 -0
- package/dist/lib/types.d.ts +8 -5
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/lib/types.js +2 -2
- package/dist/lib/types.js.map +1 -1
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +66 -320
- package/dist/plugin.js.map +1 -1
- package/dist/providers/alibaba-coding-plan.d.ts.map +1 -1
- package/dist/providers/alibaba-coding-plan.js +12 -19
- package/dist/providers/alibaba-coding-plan.js.map +1 -1
- package/dist/providers/anthropic.d.ts.map +1 -1
- package/dist/providers/anthropic.js +12 -19
- package/dist/providers/anthropic.js.map +1 -1
- package/dist/providers/chutes.d.ts.map +1 -1
- package/dist/providers/chutes.js +10 -17
- package/dist/providers/chutes.js.map +1 -1
- package/dist/providers/copilot.js +1 -1
- package/dist/providers/copilot.js.map +1 -1
- package/dist/providers/cursor.js +1 -1
- package/dist/providers/cursor.js.map +1 -1
- package/dist/providers/firmware.d.ts.map +1 -1
- package/dist/providers/firmware.js +11 -18
- package/dist/providers/firmware.js.map +1 -1
- package/dist/providers/google-antigravity.js +4 -4
- package/dist/providers/google-antigravity.js.map +1 -1
- package/dist/providers/minimax-coding-plan.d.ts.map +1 -1
- package/dist/providers/minimax-coding-plan.js +14 -29
- package/dist/providers/minimax-coding-plan.js.map +1 -1
- package/dist/providers/nanogpt.d.ts.map +1 -1
- package/dist/providers/nanogpt.js +5 -12
- package/dist/providers/nanogpt.js.map +1 -1
- package/dist/providers/openai.d.ts.map +1 -1
- package/dist/providers/openai.js +13 -28
- package/dist/providers/openai.js.map +1 -1
- package/dist/providers/opencode-go.d.ts.map +1 -1
- package/dist/providers/opencode-go.js +15 -40
- package/dist/providers/opencode-go.js.map +1 -1
- package/dist/providers/qwen-code.d.ts.map +1 -1
- package/dist/providers/qwen-code.js +16 -19
- package/dist/providers/qwen-code.js.map +1 -1
- package/dist/providers/result-helpers.d.ts +5 -0
- package/dist/providers/result-helpers.d.ts.map +1 -0
- package/dist/providers/result-helpers.js +10 -0
- package/dist/providers/result-helpers.js.map +1 -0
- package/dist/providers/zai.d.ts.map +1 -1
- package/dist/providers/zai.js +13 -28
- package/dist/providers/zai.js.map +1 -1
- package/dist/tui.d.ts +7 -0
- package/dist/tui.d.ts.map +1 -0
- package/dist/tui.tsx +155 -0
- package/package.json +27 -9
package/dist/plugin.js
CHANGED
|
@@ -13,12 +13,11 @@ import { formatQuotaCommand } from "./lib/quota-command-format.js";
|
|
|
13
13
|
import { getProviders } from "./providers/registry.js";
|
|
14
14
|
import { tool } from "@opencode-ai/plugin";
|
|
15
15
|
import { aggregateUsage, resolveSessionTree, SessionNotFoundError, } from "./lib/quota-stats.js";
|
|
16
|
-
import { fetchSessionTokensForDisplay } from "./lib/session-tokens.js";
|
|
17
16
|
import { formatQuotaStatsReport } from "./lib/quota-stats-format.js";
|
|
18
17
|
import { buildQuotaStatusReport } from "./lib/quota-status.js";
|
|
18
|
+
import { inspectTuiConfig } from "./lib/tui-config-diagnostics.js";
|
|
19
19
|
import { getPricingSnapshotMeta, getPricingSnapshotSource, getRuntimePricingRefreshStatePath, getRuntimePricingSnapshotPath, maybeRefreshPricingSnapshot, setPricingSnapshotAutoRefresh, setPricingSnapshotSelection, } from "./lib/modelsdev-pricing.js";
|
|
20
20
|
import { refreshGoogleTokensForAllAccounts } from "./lib/google.js";
|
|
21
|
-
import { getQuotaProviderDisplayLabel } from "./lib/provider-metadata.js";
|
|
22
21
|
import { DEFAULT_ALIBABA_AUTH_CACHE_MAX_AGE_MS, isAlibabaModelId, resolveAlibabaCodingPlanAuthCached, } from "./lib/alibaba-auth.js";
|
|
23
22
|
import { isQwenCodeModelId, resolveQwenLocalPlanCached } from "./lib/qwen-auth.js";
|
|
24
23
|
import { recordAlibabaCodingPlanCompletion, recordQwenCompletion } from "./lib/qwen-local-quota.js";
|
|
@@ -27,7 +26,7 @@ import { parseOptionalJsonArgs, parseQuotaBetweenArgs, startOfLocalDayMs, startO
|
|
|
27
26
|
import { handled } from "./lib/command-handled.js";
|
|
28
27
|
import { renderCommandHeading } from "./lib/format-utils.js";
|
|
29
28
|
import { sanitizeDisplayText } from "./lib/display-sanitize.js";
|
|
30
|
-
import {
|
|
29
|
+
import { collectQuotaRenderData, matchesQuotaProviderCurrentSelection, resolveQuotaRenderSelection, } from "./lib/quota-render-data.js";
|
|
31
30
|
/** All token report command specifications */
|
|
32
31
|
const TOKEN_REPORT_COMMANDS = [
|
|
33
32
|
{
|
|
@@ -243,101 +242,6 @@ export const QuotaToastPlugin = async ({ client }) => {
|
|
|
243
242
|
return false;
|
|
244
243
|
return true;
|
|
245
244
|
}
|
|
246
|
-
function makeProviderFetchCacheKey(providerId, ctx) {
|
|
247
|
-
const style = ctx.config.toastStyle ?? "classic";
|
|
248
|
-
const googleModels = ctx.config.googleModels.join(",");
|
|
249
|
-
const alibabaCodingPlanTier = ctx.config.alibabaCodingPlanTier;
|
|
250
|
-
const cursorPlan = ctx.config.cursorPlan;
|
|
251
|
-
const cursorIncludedApiUsd = ctx.config.cursorIncludedApiUsd ?? "";
|
|
252
|
-
const cursorBillingCycleStartDay = ctx.config.cursorBillingCycleStartDay ?? "";
|
|
253
|
-
const onlyCurrentModel = ctx.config.onlyCurrentModel ? "yes" : "no";
|
|
254
|
-
const currentModel = ctx.config.currentModel ?? "";
|
|
255
|
-
const currentProviderID = ctx.config.currentProviderID ?? "";
|
|
256
|
-
const anthropicBinaryPath = ctx.config.anthropicBinaryPath ?? "";
|
|
257
|
-
return `${providerId}|style=${style}|anthropicBinaryPath=${anthropicBinaryPath}|googleModels=${googleModels}|alibabaTier=${alibabaCodingPlanTier}|cursorPlan=${cursorPlan}|cursorIncludedApiUsd=${cursorIncludedApiUsd}|cursorBillingCycleStartDay=${cursorBillingCycleStartDay}|onlyCurrentModel=${onlyCurrentModel}|currentModel=${currentModel}|currentProviderID=${currentProviderID}`;
|
|
258
|
-
}
|
|
259
|
-
async function fetchProviderWithCache(params) {
|
|
260
|
-
const { provider, ctx, ttlMs } = params;
|
|
261
|
-
// Live local-usage providers should update per completion for accurate local reports.
|
|
262
|
-
if (LIVE_LOCAL_USAGE_PROVIDER_IDS.has(provider.id)) {
|
|
263
|
-
return await provider.fetch(ctx);
|
|
264
|
-
}
|
|
265
|
-
const cacheKey = makeProviderFetchCacheKey(provider.id, ctx);
|
|
266
|
-
const now = Date.now();
|
|
267
|
-
const existing = providerFetchCache.get(cacheKey);
|
|
268
|
-
if (existing?.result &&
|
|
269
|
-
existing.timestamp > 0 &&
|
|
270
|
-
ttlMs > 0 &&
|
|
271
|
-
now - existing.timestamp < ttlMs) {
|
|
272
|
-
return existing.result;
|
|
273
|
-
}
|
|
274
|
-
if (existing?.inFlight) {
|
|
275
|
-
return existing.inFlight;
|
|
276
|
-
}
|
|
277
|
-
const promise = (async () => {
|
|
278
|
-
try {
|
|
279
|
-
const result = await provider.fetch(ctx);
|
|
280
|
-
if (result.attempted) {
|
|
281
|
-
providerFetchCache.set(cacheKey, { timestamp: Date.now(), result });
|
|
282
|
-
}
|
|
283
|
-
else {
|
|
284
|
-
providerFetchCache.delete(cacheKey);
|
|
285
|
-
}
|
|
286
|
-
return result;
|
|
287
|
-
}
|
|
288
|
-
catch (err) {
|
|
289
|
-
providerFetchCache.delete(cacheKey);
|
|
290
|
-
throw err;
|
|
291
|
-
}
|
|
292
|
-
})();
|
|
293
|
-
providerFetchCache.set(cacheKey, {
|
|
294
|
-
timestamp: existing?.timestamp ?? 0,
|
|
295
|
-
result: existing?.result,
|
|
296
|
-
inFlight: promise,
|
|
297
|
-
});
|
|
298
|
-
return promise;
|
|
299
|
-
}
|
|
300
|
-
function makeProviderFetchFailure(provider) {
|
|
301
|
-
return {
|
|
302
|
-
attempted: true,
|
|
303
|
-
entries: [],
|
|
304
|
-
errors: [
|
|
305
|
-
{
|
|
306
|
-
label: getQuotaProviderDisplayLabel(provider.id),
|
|
307
|
-
message: "Failed to read quota data",
|
|
308
|
-
},
|
|
309
|
-
],
|
|
310
|
-
};
|
|
311
|
-
}
|
|
312
|
-
async function fetchProviderResults(params) {
|
|
313
|
-
const settled = await Promise.allSettled(params.providers.map((provider) => fetchProviderWithCache({
|
|
314
|
-
provider,
|
|
315
|
-
ctx: params.ctx,
|
|
316
|
-
ttlMs: params.ttlMs,
|
|
317
|
-
})));
|
|
318
|
-
return settled.map((result, index) => result.status === "fulfilled"
|
|
319
|
-
? result.value
|
|
320
|
-
: makeProviderFetchFailure(params.providers[index]));
|
|
321
|
-
}
|
|
322
|
-
function getExplicitNoDataMessage(provider) {
|
|
323
|
-
if (provider.id === "cursor") {
|
|
324
|
-
return "No local usage yet";
|
|
325
|
-
}
|
|
326
|
-
if (provider.id === "anthropic") {
|
|
327
|
-
return getAnthropicNoDataMessage();
|
|
328
|
-
}
|
|
329
|
-
return "Not configured";
|
|
330
|
-
}
|
|
331
|
-
function shouldSurfaceNoDataMessage(params) {
|
|
332
|
-
const { provider, result, isAutoMode, activeProviderCount } = params;
|
|
333
|
-
if (result.attempted || result.entries.length > 0 || result.errors.length > 0) {
|
|
334
|
-
return false;
|
|
335
|
-
}
|
|
336
|
-
if (!isAutoMode) {
|
|
337
|
-
return true;
|
|
338
|
-
}
|
|
339
|
-
return activeProviderCount === 1 && (provider.id === "anthropic" || provider.id === "cursor");
|
|
340
|
-
}
|
|
341
245
|
function isProviderEnabled(providerId) {
|
|
342
246
|
return config.enabledProviders === "auto" || config.enabledProviders.includes(providerId);
|
|
343
247
|
}
|
|
@@ -514,16 +418,6 @@ export const QuotaToastPlugin = async ({ client }) => {
|
|
|
514
418
|
return {};
|
|
515
419
|
}
|
|
516
420
|
}
|
|
517
|
-
function matchesProviderCurrentSelection(params) {
|
|
518
|
-
if (params.provider.id === "cursor" && isCursorProviderId(params.currentProviderID)) {
|
|
519
|
-
return true;
|
|
520
|
-
}
|
|
521
|
-
if (!params.currentModel)
|
|
522
|
-
return false;
|
|
523
|
-
return params.provider.matchesCurrentModel
|
|
524
|
-
? params.provider.matchesCurrentModel(params.currentModel)
|
|
525
|
-
: true;
|
|
526
|
-
}
|
|
527
421
|
function formatDebugInfo(params) {
|
|
528
422
|
const availability = params.availability
|
|
529
423
|
? params.availability.map((x) => `${x.id}=${x.ok ? "ok" : "no"}`).join(" ")
|
|
@@ -543,55 +437,6 @@ export const QuotaToastPlugin = async ({ client }) => {
|
|
|
543
437
|
`available=${availability}`,
|
|
544
438
|
].join("\n");
|
|
545
439
|
}
|
|
546
|
-
async function resolveQuotaCommandSelection(params = {}) {
|
|
547
|
-
if (!configLoaded)
|
|
548
|
-
await refreshConfig();
|
|
549
|
-
if (!config.enabled)
|
|
550
|
-
return null;
|
|
551
|
-
const allProviders = getProviders();
|
|
552
|
-
const isAutoMode = config.enabledProviders === "auto";
|
|
553
|
-
const providers = isAutoMode
|
|
554
|
-
? allProviders
|
|
555
|
-
: allProviders.filter((p) => config.enabledProviders.includes(p.id));
|
|
556
|
-
if (!isAutoMode && providers.length === 0)
|
|
557
|
-
return null;
|
|
558
|
-
let currentModel;
|
|
559
|
-
let currentProviderID;
|
|
560
|
-
if (config.onlyCurrentModel && params.sessionID) {
|
|
561
|
-
const currentSession = params.sessionMeta ?? (await getSessionModelMeta(params.sessionID));
|
|
562
|
-
currentModel = currentSession.modelID;
|
|
563
|
-
currentProviderID = currentSession.providerID;
|
|
564
|
-
}
|
|
565
|
-
const ctx = {
|
|
566
|
-
client: typedClient,
|
|
567
|
-
config: {
|
|
568
|
-
googleModels: config.googleModels,
|
|
569
|
-
anthropicBinaryPath: config.anthropicBinaryPath,
|
|
570
|
-
alibabaCodingPlanTier: config.alibabaCodingPlanTier,
|
|
571
|
-
cursorPlan: config.cursorPlan,
|
|
572
|
-
cursorIncludedApiUsd: config.cursorIncludedApiUsd,
|
|
573
|
-
cursorBillingCycleStartDay: config.cursorBillingCycleStartDay,
|
|
574
|
-
// Always format /quota in grouped mode for a more dashboard-like look.
|
|
575
|
-
toastStyle: "grouped",
|
|
576
|
-
onlyCurrentModel: config.onlyCurrentModel,
|
|
577
|
-
currentModel,
|
|
578
|
-
currentProviderID,
|
|
579
|
-
},
|
|
580
|
-
};
|
|
581
|
-
const filteringByCurrentSelection = config.onlyCurrentModel && Boolean(currentModel || isCursorProviderId(currentProviderID));
|
|
582
|
-
const filtered = filteringByCurrentSelection
|
|
583
|
-
? providers.filter((p) => matchesProviderCurrentSelection({ provider: p, currentModel, currentProviderID }))
|
|
584
|
-
: providers;
|
|
585
|
-
return {
|
|
586
|
-
isAutoMode,
|
|
587
|
-
providers,
|
|
588
|
-
filtered,
|
|
589
|
-
ctx,
|
|
590
|
-
currentModel,
|
|
591
|
-
currentProviderID,
|
|
592
|
-
filteringByCurrentSelection,
|
|
593
|
-
};
|
|
594
|
-
}
|
|
595
440
|
function describeQuotaCommandCurrentSelection(params) {
|
|
596
441
|
if (isCursorProviderId(params.currentProviderID)) {
|
|
597
442
|
return `current provider: ${params.currentProviderID}`;
|
|
@@ -602,7 +447,12 @@ export const QuotaToastPlugin = async ({ client }) => {
|
|
|
602
447
|
return "current session";
|
|
603
448
|
}
|
|
604
449
|
async function buildQuotaCommandUnavailableMessage(params = {}) {
|
|
605
|
-
const selection = await
|
|
450
|
+
const selection = await resolveQuotaRenderSelection({
|
|
451
|
+
client: typedClient,
|
|
452
|
+
config,
|
|
453
|
+
request: params,
|
|
454
|
+
formatStyle: "grouped",
|
|
455
|
+
});
|
|
606
456
|
if (!selection) {
|
|
607
457
|
return "Quota unavailable\n\nNo enabled quota providers are configured.\n\nRun /quota_status for diagnostics.";
|
|
608
458
|
}
|
|
@@ -648,140 +498,56 @@ export const QuotaToastPlugin = async ({ client }) => {
|
|
|
648
498
|
? formatDebugInfo({ trigger, reason: "disabled", enabledProviders: [] })
|
|
649
499
|
: null;
|
|
650
500
|
}
|
|
651
|
-
|
|
652
|
-
const isAutoMode = config.enabledProviders === "auto";
|
|
653
|
-
const enabledProviderIds = isAutoMode ? [] : config.enabledProviders;
|
|
654
|
-
// When enabledProviders is "auto", we'll filter by availability below.
|
|
655
|
-
// When explicit, filter to just the listed providers.
|
|
656
|
-
const providers = isAutoMode
|
|
657
|
-
? allProviders
|
|
658
|
-
: allProviders.filter((p) => enabledProviderIds.includes(p.id));
|
|
659
|
-
// Only bail on empty if user explicitly configured an empty list.
|
|
660
|
-
if (!isAutoMode && providers.length === 0) {
|
|
501
|
+
if (config.enabledProviders !== "auto" && config.enabledProviders.length === 0) {
|
|
661
502
|
return config.debug
|
|
662
503
|
? formatDebugInfo({ trigger, reason: "enabledProviders empty", enabledProviders: [] })
|
|
663
504
|
: null;
|
|
664
505
|
}
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
const currentSession = await getSessionModelMeta(sessionID);
|
|
669
|
-
currentModel = currentSession.modelID;
|
|
670
|
-
currentProviderID = currentSession.providerID;
|
|
671
|
-
}
|
|
672
|
-
const ctx = {
|
|
673
|
-
client: typedClient,
|
|
674
|
-
config: {
|
|
675
|
-
googleModels: config.googleModels,
|
|
676
|
-
anthropicBinaryPath: config.anthropicBinaryPath,
|
|
677
|
-
alibabaCodingPlanTier: config.alibabaCodingPlanTier,
|
|
678
|
-
cursorPlan: config.cursorPlan,
|
|
679
|
-
cursorIncludedApiUsd: config.cursorIncludedApiUsd,
|
|
680
|
-
cursorBillingCycleStartDay: config.cursorBillingCycleStartDay,
|
|
681
|
-
toastStyle: config.toastStyle,
|
|
682
|
-
onlyCurrentModel: config.onlyCurrentModel,
|
|
683
|
-
currentModel,
|
|
684
|
-
currentProviderID,
|
|
685
|
-
},
|
|
506
|
+
const quotaRequestContext = {
|
|
507
|
+
sessionID,
|
|
508
|
+
sessionMeta: config.onlyCurrentModel && sessionID ? await getSessionModelMeta(sessionID) : undefined,
|
|
686
509
|
};
|
|
687
|
-
const
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
510
|
+
const quotaResult = await collectQuotaRenderData({
|
|
511
|
+
client: typedClient,
|
|
512
|
+
config,
|
|
513
|
+
request: quotaRequestContext,
|
|
514
|
+
providerFetchCache,
|
|
515
|
+
surfaceExplicitProviderIssues: true,
|
|
516
|
+
formatStyle: config.formatStyle,
|
|
517
|
+
});
|
|
518
|
+
const { selection, availability, active, attemptedAny, hasExplicitProviderIssues, data } = quotaResult;
|
|
519
|
+
if (config.showSessionTokens && sessionID) {
|
|
520
|
+
lastSessionTokenError = quotaResult.sessionTokenError;
|
|
521
|
+
}
|
|
522
|
+
const currentModel = selection?.currentModel;
|
|
523
|
+
const errors = data?.errors ?? [];
|
|
524
|
+
if (active.length === 0 && !(hasExplicitProviderIssues && errors.length > 0)) {
|
|
694
525
|
return config.debug
|
|
695
526
|
? formatDebugInfo({
|
|
696
527
|
trigger,
|
|
697
528
|
reason: "no enabled providers available",
|
|
698
529
|
currentModel,
|
|
699
530
|
enabledProviders: config.enabledProviders,
|
|
700
|
-
availability:
|
|
531
|
+
availability: availability.map((item) => ({
|
|
532
|
+
id: item.provider.id,
|
|
533
|
+
ok: item.ok,
|
|
534
|
+
})),
|
|
701
535
|
})
|
|
702
536
|
: null;
|
|
703
537
|
}
|
|
704
|
-
|
|
705
|
-
providers: active,
|
|
706
|
-
ctx,
|
|
707
|
-
ttlMs: config.minIntervalMs,
|
|
708
|
-
});
|
|
709
|
-
const entries = results.flatMap((r) => r.entries);
|
|
710
|
-
const errors = results.flatMap((r) => r.errors);
|
|
711
|
-
const attemptedAny = results.some((r) => r.attempted);
|
|
712
|
-
let hasExplicitProviderIssues = false;
|
|
713
|
-
for (let i = 0; i < active.length; i++) {
|
|
714
|
-
const provider = active[i];
|
|
715
|
-
const result = results[i];
|
|
716
|
-
if (shouldSurfaceNoDataMessage({
|
|
717
|
-
provider,
|
|
718
|
-
result,
|
|
719
|
-
isAutoMode,
|
|
720
|
-
activeProviderCount: active.length,
|
|
721
|
-
})) {
|
|
722
|
-
errors.push({
|
|
723
|
-
label: getQuotaProviderDisplayLabel(provider.id),
|
|
724
|
-
message: getExplicitNoDataMessage(provider),
|
|
725
|
-
});
|
|
726
|
-
if (!isAutoMode) {
|
|
727
|
-
hasExplicitProviderIssues = true;
|
|
728
|
-
}
|
|
729
|
-
}
|
|
730
|
-
}
|
|
731
|
-
// When enabledProviders is an explicit list, surface unavailable/skipped
|
|
732
|
-
// providers instead of silently omitting them.
|
|
733
|
-
if (!isAutoMode) {
|
|
734
|
-
// If a user explicitly enabled providers that are unavailable (or skipped due
|
|
735
|
-
// to model filtering), surface that instead of silently omitting them.
|
|
736
|
-
const filteredIds = new Set(filtered.map((p) => p.id));
|
|
737
|
-
const activeIds = new Set(active.map((p) => p.id));
|
|
738
|
-
const availById = new Map(avail.map((x) => [x.p.id, x.ok]));
|
|
739
|
-
for (const p of providers) {
|
|
740
|
-
if (activeIds.has(p.id))
|
|
741
|
-
continue;
|
|
742
|
-
if (!filteredIds.has(p.id)) {
|
|
743
|
-
const detail = config.onlyCurrentModel && currentModel ? `current model: ${currentModel}` : "filtered";
|
|
744
|
-
errors.push({
|
|
745
|
-
label: getQuotaProviderDisplayLabel(p.id),
|
|
746
|
-
message: `Skipped (${detail})`,
|
|
747
|
-
});
|
|
748
|
-
hasExplicitProviderIssues = true;
|
|
749
|
-
continue;
|
|
750
|
-
}
|
|
751
|
-
const ok = availById.get(p.id);
|
|
752
|
-
if (ok === false) {
|
|
753
|
-
errors.push({
|
|
754
|
-
label: getQuotaProviderDisplayLabel(p.id),
|
|
755
|
-
message: "Unavailable (not detected)",
|
|
756
|
-
});
|
|
757
|
-
hasExplicitProviderIssues = true;
|
|
758
|
-
}
|
|
759
|
-
}
|
|
760
|
-
}
|
|
761
|
-
// Fetch session tokens if enabled and sessionID is available
|
|
762
|
-
let sessionTokens;
|
|
763
|
-
if (config.showSessionTokens && sessionID) {
|
|
764
|
-
const stResult = await fetchSessionTokensForDisplay({
|
|
765
|
-
enabled: config.showSessionTokens,
|
|
766
|
-
sessionID,
|
|
767
|
-
});
|
|
768
|
-
sessionTokens = stResult.sessionTokens;
|
|
769
|
-
// Update diagnostics state: clear on success (no error returned), set on failure
|
|
770
|
-
lastSessionTokenError = stResult.error;
|
|
771
|
-
}
|
|
772
|
-
if (entries.length > 0) {
|
|
538
|
+
if (data?.entries.length) {
|
|
773
539
|
const formatted = formatQuotaRows({
|
|
774
540
|
version: "1.0.0",
|
|
775
541
|
layout: config.layout,
|
|
776
|
-
entries,
|
|
777
|
-
errors,
|
|
778
|
-
style: config.
|
|
779
|
-
sessionTokens,
|
|
542
|
+
entries: data.entries,
|
|
543
|
+
errors: data.errors,
|
|
544
|
+
style: config.formatStyle,
|
|
545
|
+
sessionTokens: data.sessionTokens,
|
|
780
546
|
});
|
|
781
547
|
if (!config.debug)
|
|
782
548
|
return formatted;
|
|
783
|
-
const debugFooter = `\n\n[debug] src=${configMeta.source} providers=${config.enabledProviders === "auto" ? "(auto)" : config.enabledProviders.join(",") || "(none)"} avail=${
|
|
784
|
-
.map((
|
|
549
|
+
const debugFooter = `\n\n[debug] src=${configMeta.source} providers=${config.enabledProviders === "auto" ? "(auto)" : config.enabledProviders.join(",") || "(none)"} avail=${availability
|
|
550
|
+
.map((item) => `${item.provider.id}:${item.ok ? "ok" : "no"}`)
|
|
785
551
|
.join(" ")}`;
|
|
786
552
|
return formatted + debugFooter;
|
|
787
553
|
}
|
|
@@ -789,8 +555,7 @@ export const QuotaToastPlugin = async ({ client }) => {
|
|
|
789
555
|
// 1. showOnBothFail is enabled and at least one provider attempted (existing behavior)
|
|
790
556
|
// 2. OR we're in explicit mode and have "Not configured"/"Unavailable" errors (new behavior)
|
|
791
557
|
if ((config.showOnBothFail && attemptedAny && errors.length > 0) || hasExplicitProviderIssues) {
|
|
792
|
-
|
|
793
|
-
const errorLines = errors.map((e) => `${e.label}: ${e.message}`).join("\n");
|
|
558
|
+
const errorLines = errors.map((error) => `${error.label}: ${error.message}`).join("\n");
|
|
794
559
|
if (!config.debug)
|
|
795
560
|
return errorLines || "Quota unavailable";
|
|
796
561
|
return ((errorLines || "Quota unavailable") +
|
|
@@ -802,7 +567,10 @@ export const QuotaToastPlugin = async ({ client }) => {
|
|
|
802
567
|
: "all providers failed",
|
|
803
568
|
currentModel,
|
|
804
569
|
enabledProviders: config.enabledProviders,
|
|
805
|
-
availability:
|
|
570
|
+
availability: availability.map((item) => ({
|
|
571
|
+
id: item.provider.id,
|
|
572
|
+
ok: item.ok,
|
|
573
|
+
})),
|
|
806
574
|
}));
|
|
807
575
|
}
|
|
808
576
|
return config.debug
|
|
@@ -811,7 +579,10 @@ export const QuotaToastPlugin = async ({ client }) => {
|
|
|
811
579
|
reason: "no entries",
|
|
812
580
|
currentModel,
|
|
813
581
|
enabledProviders: config.enabledProviders,
|
|
814
|
-
availability:
|
|
582
|
+
availability: availability.map((item) => ({
|
|
583
|
+
id: item.provider.id,
|
|
584
|
+
ok: item.ok,
|
|
585
|
+
})),
|
|
815
586
|
})
|
|
816
587
|
: null;
|
|
817
588
|
}
|
|
@@ -871,50 +642,18 @@ export const QuotaToastPlugin = async ({ client }) => {
|
|
|
871
642
|
}
|
|
872
643
|
}
|
|
873
644
|
async function fetchQuotaCommandData(trigger, params = {}) {
|
|
874
|
-
const
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
return null;
|
|
882
|
-
const results = await fetchProviderResults({
|
|
883
|
-
providers: active,
|
|
884
|
-
ctx,
|
|
885
|
-
ttlMs: config.minIntervalMs,
|
|
645
|
+
const quotaResult = await collectQuotaRenderData({
|
|
646
|
+
client: typedClient,
|
|
647
|
+
config,
|
|
648
|
+
request: params,
|
|
649
|
+
providerFetchCache,
|
|
650
|
+
surfaceExplicitProviderIssues: false,
|
|
651
|
+
formatStyle: "grouped",
|
|
886
652
|
});
|
|
887
|
-
const entries = results.flatMap((r) => r.entries);
|
|
888
|
-
const errors = results.flatMap((r) => r.errors);
|
|
889
|
-
for (let i = 0; i < active.length; i++) {
|
|
890
|
-
const provider = active[i];
|
|
891
|
-
const result = results[i];
|
|
892
|
-
if (shouldSurfaceNoDataMessage({
|
|
893
|
-
provider,
|
|
894
|
-
result,
|
|
895
|
-
isAutoMode,
|
|
896
|
-
activeProviderCount: active.length,
|
|
897
|
-
})) {
|
|
898
|
-
errors.push({
|
|
899
|
-
label: getQuotaProviderDisplayLabel(provider.id),
|
|
900
|
-
message: getExplicitNoDataMessage(provider),
|
|
901
|
-
});
|
|
902
|
-
}
|
|
903
|
-
}
|
|
904
|
-
// Fetch session tokens if enabled and sessionID is available
|
|
905
|
-
let sessionTokens;
|
|
906
653
|
if (config.showSessionTokens && params.sessionID) {
|
|
907
|
-
|
|
908
|
-
enabled: config.showSessionTokens,
|
|
909
|
-
sessionID: params.sessionID,
|
|
910
|
-
});
|
|
911
|
-
sessionTokens = stResult.sessionTokens;
|
|
912
|
-
// Update diagnostics state: clear on success (no error returned), set on failure
|
|
913
|
-
lastSessionTokenError = stResult.error;
|
|
654
|
+
lastSessionTokenError = quotaResult.sessionTokenError;
|
|
914
655
|
}
|
|
915
|
-
|
|
916
|
-
return null;
|
|
917
|
-
return { entries, errors, sessionTokens };
|
|
656
|
+
return quotaResult.data;
|
|
918
657
|
}
|
|
919
658
|
async function buildQuotaReport(params) {
|
|
920
659
|
const result = await aggregateUsage({
|
|
@@ -976,16 +715,23 @@ export const QuotaToastPlugin = async ({ client }) => {
|
|
|
976
715
|
enabled: isAutoMode ? ok : config.enabledProviders.includes(p.id),
|
|
977
716
|
available: ok,
|
|
978
717
|
matchesCurrentModel: currentModel || isCursorProviderId(currentProviderID)
|
|
979
|
-
?
|
|
718
|
+
? matchesQuotaProviderCurrentSelection({
|
|
719
|
+
provider: p,
|
|
720
|
+
currentModel,
|
|
721
|
+
currentProviderID,
|
|
722
|
+
})
|
|
980
723
|
: undefined,
|
|
981
724
|
};
|
|
982
725
|
}));
|
|
983
726
|
const refresh = params.refreshGoogleTokens
|
|
984
727
|
? await refreshGoogleTokensForAllAccounts({ skewMs: params.skewMs, force: params.force })
|
|
985
728
|
: null;
|
|
729
|
+
const tuiDiagnostics = await inspectTuiConfig();
|
|
986
730
|
return await buildQuotaStatusReport({
|
|
731
|
+
tuiDiagnostics,
|
|
987
732
|
configSource: configMeta.source,
|
|
988
733
|
configPaths: configMeta.paths,
|
|
734
|
+
networkSettingSources: configMeta.networkSettingSources,
|
|
989
735
|
enabledProviders: config.enabledProviders,
|
|
990
736
|
anthropicBinaryPath: config.anthropicBinaryPath,
|
|
991
737
|
alibabaCodingPlanTier: config.alibabaCodingPlanTier,
|
|
@@ -1249,7 +995,7 @@ export const QuotaToastPlugin = async ({ client }) => {
|
|
|
1249
995
|
};
|
|
1250
996
|
cfg.command["quota_status"] = {
|
|
1251
997
|
template: "/quota_status",
|
|
1252
|
-
description: "Diagnostics for toast + pricing + local storage (includes unknown pricing report).",
|
|
998
|
+
description: "Diagnostics for toast + TUI + pricing + local storage (includes unknown pricing report).",
|
|
1253
999
|
};
|
|
1254
1000
|
cfg.command["pricing_refresh"] = {
|
|
1255
1001
|
template: "/pricing_refresh",
|
|
@@ -1312,7 +1058,7 @@ export const QuotaToastPlugin = async ({ client }) => {
|
|
|
1312
1058
|
},
|
|
1313
1059
|
tool: {
|
|
1314
1060
|
quota_status: tool({
|
|
1315
|
-
description: "Diagnostics for toast + pricing + local storage (includes unknown pricing report).",
|
|
1061
|
+
description: "Diagnostics for toast + TUI + pricing + local storage (includes unknown pricing report).",
|
|
1316
1062
|
args: {
|
|
1317
1063
|
refreshGoogleTokens: tool.schema
|
|
1318
1064
|
.boolean()
|