From 8ffbffcd7f03120b876201b329096a88b5b4bfa4 Mon Sep 17 00:00:00 2001 From: iamtoruk Date: Sat, 25 Apr 2026 01:44:02 +0200 Subject: [PATCH] Fix double-counting in menubar-json period data PR #136 (2e5e449) changed parseAllSessions to use periodInfo.range (full period) instead of just today's range. When combined with cached historical data, this caused days to be counted twice: - Once from getDaysInRange(cache, ...) - Again from parseAllSessions(periodInfo.range, ...) Result: 7-day cost showed ~$402 instead of correct ~$209. Fix: Parse only today's sessions when using cache path. Historical data comes exclusively from cache, today's data from fresh parse. --- src/cli.ts | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/cli.ts b/src/cli.ts index 4f611f0..46bdaa1 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -421,7 +421,9 @@ program let scanRange: DateRange if (isAllProviders) { - const todayProjects = fp(await parseAllSessions(periodInfo.range, 'all')) + // Parse only today's sessions; historical data comes from cache to avoid double-counting + const todayRange: DateRange = { start: todayStart, end: new Date() } + const todayProjects = fp(await parseAllSessions(todayRange, 'all')) const todayDays = aggregateProjectsIntoDays(todayProjects) const rangeStartStr = toDateString(periodInfo.range.start) const rangeEndStr = toDateString(periodInfo.range.end) @@ -445,11 +447,14 @@ program const displayNameByName = new Map(allProviders.map(p => [p.name, p.displayName])) const providers: ProviderCost[] = [] if (isAllProviders) { - const todayDaysForProviders = aggregateProjectsIntoDays(fp(await parseAllSessions(periodInfo.range, 'all'))) + // Parse only today; historical provider costs come from cache + const todayRangeForProviders: DateRange = { start: todayStart, end: new Date() } + const todayDaysForProviders = aggregateProjectsIntoDays(fp(await parseAllSessions(todayRangeForProviders, 'all'))) const rangeStartStr = toDateString(periodInfo.range.start) + const todayStr = toDateString(todayStart) const allDaysForProviders = [ ...getDaysInRange(cache, rangeStartStr, yesterdayStr), - ...todayDaysForProviders.filter(d => d.date >= rangeStartStr), + ...todayDaysForProviders.filter(d => d.date === todayStr), ] const providerTotals: Record = {} for (const d of allDaysForProviders) { @@ -476,8 +481,11 @@ program // in the cache, so the filtered view shows zero tokens (heatmap/trend still works on cost). const historyStartStr = toDateString(new Date(todayStart.getTime() - BACKFILL_DAYS * MS_PER_DAY)) const allCacheDays = getDaysInRange(cache, historyStartStr, yesterdayStr) - const allTodayDaysForHistory = aggregateProjectsIntoDays(fp(await parseAllSessions(periodInfo.range, 'all'))) - const fullHistory = [...allCacheDays, ...allTodayDaysForHistory] + // Parse only today for history; historical days come from cache + const todayRangeForHistory: DateRange = { start: todayStart, end: new Date() } + const allTodayDaysForHistory = aggregateProjectsIntoDays(fp(await parseAllSessions(todayRangeForHistory, 'all'))) + const todayStrForHistory = toDateString(todayStart) + const fullHistory = [...allCacheDays, ...allTodayDaysForHistory.filter(d => d.date === todayStrForHistory)] const dailyHistory = fullHistory.map(d => { if (isAllProviders) { const topModels = Object.entries(d.models)