Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
854090a
feat(core): generalized usage/spend scanning + pricing foundation
Yuxin-Qiao Jul 31, 2026
c338e8f
Keep Groq out of the cost-capable set in the foundation layer
Yuxin-Qiao Jul 31, 2026
c565404
feat(core): registerable local-history scanner registry + zcode/trae/…
Yuxin-Qiao Aug 1, 2026
1bba0c5
feat(core): unified usage-event layer + shared aggregator, add Copilot
Yuxin-Qiao Aug 1, 2026
3eb62c2
style(tests): apply SwiftFormat to new engine/copilot suites
Yuxin-Qiao Aug 1, 2026
2af1b1c
feat: add standalone token activity heatmap
Yuxin-Qiao Aug 1, 2026
4990426
fix: preserve token activity coverage
Yuxin-Qiao Aug 1, 2026
b2114dc
fix: complete activity heatmap navigation
Yuxin-Qiao Aug 1, 2026
db44ad1
fix: expose daily activity accessibility
Yuxin-Qiao Aug 1, 2026
6cfcb0c
feat(core): full-history manual rescan + live scan progress
Yuxin-Qiao Aug 1, 2026
4542293
fix: publish daily accessibility semantics
Yuxin-Qiao Aug 1, 2026
ee6b5cb
fix: expose dates in activity accessibility
Yuxin-Qiao Aug 1, 2026
2f820c9
fix: expose weekly activity accessibility
Yuxin-Qiao Aug 1, 2026
9792595
fix(i18n): translate "Scanning history" into Italian
Yuxin-Qiao Aug 1, 2026
5c2ae86
fix(core): provider ownership + complete-cost + cache-write pricing
Yuxin-Qiao Aug 1, 2026
2d25dab
fix(core): prefer refreshed catalog rates over embedded Gemini table
Yuxin-Qiao Aug 1, 2026
d5f4385
fix(core): fall back to OpenCode's time_created column
Yuxin-Qiao Aug 1, 2026
554ef51
fix: separate spend and annual activity scan budgets
Yuxin-Qiao Aug 1, 2026
0adc8a1
feat(core): wire local history scanners into the dashboard loader
Yuxin-Qiao Aug 1, 2026
1d68546
refactor(core): migrate Kimi/MiniMax/Antigravity scanners to the shar…
Yuxin-Qiao Aug 1, 2026
b7110f4
feat(core): retain OpenCode billing ownership evidence end to end
Yuxin-Qiao Aug 1, 2026
f719adf
style: satisfy swift-format lint-macos gate
Yuxin-Qiao Aug 1, 2026
3a22838
fix(core): wire local-history providers into the token refresh pipeline
Yuxin-Qiao Aug 1, 2026
204f1eb
fix(core): preserve billing ownership across merged daily reports
Yuxin-Qiao Aug 1, 2026
65af90d
fix(core): withhold OpenCode headline cost on unpriced days and mark …
Yuxin-Qiao Aug 1, 2026
10fb613
fix(core): omit Trae activity outside the requested history window
Yuxin-Qiao Aug 1, 2026
7ef4935
fix(core): lift the per-file cap for full Codex rescans and bridge ca…
Yuxin-Qiao Aug 1, 2026
b366ef8
fix(core): overflow-safe total checks and Copilot rollup request counts
Yuxin-Qiao Aug 1, 2026
341fc5b
fix: treat established empty annual scans as confirmed zero activity
Yuxin-Qiao Aug 1, 2026
7c3818d
chore: integration base main+pr2527 (local only)
Yuxin-Qiao Aug 2, 2026
dbbe15c
chore: merge pr2548 heatmap head into integration base (local only)
Yuxin-Qiao Aug 2, 2026
0b2c2b5
feat(spend): model-centric Models view with per-tool breakdown and bi…
Yuxin-Qiao Aug 2, 2026
564941d
chore: remove local design QA scratch file
Yuxin-Qiao Aug 2, 2026
a2d1021
refactor(spend): remove unfinished daily estimated spend card from mo…
Yuxin-Qiao Aug 2, 2026
dce897f
feat(spend): CLIENTS & MODELS by-tool view with collapsible client ro…
Yuxin-Qiao Aug 2, 2026
7774c2a
fix(spend): address ClawSweeper findings for local history, billing, …
Yuxin-Qiao Aug 2, 2026
a0245f2
test(i18n): allowlist models strings kept in English in Italian catalog
Yuxin-Qiao Aug 2, 2026
05fcc1a
style(spend): refine clients view hierarchy and add colored Codex icon
Yuxin-Qiao Aug 2, 2026
314a7a2
test(spend): fix coverage assertions after daily chart removal
Yuxin-Qiao Aug 2, 2026
dc9ae67
test(spend): align scan budget tests with merged 365-day spend scan
Yuxin-Qiao Aug 2, 2026
8efc032
ci: retrigger after flaky Linux fd test
Yuxin-Qiao Aug 2, 2026
00a3d05
fix(spend): pass active currency to model spend formatters and keep o…
Yuxin-Qiao Aug 2, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 36 additions & 4 deletions Sources/CodexBar/CodexbarApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ struct CodexBarApp: App {
@State private var store: UsageStore
@State private var managedCodexAccountCoordinator: ManagedCodexAccountCoordinator
@State private var codexAccountPromotionCoordinator: CodexAccountPromotionCoordinator
@State private var spendDashboardController: SpendDashboardController
private let preferencesSelection: PreferencesSelection
private let account: AccountInfo

Expand Down Expand Up @@ -78,6 +79,9 @@ struct CodexBarApp: App {
let browserDetection = BrowserDetection(cacheTTL: BrowserDetection.defaultCacheTTL)
let account = fetcher.loadAccountInfo()
let store = UsageStore(fetcher: fetcher, browserDetection: browserDetection, settings: settings)
let spendDashboardController = SpendDashboardController(requestBuilder: { mode in
await SpendDashboardSource.makeRequest(settings: settings, store: store, mode: mode)
})
let codexAccountPromotionCoordinator = CodexAccountPromotionCoordinator(
settingsStore: settings,
usageStore: store,
Expand All @@ -87,6 +91,7 @@ struct CodexBarApp: App {
_store = State(wrappedValue: store)
_managedCodexAccountCoordinator = State(wrappedValue: managedCodexAccountCoordinator)
_codexAccountPromotionCoordinator = State(wrappedValue: codexAccountPromotionCoordinator)
_spendDashboardController = State(wrappedValue: spendDashboardController)
self.account = account
CodexBarLog.setLogLevel(settings.debugLogLevel)
self.appDelegate.configure(.init(
Expand All @@ -95,7 +100,8 @@ struct CodexBarApp: App {
account: account,
selection: preferencesSelection,
managedCodexAccountCoordinator: managedCodexAccountCoordinator,
codexAccountPromotionCoordinator: codexAccountPromotionCoordinator))
codexAccountPromotionCoordinator: codexAccountPromotionCoordinator,
spendDashboardController: spendDashboardController))
}

@SceneBuilder
Expand All @@ -112,6 +118,7 @@ struct CodexBarApp: App {
PreferencesView(
settings: self.settings,
store: self.store,
spendDashboardController: self.spendDashboardController,
updater: self.appDelegate.updaterController,
selection: self.preferencesSelection,
managedCodexAccountCoordinator: self.managedCodexAccountCoordinator,
Expand Down Expand Up @@ -374,6 +381,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
let selection: PreferencesSelection
let managedCodexAccountCoordinator: ManagedCodexAccountCoordinator
let codexAccountPromotionCoordinator: CodexAccountPromotionCoordinator
let spendDashboardController: SpendDashboardController?
}

let updaterController: UpdaterProviding = makeUpdaterController()
Expand All @@ -390,6 +398,8 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
private var preferencesSelection: PreferencesSelection?
private var managedCodexAccountCoordinator: ManagedCodexAccountCoordinator?
private var codexAccountPromotionCoordinator: CodexAccountPromotionCoordinator?
private var spendDashboardController: SpendDashboardController?
private var spendDashboardWarmupTask: Task<Void, Never>?
private var hasInstalledLimitResetObservers = false
#if DEBUG
private var debugMemoryPressureObserver: NSObjectProtocol?
Expand All @@ -405,6 +415,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
self.preferencesSelection = dependencies.selection
self.managedCodexAccountCoordinator = dependencies.managedCodexAccountCoordinator
self.codexAccountPromotionCoordinator = dependencies.codexAccountPromotionCoordinator
self.spendDashboardController = dependencies.spendDashboardController
}

func applicationWillFinishLaunching(_ notification: Notification) {
Expand All @@ -417,6 +428,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
self.installDebugMemoryPressureObserverIfNeeded()
#endif
self.ensureStatusController()
self.scheduleSpendDashboardWarmup()
Task { @MainActor [weak self] in
await Task.yield()
guard let settings = self?.settings else { return }
Expand Down Expand Up @@ -452,6 +464,9 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
}

func applicationWillTerminate(_ notification: Notification) {
self.spendDashboardWarmupTask?.cancel()
self.spendDashboardWarmupTask = nil
self.spendDashboardController?.stop()
self.memoryPressureMonitor.stop()
#if DEBUG
self.removeDebugMemoryPressureObserver()
Expand All @@ -462,6 +477,26 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
self.terminateActiveProcessesForAppShutdown()
}

private func scheduleSpendDashboardWarmup() {
guard self.spendDashboardWarmupTask == nil,
let controller = self.spendDashboardController,
let settings = self.settings,
let store = self.store
else {
return
}
self.spendDashboardWarmupTask = Task(priority: .utility) { @MainActor [weak self] in
defer { self?.spendDashboardWarmupTask = nil }
do {
try await Task.sleep(for: .seconds(5))
} catch {
return
}
guard !Task.isCancelled, settings.costUsageEnabled else { return }
controller.update(configuration: SpendDashboardSource.configuration(settings: settings, store: store))
}
}

func runProviderLoginFlow(_ provider: UsageProvider) async {
self.ensureStatusController()
guard let statusController else { return }
Expand Down Expand Up @@ -556,9 +591,6 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
selection,
managedCodexAccountCoordinator,
codexAccountPromotionCoordinator)
if let statusController = self.statusController as? StatusItemController {
MenuSwitchFlickerProbe.startIfRequested(controller: statusController)
}
return
}

Expand Down
Loading