feat(hud): session reset timers and weekly/monthly cost tracking#190
Merged
feat(hud): session reset timers and weekly/monthly cost tracking#190
Conversation
…etsAt to UsageData, CostAggregation type, and costHistory to GatherContext Co-Authored-By: Claude <noreply@anthropic.com>
Implements persistSessionCost (atomic write per session), aggregateCosts (merges active files + archive, deduplicates by max cost_usd), and getCostFilePaths (testable path resolution via DEVFLOW_DIR env var). Cleanup runs periodically: archives 24h-old sessions, trims archive at 90 days. Co-Authored-By: Claude <noreply@anthropic.com>
usage-quota: drop Session prefix, add formatCountdown helper for reset timers (↻2h15m format), show countdown after label and before bar. session-cost: extend to show weekly ($18.50/wk) and monthly ($62.30/mo) cost totals from costHistory when available. Co-Authored-By: Claude <noreply@anthropic.com>
render.ts: reorder Line 3 to model · configCounts · sessionDuration · sessionCost. index.ts: remove OAuth fetchUsageData, add extractUsageFromStdin (reads rate_limits from stdin directly), wire persistSessionCost and aggregateCosts for cost tracking. costHistory passed into GatherContext. Co-Authored-By: Claude <noreply@anthropic.com>
… extraction OAuth-based usage fetching removed; rate limits now read directly from stdin.rate_limits on each render. No network calls, no credentials needed. Co-Authored-By: Claude <noreply@anthropic.com>
hud-components.test.ts: add learningCounts/costHistory to makeCtx; update usageQuota tests to drop Session prefix, add resets_at fields, and test countdown rendering; add sessionCost tests for weekly/monthly. hud-render.test.ts: add costHistory to makeCtx; update usage assertions to drop Session prefix, add resets_at fields. cost-history.test.ts: new suite covering persistSessionCost (atomic writes, skip on zero cost, overwrite, concurrent sessions) and aggregateCosts (null handling, file reads, archive, dedup, window sums, malformed entry resilience). credentials.test.ts: deleted — credentials.ts removed. Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
Three discrepancies between the README preview and actual render: - Line 2 lacked 'Context' label prefix and used wrong quota format (↻ symbol with pre-bar countdown instead of parenthesized post-percent countdown) - Line 3 included ⏱ 15m (sessionDuration) which is removed from defaults - Feature description mentioned 'session duration' — removed Co-Authored-By: Claude <noreply@anthropic.com>
…-history - Extract nowEpoch() helper to deduplicate Math.floor(Date.now() / 1000) across 4 call sites - Add isSessionEntry() type guard replacing all unsafe JSON.parse casts - Fix !costUsd guard to costUsd <= 0 || !Number.isFinite(costUsd) to correctly reject NaN and negative values - Guard mkdirSync with sessionsDirCreated module flag to avoid redundant syscalls - Extract cleanOrphanedTmpFiles() and archiveStaleSessionFiles() from runCleanup to reduce nesting - Extract upsertMax(), readSessionEntries(), readArchiveEntries() from aggregateCosts to thin the orchestrator - Add 30s aggregation cache to avoid repeated filesystem reads on every HUD render tick Co-Authored-By: Claude <noreply@anthropic.com>
…sistence - formatCountdown JSDoc: remove stale "compact, no spaces" note (impl uses spaces) - renderQuotaWindow: add JSDoc showing rendered format - ComponentId JSDoc: replace "16 HUD components" count with accurate description - StdinData.rate_limits resets_at fields: annotate as Epoch seconds - sessionCost: add JSDoc documenting weekly/monthly totals - persistSessionCost call: guard with needsSessionCost so cost is only persisted when the sessionCost component is actually enabled Co-Authored-By: Claude <noreply@anthropic.com>
- Fix module isolation: add vi.resetModules() in beforeEach so module-level singletons (sessionsDirCreated, cachedAggregation) reset between tests; this fixes 15 pre-existing test failures - Fix misleading comment: "cache-busting" → accurate description of why dynamic import is used (DEVFLOW_DIR read at call time) - Add path traversal guard tests for persistSessionCost (/, \, empty string) - Add runCleanup test: verifies stale session files (>24h) are archived to archive.jsonl, triggered by mocking Date.now to a timestamp % 50 === 0 - Add formatCountdown describe block: past timestamp, 2h 30m, 2d 5h, 45m minutes-only, exact day (no hours sub-unit), exact hour (no minutes sub-unit) Co-Authored-By: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
usage-api.tsandcredentials.ts, extractrate_limits.resets_atandcostfrom Claude Code's stdin payload instead of making external API calls5h ████░░░░ 45% (2h 15m)format with parenthesized countdown after quota bars$1.42 · $18.50/wk · $62.30/moon Line 3sessionDurationfrom defaults (component retained for reinstatement)Changes
cost-history.ts(310 lines) — atomic persistence, cleanup, archival, aggregation with type guard, caching, and extracted helperscost-history.test.ts(519 lines, 28 tests) — persistence, path traversal, cleanup, archival, trimming, aggregationusage-quota.ts—formatCountdown,renderQuotaWindowwith JSDocsession-cost.ts— weekly/monthly cost displayindex.ts— stdin extraction forresets_atand cost, cost persistence gated behindneedsSessionCosttypes.ts—CostAggregation, epoch-seconds annotations, count-agnostic JSDochud-components.test.ts— 67 tests (added formatCountdown unit tests, updated component output assertions)usage-api.ts,credentials.ts,credentials.test.ts— OAuth flow replaced by stdin extractionTest plan