From ae799858af9ac1a4961bf6e02a1a5a6b84c6b804 Mon Sep 17 00:00:00 2001 From: ted Date: Tue, 27 Jan 2026 11:55:37 -0800 Subject: [PATCH] feat: make cost summary refresh interval configurable Replace the hardcoded 1-hour (3600s) cost summary refresh interval with the user-configurable refresh cadence setting. The cost summary now refreshes on the same schedule as provider usage (1m, 2m, 5m, 15m, 30m). Changes: - Remove hardcoded tokenFetchTTL constant from UsageStore - Update startTokenTimer() to use settings.refreshFrequency.seconds - Restart token timer when settings change (like provider timer) - Update UI text from "Auto-refresh: hourly" to show actual interval Note: The CostUsageScanner already has internal 60-second caching, so no additional floor is needed at the app level. Co-Authored-By: Claude Opus 4.5 --- Sources/CodexBar/PreferencesGeneralPane.swift | 11 ++++++++++- Sources/CodexBar/UsageStore.swift | 4 ++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/Sources/CodexBar/PreferencesGeneralPane.swift b/Sources/CodexBar/PreferencesGeneralPane.swift index 39a95a55..52ec6989 100644 --- a/Sources/CodexBar/PreferencesGeneralPane.swift +++ b/Sources/CodexBar/PreferencesGeneralPane.swift @@ -43,7 +43,7 @@ struct GeneralPane: View { .fixedSize(horizontal: false, vertical: true) if self.settings.costUsageEnabled { - Text("Auto-refresh: hourly · Timeout: 10m") + Text("Auto-refresh: \(self.costRefreshLabel) · Timeout: 10m") .font(.footnote) .foregroundStyle(.tertiary) @@ -115,6 +115,15 @@ struct GeneralPane: View { } } + private var costRefreshLabel: String { + switch self.settings.refreshFrequency { + case .manual: + return "off" + default: + return self.settings.refreshFrequency.label + } + } + private func costStatusLine(provider: UsageProvider) -> some View { let name = ProviderDescriptorRegistry.descriptor(for: provider).metadata.displayName diff --git a/Sources/CodexBar/UsageStore.swift b/Sources/CodexBar/UsageStore.swift index 69491056..f64da2dd 100644 --- a/Sources/CodexBar/UsageStore.swift +++ b/Sources/CodexBar/UsageStore.swift @@ -56,6 +56,7 @@ extension UsageStore { guard let self else { return } self.observeSettingsChanges() self.startTimer() + self.startTokenTimer() self.updateProviderRuntimes() await self.refresh() } @@ -193,7 +194,6 @@ final class UsageStore { @ObservationIgnored private var pathDebugRefreshTask: Task? @ObservationIgnored var lastKnownSessionRemaining: [UsageProvider: Double] = [:] @ObservationIgnored var lastTokenFetchAt: [UsageProvider: Date] = [:] - @ObservationIgnored private let tokenFetchTTL: TimeInterval = 60 * 60 @ObservationIgnored private let tokenFetchTimeout: TimeInterval = 10 * 60 init( @@ -485,7 +485,7 @@ final class UsageStore { private func startTokenTimer() { self.tokenTimerTask?.cancel() - let wait = self.tokenFetchTTL + guard let wait = self.settings.refreshFrequency.seconds else { return } self.tokenTimerTask = Task.detached(priority: .utility) { [weak self] in while !Task.isCancelled { try? await Task.sleep(for: .seconds(wait))