/** * The full usage picture for every account, written to be read at a glance. * * The old output was one cramped table with the reset times on a second line, * which made the thing you actually want to know ("can I work, and where") * something you had to work out yourself. This shows every window per account * with a bar, says which one is the binding constraint, and ends with where to * go right now. */ export interface UsageWindow { label: string; used: number | null; resetsAt: number | null; /** * True for a window that covers ONE model rather than the whole account. * The difference matters: a spent model window stops that model, not the * account, and saying otherwise sends you away from an account you could * still work on by switching model. */ modelOnly?: boolean; } export interface UsageAccount { name: string; email?: string | undefined; plan?: string | undefined; active: boolean; /** Null when nothing has been read for this account yet. */ windows: UsageWindow[] | null; /** * The stored login has been rejected for good, so this account cannot work * however much room it has. Passed in rather than looked up here, because * this renderer stays pure and testable on its own. */ needsSignIn?: boolean; } export interface ReportOptions { color?: boolean; /** Terminal width, so the bars fit rather than wrapping. */ width?: number; } /** Full when spent, and never rounds a non-zero sliver down to empty. */ export declare function bar(used: number | null, size: number): string; export declare function percent(used: number | null): string; /** * A wait at the coarsest useful precision. Weekly windows are days away, and * printing those in hours is technically right and unreadable. */ export declare function humanWait(resetsAt: number | null, now: number): string; /** * How much of a window is used RIGHT NOW. * * Three states, and conflating any two of them produces a wrong report: * * - nothing measured: null, and null is not zero * - measured, but the window has since reset: the recorded number describes a * limit that has ended, so it constrains nothing now * - measured and still open: the number stands * * The middle case is positive information, not missing information. A window * that reset began again at empty, which is why it counts as room rather than * as an unknown. */ export declare function effectiveUsed(w: UsageWindow, now: number): number | null; /** * Whether anything at all has been measured for these windows. * * Deliberately independent of whether any window is still in force: an account * whose limits have all reset HAS been read, and reporting "nothing read yet" * for it would be false. */ export declare function hasReading(windows: UsageWindow[] | null | undefined): boolean; /** * The window closest to its limit: the one that will actually stop you. An * average across windows hides exactly this, which is the number that matters. * * Judged on usage as it stands now, so a window that has reset sinks to the * bottom instead of being reported as the constraint. */ export declare function bindingWindow(windows: UsageWindow[], now: number): UsageWindow | null; /** * The tightest window that applies to the WHOLE account, ignoring per-model * ones. This is the "can I work here at all" question: a spent model window * stops that model, not the account. */ export declare function accountWideBinding(windows: UsageWindow[], now: number): UsageWindow | null; /** * Where there is room, most room first, judged on account-wide windows only. * Judging on every window would hide an account that is perfectly usable and * merely out of one model, which is the common case. */ export declare function roomiest(accounts: UsageAccount[], now: number): UsageAccount[]; export declare function renderUsageReport(accounts: UsageAccount[], now: number, options?: ReportOptions): string;