From 5cdcd2c2ee453bcea451c85c49cc8c4fae515711 Mon Sep 17 00:00:00 2001 From: Christopher Sant Date: Tue, 14 Apr 2026 14:09:42 -0700 Subject: [PATCH] feat: add rolling 30-day window to menubar status Add a '30 Days' section to the menubar format output, positioned between '7 Days' and 'Month' to match the tab order in the interactive report. The rolling 30-day date range logic already existed (used by report and export commands) - this wires it into the status menubar renderer. Both 30 Days (rolling window) and Month (calendar month) are shown, giving useful context early in the month when the calendar month total is nearly empty. --- src/cli.ts | 3 ++- src/menubar.ts | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/cli.ts b/src/cli.ts index 3f8d1c9..2c83efc 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -127,6 +127,7 @@ program const todayRange = getDateRange('today').range const todayData = buildPeriodData('Today', await parseAllSessions(todayRange, pf)) const weekData = buildPeriodData('7 Days', await parseAllSessions(getDateRange('week').range, pf)) + const thirtyDayData = buildPeriodData('30 Days', await parseAllSessions(getDateRange('30days').range, pf)) const monthData = buildPeriodData('Month', await parseAllSessions(getDateRange('month').range, pf)) const todayProviders: ProviderCost[] = [] for (const p of await getAllProviders()) { @@ -134,7 +135,7 @@ program const cost = data.reduce((s, proj) => s + proj.totalCostUSD, 0) if (cost > 0) todayProviders.push({ name: p.displayName, cost }) } - console.log(renderMenubarFormat(todayData, weekData, monthData, todayProviders)) + console.log(renderMenubarFormat(todayData, weekData, thirtyDayData, monthData, todayProviders)) return } diff --git a/src/menubar.ts b/src/menubar.ts index 2d47104..6386000 100644 --- a/src/menubar.ts +++ b/src/menubar.ts @@ -68,6 +68,7 @@ export type ProviderCost = { export function renderMenubarFormat( today: PeriodData, week: PeriodData, + thirtyDays: PeriodData, month: PeriodData, todayProviders?: ProviderCost[], ): string { @@ -130,6 +131,24 @@ export function renderMenubarFormat( lines.push(`--${bar} ${name} ${formatCost(model.cost).padStart(8)} ${String(model.calls).padStart(5)} calls | font=Menlo size=11`) } + lines.push(`30 Days ${formatCost(thirtyDays.cost)} ${thirtyDays.calls.toLocaleString()} calls | size=14`) + const tdMaxCat = Math.max(...thirtyDays.categories.map(c => c.cost), 0.01) + const tdMaxModel = Math.max(...thirtyDays.models.filter(m => m.name !== '').map(m => m.cost), 0.01) + lines.push(`--Activity | size=12 color=#FF8C42`) + for (const cat of thirtyDays.categories.slice(0, 8)) { + const bar = miniBar(cat.cost, tdMaxCat) + const name = cat.name.padEnd(14) + lines.push(`--${bar} ${name} ${formatCost(cat.cost).padStart(8)} ${String(cat.turns).padStart(4)} turns | font=Menlo size=11`) + } + lines.push(`-----`) + lines.push(`--Models | size=12 color=#FF8C42`) + for (const model of thirtyDays.models.slice(0, 5)) { + if (model.name === '') continue + const bar = miniBar(model.cost, tdMaxModel) + const name = model.name.padEnd(14) + lines.push(`--${bar} ${name} ${formatCost(model.cost).padStart(8)} ${String(model.calls).padStart(5)} calls | font=Menlo size=11`) + } + lines.push(`Month ${formatCost(month.cost)} ${month.calls.toLocaleString()} calls | size=14`) const monthMaxCat = Math.max(...month.categories.map(c => c.cost), 0.01) const monthMaxModel = Math.max(...month.models.filter(m => m.name !== '').map(m => m.cost), 0.01)