refactor(infra): split provider usage
This commit is contained in:
91
src/infra/provider-usage.format.ts
Normal file
91
src/infra/provider-usage.format.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
import { clampPercent } from "./provider-usage.shared.js";
|
||||
import type { UsageSummary, UsageWindow } from "./provider-usage.types.js";
|
||||
|
||||
function formatResetRemaining(targetMs?: number, now?: number): string | null {
|
||||
if (!targetMs) return null;
|
||||
const base = now ?? Date.now();
|
||||
const diffMs = targetMs - base;
|
||||
if (diffMs <= 0) return "now";
|
||||
|
||||
const diffMins = Math.floor(diffMs / 60000);
|
||||
if (diffMins < 60) return `${diffMins}m`;
|
||||
|
||||
const hours = Math.floor(diffMins / 60);
|
||||
const mins = diffMins % 60;
|
||||
if (hours < 24) return mins > 0 ? `${hours}h ${mins}m` : `${hours}h`;
|
||||
|
||||
const days = Math.floor(hours / 24);
|
||||
if (days < 7) return `${days}d ${hours % 24}h`;
|
||||
|
||||
return new Intl.DateTimeFormat("en-US", {
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
}).format(new Date(targetMs));
|
||||
}
|
||||
|
||||
function pickPrimaryWindow(windows: UsageWindow[]): UsageWindow | undefined {
|
||||
if (windows.length === 0) return undefined;
|
||||
return windows.reduce((best, next) =>
|
||||
next.usedPercent > best.usedPercent ? next : best,
|
||||
);
|
||||
}
|
||||
|
||||
function formatWindowShort(window: UsageWindow, now?: number): string {
|
||||
const remaining = clampPercent(100 - window.usedPercent);
|
||||
const reset = formatResetRemaining(window.resetAt, now);
|
||||
const resetSuffix = reset ? ` ⏱${reset}` : "";
|
||||
return `${remaining.toFixed(0)}% left (${window.label}${resetSuffix})`;
|
||||
}
|
||||
|
||||
export function formatUsageSummaryLine(
|
||||
summary: UsageSummary,
|
||||
opts?: { now?: number; maxProviders?: number },
|
||||
): string | null {
|
||||
const providers = summary.providers
|
||||
.filter((entry) => entry.windows.length > 0 && !entry.error)
|
||||
.slice(0, opts?.maxProviders ?? summary.providers.length);
|
||||
if (providers.length === 0) return null;
|
||||
|
||||
const parts = providers
|
||||
.map((entry) => {
|
||||
const window = pickPrimaryWindow(entry.windows);
|
||||
if (!window) return null;
|
||||
return `${entry.displayName} ${formatWindowShort(window, opts?.now)}`;
|
||||
})
|
||||
.filter(Boolean) as string[];
|
||||
|
||||
if (parts.length === 0) return null;
|
||||
return `📊 Usage: ${parts.join(" · ")}`;
|
||||
}
|
||||
|
||||
export function formatUsageReportLines(
|
||||
summary: UsageSummary,
|
||||
opts?: { now?: number },
|
||||
): string[] {
|
||||
if (summary.providers.length === 0) {
|
||||
return ["Usage: no provider usage available."];
|
||||
}
|
||||
|
||||
const lines: string[] = ["Usage:"];
|
||||
for (const entry of summary.providers) {
|
||||
const planSuffix = entry.plan ? ` (${entry.plan})` : "";
|
||||
if (entry.error) {
|
||||
lines.push(` ${entry.displayName}${planSuffix}: ${entry.error}`);
|
||||
continue;
|
||||
}
|
||||
if (entry.windows.length === 0) {
|
||||
lines.push(` ${entry.displayName}${planSuffix}: no data`);
|
||||
continue;
|
||||
}
|
||||
lines.push(` ${entry.displayName}${planSuffix}`);
|
||||
for (const window of entry.windows) {
|
||||
const remaining = clampPercent(100 - window.usedPercent);
|
||||
const reset = formatResetRemaining(window.resetAt, opts?.now);
|
||||
const resetSuffix = reset ? ` · resets ${reset}` : "";
|
||||
lines.push(
|
||||
` ${window.label}: ${remaining.toFixed(0)}% left${resetSuffix}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
Reference in New Issue
Block a user