diff --git a/mac/Sources/CodeBurnMenubar/AppStore.swift b/mac/Sources/CodeBurnMenubar/AppStore.swift index cd26d76..db3e2da 100644 --- a/mac/Sources/CodeBurnMenubar/AppStore.swift +++ b/mac/Sources/CodeBurnMenubar/AppStore.swift @@ -213,6 +213,8 @@ enum ProviderFilter: String, CaseIterable, Identifiable { case codex = "Codex" case cursor = "Cursor" case copilot = "Copilot" + case opencode = "OpenCode" + case pi = "Pi" var id: String { rawValue } @@ -224,6 +226,8 @@ enum ProviderFilter: String, CaseIterable, Identifiable { case .codex: "codex" case .cursor: "cursor" case .copilot: "copilot" + case .opencode: "opencode" + case .pi: "pi" } } } diff --git a/mac/Sources/CodeBurnMenubar/Views/AgentTabStrip.swift b/mac/Sources/CodeBurnMenubar/Views/AgentTabStrip.swift index 4feb180..885bdcc 100644 --- a/mac/Sources/CodeBurnMenubar/Views/AgentTabStrip.swift +++ b/mac/Sources/CodeBurnMenubar/Views/AgentTabStrip.swift @@ -33,7 +33,16 @@ struct AgentTabStrip: View { } private var visibleFilters: [ProviderFilter] { - let activeKeys = Set(allProvidersToday.current.providers.keys.map { $0.lowercased() }) + // Only surface providers that actually spent money in the all-provider view. + // The CLI includes zero-cost providers in the payload for completeness, so + // filtering on value > 0 keeps the tab row honest and avoids showing tabs + // for tools the user hasn't run yet. + let activeKeys = Set( + allProvidersToday.current.providers + .filter { $0.value > 0 } + .keys + .map { $0.lowercased() } + ) return ProviderFilter.allCases.filter { filter in if filter == .all { return true } return activeKeys.contains(filter.rawValue.lowercased()) @@ -87,6 +96,8 @@ extension ProviderFilter { case .codex: return Theme.categoricalCodex case .cursor: return Theme.categoricalCursor case .copilot: return Color(red: 0x6D/255.0, green: 0x8F/255.0, blue: 0xA6/255.0) + case .opencode: return Color(red: 0x5B/255.0, green: 0x83/255.0, blue: 0x5B/255.0) + case .pi: return Color(red: 0xB2/255.0, green: 0x6B/255.0, blue: 0x3D/255.0) } } } diff --git a/mac/Sources/CodeBurnMenubar/Views/MenuBarContent.swift b/mac/Sources/CodeBurnMenubar/Views/MenuBarContent.swift index b6c550d..3c08c27 100644 --- a/mac/Sources/CodeBurnMenubar/Views/MenuBarContent.swift +++ b/mac/Sources/CodeBurnMenubar/Views/MenuBarContent.swift @@ -11,9 +11,10 @@ struct MenuBarContent: View { Divider() - AgentTabStrip() - - Divider() + if showAgentTabs { + AgentTabStrip() + Divider() + } ZStack { ScrollView(.vertical, showsIndicators: false) { @@ -63,6 +64,15 @@ struct MenuBarContent: View { return store.payload.current.cost <= 0 && store.payload.current.calls == 0 } + /// Only show the tab row when two or more providers have non-zero spend. One + /// provider means the tabs are redundant (the All tab already shows it); zero + /// providers means the popover has nothing to filter. + private var showAgentTabs: Bool { + let payload = store.todayPayload ?? store.payload + let active = payload.current.providers.values.filter { $0 > 0 } + return active.count >= 2 + } + } private struct EmptyProviderState: View {