From 39978b83fa2ed2a957522135964b46be16a8207d Mon Sep 17 00:00:00 2001 From: AgentSeal Date: Mon, 22 Jun 2026 03:18:42 +0200 Subject: [PATCH] fix(menubar): show every active agent as a tab, ordered by usage for the selected range The agent tab strip never showed Grok, Hermes, or ZCode: ProviderFilter had no cases for them, so they could not become tabs. It also derived the visible tabs from today's providers rather than the range the user actually has selected, so an agent used in the selected window but not today never appeared. Add the three missing cases (filter keys, CLI arg, accent color) and rebuild visibleFilters to source from the selected period via cost(for:). Every agent with usage in the range now appears, ordered by spend descending, and agents with no usage in the range are omitted. --- mac/Sources/CodeBurnMenubar/AppStore.swift | 8 ++++++++ .../CodeBurnMenubar/Views/AgentTabStrip.swift | 19 +++++++++---------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/mac/Sources/CodeBurnMenubar/AppStore.swift b/mac/Sources/CodeBurnMenubar/AppStore.swift index 9f761363..a9a896ef 100644 --- a/mac/Sources/CodeBurnMenubar/AppStore.swift +++ b/mac/Sources/CodeBurnMenubar/AppStore.swift @@ -1078,6 +1078,9 @@ enum ProviderFilter: String, CaseIterable, Identifiable { case crush = "Crush" case antigravity = "Antigravity" case goose = "Goose" + case grok = "Grok" + case hermes = "Hermes" + case zcode = "ZCode" var id: String { rawValue } @@ -1092,6 +1095,8 @@ enum ProviderFilter: String, CaseIterable, Identifiable { case .openclaw: ["openclaw"] case .antigravity: ["antigravity"] case .goose: ["goose"] + case .grok: ["grok", "grok build"] + case .hermes: ["hermes", "hermes agent"] default: [rawValue.lowercased()] } } @@ -1121,6 +1126,9 @@ enum ProviderFilter: String, CaseIterable, Identifiable { case .crush: "crush" case .antigravity: "antigravity" case .goose: "goose" + case .grok: "grok" + case .hermes: "hermes" + case .zcode: "zcode" } } } diff --git a/mac/Sources/CodeBurnMenubar/Views/AgentTabStrip.swift b/mac/Sources/CodeBurnMenubar/Views/AgentTabStrip.swift index 0c0a81f7..3276ba93 100644 --- a/mac/Sources/CodeBurnMenubar/Views/AgentTabStrip.swift +++ b/mac/Sources/CodeBurnMenubar/Views/AgentTabStrip.swift @@ -108,23 +108,19 @@ struct AgentTabStrip: View { .frame(height: 38) } - private var todayAll: MenubarPayload { - store.todayPayload ?? store.payload - } - private var periodAll: MenubarPayload { store.periodAllPayload ?? store.payload } private var visibleFilters: [ProviderFilter] { - let detectedKeys = Set( - todayAll.current.providers.keys.map { $0.lowercased() } - ) + // Tabs reflect the SELECTED range: every provider with usage (cost > 0) + // in the period, ordered by usage. Providers with no usage in the range + // are omitted. `.all` always leads. cost(for:) reads periodAll, so this + // updates as the user switches periods. + let costs = Dictionary(uniqueKeysWithValues: ProviderFilter.allCases.map { ($0, cost(for: $0) ?? 0) }) let detected = ProviderFilter.allCases.filter { filter in - if filter == .all { return true } - return filter.providerKeys.contains(where: detectedKeys.contains) + filter == .all || (costs[filter] ?? 0) > 0 } - let costs = Dictionary(uniqueKeysWithValues: detected.map { ($0, cost(for: $0) ?? 0) }) return detected.sorted { a, b in if a == .all { return true } if b == .all { return false } @@ -506,6 +502,9 @@ extension ProviderFilter { case .crush: return Color(red: 0xE0/255.0, green: 0x6C/255.0, blue: 0x9F/255.0) case .antigravity: return Color(red: 0xFF/255.0, green: 0x7A/255.0, blue: 0x45/255.0) case .goose: return Color(red: 0xB7/255.0, green: 0x8D/255.0, blue: 0x52/255.0) + case .grok: return Color(red: 0x8E/255.0, green: 0x8E/255.0, blue: 0x93/255.0) + case .hermes: return Color(red: 0xC7/255.0, green: 0x52/255.0, blue: 0x3E/255.0) + case .zcode: return Color(red: 0x52/255.0, green: 0x6E/255.0, blue: 0xD6/255.0) } } }