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.
This commit is contained in:
iamtoruk 2026-04-25 01:44:02 +02:00 committed by AgentSeal
parent bfcae0f84e
commit 8ffbffcd7f

View file

@ -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<string, number> = {}
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)