+
Tiny macOS 14+ menu bar app that keeps **AI coding-provider limits visible** and shows when each window resets. Codex, OpenAI, Claude, Cursor, Gemini, Copilot, Grok, GroqCloud, ElevenLabs, Deepgram, z.ai, MiniMax, Kiro, Zed, Vertex AI, Augment, OpenRouter, LiteLLM, LLM Proxy, Codebuff, Command Code, ClinePass, AWS Bedrock, and many newer coding providers. One status item per provider, or Merge Icons mode with a provider switcher. No Dock icon, minimal UI, dynamic bar icons.
diff --git a/Sources/CodexBar/CodexbarApp.swift b/Sources/CodexBar/CodexbarApp.swift
index e7b71bfb82..5929389e35 100644
--- a/Sources/CodexBar/CodexbarApp.swift
+++ b/Sources/CodexBar/CodexbarApp.swift
@@ -450,6 +450,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
resetKind: String)
{
let origin = self.statusController?.celebrationOriginPoint(for: provider)
+ let palette = ProviderDescriptorRegistry.descriptor(for: provider).branding.confettiPalette
self.confettiLogger.info(
"Triggering confetti",
metadata: [
@@ -458,7 +459,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
"resetKind": resetKind,
"originKnown": origin == nil ? "0" : "1",
])
- self.confettiOverlayController.play(originInScreen: origin)
+ self.confettiOverlayController.play(originInScreen: origin, colors: palette)
}
/// Use the classic (non-Liquid Glass) app icon on macOS versions before 26.
diff --git a/Sources/CodexBar/CostHistoryChartMenuView.swift b/Sources/CodexBar/CostHistoryChartMenuView.swift
index f45b88e316..91621db129 100644
--- a/Sources/CodexBar/CostHistoryChartMenuView.swift
+++ b/Sources/CodexBar/CostHistoryChartMenuView.swift
@@ -48,6 +48,7 @@ struct CostHistoryChartMenuView: View {
private let historyDays: Int
private let windowLabel: String?
private let projects: [CostUsageProjectBreakdown]
+ private let sessions: [CostUsageSessionBreakdown]
private let width: CGFloat
@State private var selectedDateKey: String?
@@ -59,6 +60,7 @@ struct CostHistoryChartMenuView: View {
historyDays: Int = 30,
windowLabel: String? = nil,
projects: [CostUsageProjectBreakdown] = [],
+ sessions: [CostUsageSessionBreakdown] = [],
width: CGFloat)
{
self.provider = provider
@@ -68,6 +70,7 @@ struct CostHistoryChartMenuView: View {
self.historyDays = max(1, min(365, historyDays))
self.windowLabel = windowLabel
self.projects = projects
+ self.sessions = sessions
self.width = width
}
@@ -284,6 +287,10 @@ struct CostHistoryChartMenuView: View {
}
.frame(height: Self.projectBlockHeight(projects: self.projects), alignment: .topLeading)
}
+
+ if !self.sessions.isEmpty {
+ self.sessionsBlock
+ }
}
.padding(.horizontal, 16)
.padding(.vertical, Self.verticalPadding)
@@ -327,8 +334,95 @@ struct CostHistoryChartMenuView: View {
private static let projectSourceIndent: CGFloat = 10
private static let projectMoreRowHeight: CGFloat = 16
private static let maxVisibleProjectSourceRows = 2
+ private static let sessionRowHeight: CGFloat = 44
+ private static let sessionRowSpacing: CGFloat = 5
+ private static let maxVisibleSessionRows = 5
static let verticalPadding: CGFloat = 10
+ private var sessionsBlock: some View {
+ let visibleCount = min(self.sessions.count, Self.maxVisibleSessionRows)
+ return VStack(alignment: .leading, spacing: Self.sessionRowSpacing) {
+ HStack {
+ Text("Conversations (\(self.windowLabel ?? Self.windowLabel(days: self.historyDays)))")
+ .font(.caption)
+ .foregroundStyle(.secondary)
+ .lineLimit(1)
+ Spacer()
+ Text("\(self.sessions.count)")
+ .font(.caption2)
+ .foregroundStyle(Color(nsColor: .tertiaryLabelColor))
+ }
+ .frame(height: Self.detailPrimaryLineHeight, alignment: .leading)
+
+ ScrollView(.vertical) {
+ LazyVStack(alignment: .leading, spacing: Self.sessionRowSpacing) {
+ ForEach(self.sessions) { session in
+ self.sessionRow(session)
+ }
+ }
+ }
+ .scrollIndicators(self.sessions.count > visibleCount ? .visible : .hidden)
+ .frame(
+ height: CGFloat(visibleCount) * Self.sessionRowHeight
+ + CGFloat(max(visibleCount - 1, 0)) * Self.sessionRowSpacing,
+ alignment: .topLeading)
+ }
+ .frame(
+ height: Self.detailPrimaryLineHeight + Self.sessionRowSpacing
+ + CGFloat(visibleCount) * Self.sessionRowHeight
+ + CGFloat(max(visibleCount - 1, 0)) * Self.sessionRowSpacing,
+ alignment: .topLeading)
+ }
+
+ private func sessionRow(_ session: CostUsageSessionBreakdown) -> some View {
+ HStack(alignment: .top, spacing: 8) {
+ VStack(alignment: .leading, spacing: 1) {
+ Text("Session \(Self.shortSessionID(session.sessionID))")
+ .font(.caption)
+ .foregroundStyle(.secondary)
+ .lineLimit(1)
+ Text(Self.sessionUsageLine(session))
+ .font(.caption2)
+ .foregroundStyle(Color(nsColor: .tertiaryLabelColor))
+ .lineLimit(1)
+ .truncationMode(.tail)
+ Text(session.lastActivity, format: .dateTime.month(.abbreviated).day().hour().minute())
+ .font(.caption2)
+ .foregroundStyle(Color(nsColor: .tertiaryLabelColor))
+ .lineLimit(1)
+ }
+ Spacer(minLength: 8)
+ Text(session.costUSD.map(self.costString) ?? "—")
+ .font(.caption)
+ .monospacedDigit()
+ .foregroundStyle(.secondary)
+ .lineLimit(1)
+ }
+ .frame(height: Self.sessionRowHeight, alignment: .topLeading)
+ .accessibilityElement(children: .combine)
+ }
+
+ static func shortSessionID(_ sessionID: String) -> String {
+ let trimmed = sessionID.trimmingCharacters(in: .whitespacesAndNewlines)
+ guard trimmed.count > 12 else { return trimmed }
+ return "\(trimmed.prefix(4))...\(trimmed.suffix(8))"
+ }
+
+ private static func sessionUsageLine(_ session: CostUsageSessionBreakdown) -> String {
+ let models = session.modelBreakdowns.map(\.modelName)
+ let modelLabel = if models.isEmpty {
+ "Unknown model"
+ } else if models.count == 1 {
+ models[0]
+ } else {
+ "\(models[0]) +\(models.count - 1)"
+ }
+ let input = session.inputTokens.map(UsageFormatter.tokenCountString) ?? "—"
+ let cached = session.cachedInputTokens.map(UsageFormatter.tokenCountString) ?? "—"
+ let output = session.outputTokens.map(UsageFormatter.tokenCountString) ?? "—"
+ return "\(modelLabel) · \(input) input · \(cached) cached · \(output) output"
+ }
+
static func windowLabel(days: Int) -> String {
if days == 1 {
return L("Today")
@@ -788,6 +882,7 @@ extension CostHistoryChartMenuView {
let hasDailyEntries: Bool
let daily: [VisibleDailyFingerprint]
let projects: [VisibleProjectFingerprint]
+ let sessions: [VisibleSessionFingerprint]
}
struct VisibleDailyFingerprint: Equatable {
@@ -824,11 +919,23 @@ extension CostHistoryChartMenuView {
let totalCostBitPattern: UInt64?
}
+ struct VisibleSessionFingerprint: Equatable {
+ let sessionID: String
+ let lastActivityBitPattern: UInt64
+ let inputTokens: Int?
+ let cachedInputTokens: Int?
+ let outputTokens: Int?
+ let totalTokens: Int?
+ let costBitPattern: UInt64?
+ let models: [VisibleModelBreakdownFingerprint]
+ }
+
static func renderFingerprint(
from snapshot: CostUsageTokenSnapshot,
provider: UsageProvider) -> RenderFingerprint
{
let projects = provider == .codex ? snapshot.projects : []
+ let sessions = provider == .codex ? snapshot.sessions : []
return RenderFingerprint(
currencyCode: snapshot.currencyCode,
historyDays: snapshot.historyDays,
@@ -854,6 +961,26 @@ extension CostHistoryChartMenuView {
totalTokens: source.totalTokens,
totalCostBitPattern: source.totalCostUSD.map(\.bitPattern))
})
+ },
+ sessions: sessions.map { session in
+ VisibleSessionFingerprint(
+ sessionID: session.sessionID,
+ lastActivityBitPattern: session.lastActivity.timeIntervalSince1970.bitPattern,
+ inputTokens: session.inputTokens,
+ cachedInputTokens: session.cachedInputTokens,
+ outputTokens: session.outputTokens,
+ totalTokens: session.totalTokens,
+ costBitPattern: session.costUSD.map(\.bitPattern),
+ models: session.modelBreakdowns.map { item in
+ VisibleModelBreakdownFingerprint(
+ modelName: item.modelName,
+ costBitPattern: item.costUSD.map(\.bitPattern),
+ totalTokens: item.totalTokens,
+ standardCostBitPattern: item.standardCostUSD.map(\.bitPattern),
+ priorityCostBitPattern: item.priorityCostUSD.map(\.bitPattern),
+ standardTokens: item.standardCostUSD == nil ? nil : item.standardTokens,
+ priorityTokens: item.priorityCostUSD == nil ? nil : item.priorityTokens)
+ })
})
}
diff --git a/Sources/CodexBar/MenuCardView+Costs.swift b/Sources/CodexBar/MenuCardView+Costs.swift
index fc587dd330..a2362fd3dd 100644
--- a/Sources/CodexBar/MenuCardView+Costs.swift
+++ b/Sources/CodexBar/MenuCardView+Costs.swift
@@ -342,7 +342,9 @@ extension UsageMenuCardView.Model {
percentLine: nil)
}
- if provider == .openai || provider == .claude || provider == .litellm, cost.limit <= 0 {
+ if provider == .openai || provider == .claude || provider == .litellm || provider == .aiand,
+ cost.limit <= 0
+ {
let spend = UsageFormatter.currencyString(cost.used, currencyCode: cost.currencyCode)
let periodLabel = Self.localizedPeriodLabel(cost.period ?? "Last 30 days")
return ProviderCostSection(
diff --git a/Sources/CodexBar/MenuCardView+ModelHelpers.swift b/Sources/CodexBar/MenuCardView+ModelHelpers.swift
index 101ce3b7c7..ca2c5e6552 100644
--- a/Sources/CodexBar/MenuCardView+ModelHelpers.swift
+++ b/Sources/CodexBar/MenuCardView+ModelHelpers.swift
@@ -341,6 +341,15 @@ extension UsageMenuCardView.Model {
else {
return nil
}
+ // Local Codex session costs are independent from OAuth, CLI quota, and OpenAI web
+ // dashboard access. Do not present a failed account-level quota fetch as a failure of
+ // a valid local API-key ledger.
+ if input.codexLocalSessionCostLedgerEnabled,
+ self.hasLocalCodexTokenUsage(input),
+ self.isRemoteCodexQuotaFetchError(lastError)
+ {
+ return nil
+ }
if self.shouldShowRateLimitsUnavailablePlaceholder(input: input, lastError: lastError) {
return nil
}
@@ -402,6 +411,10 @@ extension UsageMenuCardView.Model {
self.tokenUsageSnapshot(input: input) != nil
}
+ private static func isRemoteCodexQuotaFetchError(_ error: String) -> Bool {
+ error.localizedCaseInsensitiveContains("Codex usage is temporarily unavailable")
+ }
+
private static func shouldShowRateLimitsUnavailablePlaceholder(input: Input, lastError: String? = nil) -> Bool {
let currentError = lastError ?? input.lastError
if let currentError = currentError?.trimmingCharacters(in: .whitespacesAndNewlines),
diff --git a/Sources/CodexBar/MenuCardView+ModelInput.swift b/Sources/CodexBar/MenuCardView+ModelInput.swift
index c3bcde4ea4..1e7094a989 100644
--- a/Sources/CodexBar/MenuCardView+ModelInput.swift
+++ b/Sources/CodexBar/MenuCardView+ModelInput.swift
@@ -22,6 +22,7 @@ extension UsageMenuCardView.Model {
let usageBarsShowUsed: Bool
let resetTimeDisplayStyle: ResetTimeDisplayStyle
let tokenCostUsageEnabled: Bool
+ let codexLocalSessionCostLedgerEnabled: Bool
let tokenCostInlineDashboardEnabled: Bool
let tokenCostMenuSectionEnabled: Bool
let costComparisonPeriodsEnabled: Bool
@@ -57,6 +58,7 @@ extension UsageMenuCardView.Model {
usageBarsShowUsed: Bool,
resetTimeDisplayStyle: ResetTimeDisplayStyle,
tokenCostUsageEnabled: Bool,
+ codexLocalSessionCostLedgerEnabled: Bool = false,
tokenCostInlineDashboardEnabled: Bool? = nil,
tokenCostMenuSectionEnabled: Bool? = nil,
costComparisonPeriodsEnabled: Bool = false,
@@ -91,6 +93,7 @@ extension UsageMenuCardView.Model {
self.usageBarsShowUsed = usageBarsShowUsed
self.resetTimeDisplayStyle = resetTimeDisplayStyle
self.tokenCostUsageEnabled = tokenCostUsageEnabled
+ self.codexLocalSessionCostLedgerEnabled = codexLocalSessionCostLedgerEnabled
self.tokenCostInlineDashboardEnabled = tokenCostInlineDashboardEnabled ?? tokenCostUsageEnabled
self.tokenCostMenuSectionEnabled = tokenCostMenuSectionEnabled ?? tokenCostUsageEnabled
self.costComparisonPeriodsEnabled = costComparisonPeriodsEnabled
diff --git a/Sources/CodexBar/PreferencesProvidersPane.swift b/Sources/CodexBar/PreferencesProvidersPane.swift
index 386c100738..abf01793e8 100644
--- a/Sources/CodexBar/PreferencesProvidersPane.swift
+++ b/Sources/CodexBar/PreferencesProvidersPane.swift
@@ -98,7 +98,9 @@ struct ProvidersPane: View {
isPresented: Binding(
get: { self.activeConfirmation != nil },
set: { isPresented in
- if !isPresented { self.activeConfirmation = nil }
+ if !isPresented {
+ self.activeConfirmation = nil
+ }
}),
actions: {
if let active = self.activeConfirmation {
@@ -684,6 +686,7 @@ struct ProvidersPane: View {
usageBarsShowUsed: self.settings.usageBarsShowUsed,
resetTimeDisplayStyle: self.settings.resetTimeDisplayStyle,
tokenCostUsageEnabled: self.settings.isCostUsageEffectivelyEnabled(for: provider),
+ codexLocalSessionCostLedgerEnabled: self.settings.codexLocalSessionCostLedgerEnabled,
tokenCostInlineDashboardEnabled: self.settings.costSummaryShowsInlineDashboard(for: provider),
// Display style only controls the main menu. Provider details always expose
// available cost data in their Usage section.
diff --git a/Sources/CodexBar/Providers/AiAnd/AiAndProviderImplementation.swift b/Sources/CodexBar/Providers/AiAnd/AiAndProviderImplementation.swift
new file mode 100644
index 0000000000..34baab3658
--- /dev/null
+++ b/Sources/CodexBar/Providers/AiAnd/AiAndProviderImplementation.swift
@@ -0,0 +1,52 @@
+import AppKit
+import CodexBarCore
+import Foundation
+
+struct AiAndProviderImplementation: ProviderImplementation {
+ let id: UsageProvider = .aiand
+
+ @MainActor
+ func presentation(context _: ProviderPresentationContext) -> ProviderPresentation {
+ ProviderPresentation { _ in "api" }
+ }
+
+ @MainActor
+ func observeSettings(_ settings: SettingsStore) {
+ _ = settings.aiAndAPIKey
+ }
+
+ @MainActor
+ func isAvailable(context: ProviderAvailabilityContext) -> Bool {
+ if AiAndSettingsReader.apiKey(environment: context.environment) != nil {
+ return true
+ }
+ return !context.settings.aiAndAPIKey.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
+ }
+
+ @MainActor
+ func settingsFields(context: ProviderSettingsContext) -> [ProviderSettingsFieldDescriptor] {
+ [
+ ProviderSettingsFieldDescriptor(
+ id: "aiand-api-key",
+ title: "API key",
+ subtitle: "Stored in CodexBar's config file. Create a key in the ai& console (shown once).",
+ kind: .secure,
+ placeholder: "sk-…",
+ binding: context.stringBinding(\.aiAndAPIKey),
+ actions: [
+ ProviderSettingsActionDescriptor(
+ id: "aiand-open-console",
+ title: "Open ai& Console",
+ style: .link,
+ isVisible: nil,
+ perform: {
+ if let url = URL(string: "https://console.aiand.com") {
+ NSWorkspace.shared.open(url)
+ }
+ }),
+ ],
+ isVisible: nil,
+ onActivate: nil),
+ ]
+ }
+}
diff --git a/Sources/CodexBar/Providers/AiAnd/AiAndSettingsStore.swift b/Sources/CodexBar/Providers/AiAnd/AiAndSettingsStore.swift
new file mode 100644
index 0000000000..73e5b26b24
--- /dev/null
+++ b/Sources/CodexBar/Providers/AiAnd/AiAndSettingsStore.swift
@@ -0,0 +1,14 @@
+import CodexBarCore
+import Foundation
+
+extension SettingsStore {
+ var aiAndAPIKey: String {
+ get { self.configSnapshot.providerConfig(for: .aiand)?.sanitizedAPIKey ?? "" }
+ set {
+ self.updateProviderConfig(provider: .aiand) { entry in
+ entry.apiKey = self.normalizedConfigValue(newValue)
+ }
+ self.logSecretUpdate(provider: .aiand, field: "apiKey", value: newValue)
+ }
+ }
+}
diff --git a/Sources/CodexBar/Providers/Codex/CodexProviderImplementation.swift b/Sources/CodexBar/Providers/Codex/CodexProviderImplementation.swift
index f21275e6db..5744287c09 100644
--- a/Sources/CodexBar/Providers/Codex/CodexProviderImplementation.swift
+++ b/Sources/CodexBar/Providers/Codex/CodexProviderImplementation.swift
@@ -76,6 +76,22 @@ struct CodexProviderImplementation: ProviderImplementation {
].joined(separator: " ")
return [
+ ProviderSettingsToggleDescriptor(
+ id: "codex-local-session-cost-ledger",
+ title: "Local session cost estimates",
+ subtitle: [
+ "Uses this Mac's Codex sessions instead of the selected managed account's session history.",
+ "Works with organization API keys and does not require OpenAI billing or administrator access.",
+ "Uses locally cached or bundled model prices without making a network request.",
+ "This provider-specific toggle does not enable cost summaries for other providers.",
+ ].joined(separator: " "),
+ binding: context.boolBinding(\.codexLocalSessionCostLedgerEnabled),
+ statusText: nil,
+ actions: [],
+ isVisible: nil,
+ onChange: nil,
+ onAppDidBecomeActive: nil,
+ onAppearWhenEnabled: nil),
ProviderSettingsToggleDescriptor(
id: "codex-historical-tracking",
title: "Historical tracking",
@@ -165,8 +181,11 @@ struct CodexProviderImplementation: ProviderImplementation {
return [
ProviderSettingsPickerDescriptor(
id: "codex-usage-source",
- title: "Usage source",
- subtitle: "Auto falls back to the next source if the preferred one fails.",
+ title: "Quota usage source",
+ subtitle: [
+ "Controls live session and weekly quota fetching only.",
+ "Local session cost estimates work independently.",
+ ].joined(separator: " "),
binding: usageBinding,
options: usageOptions,
isVisible: nil,
diff --git a/Sources/CodexBar/Providers/Codex/UsageStore+CodexRefresh.swift b/Sources/CodexBar/Providers/Codex/UsageStore+CodexRefresh.swift
index af04e29329..e6b7d06682 100644
--- a/Sources/CodexBar/Providers/Codex/UsageStore+CodexRefresh.swift
+++ b/Sources/CodexBar/Providers/Codex/UsageStore+CodexRefresh.swift
@@ -9,7 +9,7 @@ extension UsageStore {
func codexCreditsFetcher() -> UsageFetcher {
// Credits are remote Codex account state, so they need the same managed-home routing as the
- // primary Codex usage fetch. Local token-cost scanning intentionally stays ambient-system scoped.
+ // primary Codex usage fetch. Token-cost scanning owns its selected managed or ambient scope separately.
self.makeFetchContext(provider: .codex, override: nil).fetcher
}
diff --git a/Sources/CodexBar/Providers/Shared/ProviderImplementationRegistry.swift b/Sources/CodexBar/Providers/Shared/ProviderImplementationRegistry.swift
index e47311cde1..1883844b3a 100644
--- a/Sources/CodexBar/Providers/Shared/ProviderImplementationRegistry.swift
+++ b/Sources/CodexBar/Providers/Shared/ProviderImplementationRegistry.swift
@@ -73,6 +73,7 @@ enum ProviderImplementationRegistry {
case .sub2api: Sub2APIProviderImplementation()
case .wayfinder: WayfinderProviderImplementation()
case .zenmux: ZenMuxProviderImplementation()
+ case .aiand: AiAndProviderImplementation()
}
}
diff --git a/Sources/CodexBar/Resources/ProviderIcon-aiand.svg b/Sources/CodexBar/Resources/ProviderIcon-aiand.svg
new file mode 100644
index 0000000000..68cba8283f
--- /dev/null
+++ b/Sources/CodexBar/Resources/ProviderIcon-aiand.svg
@@ -0,0 +1,6 @@
+
diff --git a/Sources/CodexBar/ScreenConfettiOverlayController.swift b/Sources/CodexBar/ScreenConfettiOverlayController.swift
index acacceb5e7..b6544bad42 100644
--- a/Sources/CodexBar/ScreenConfettiOverlayController.swift
+++ b/Sources/CodexBar/ScreenConfettiOverlayController.swift
@@ -11,7 +11,7 @@ final class ScreenConfettiOverlayController {
private var windows: [NSWindow] = []
private var dismissalTask: Task
Popular providers become status items with their own usage windows, reset countdowns, charts, and provider menus.
diff --git a/docs/llms.txt b/docs/llms.txt
index 9d0f911716..0eef651a3f 100644
--- a/docs/llms.txt
+++ b/docs/llms.txt
@@ -1,9 +1,9 @@
# CodexBar
-A tiny macOS menu bar app that tracks AI coding-provider usage windows, credits, costs, and resets across 60 providers — Codex, OpenAI, Claude, Cursor, Gemini, Copilot, LiteLLM, and more.
+A tiny macOS menu bar app that tracks AI coding-provider usage windows, credits, costs, and resets across 61 providers — Codex, OpenAI, Claude, Cursor, Gemini, Copilot, LiteLLM, and more.
Canonical documentation:
-- CodexBar — every AI coding limit, in your menu bar: https://codexbar.app/ - A tiny macOS menu bar app that tracks AI coding-provider usage windows, credits, costs, and resets across 60 providers — Codex, OpenAI, Claude, Cursor, Gemini, Copilot, LiteLLM, and more.
+- CodexBar — every AI coding limit, in your menu bar: https://codexbar.app/ - A tiny macOS menu bar app that tracks AI coding-provider usage windows, credits, costs, and resets across 61 providers — Codex, OpenAI, Claude, Cursor, Gemini, Copilot, LiteLLM, and more.
Source: https://github.com/steipete/CodexBar
diff --git a/docs/provider.md b/docs/provider.md
index 4a2be9894a..6fd968d36f 100644
--- a/docs/provider.md
+++ b/docs/provider.md
@@ -47,7 +47,7 @@ Provider behavior is descriptor-driven. Two explicit, exhaustive registries form
Introduce a single descriptor per provider:
- `id` (stable `UsageProvider`)
- display/labels/URLs (menu title, dashboard URL, status URL)
-- UI branding (icon name, primary color)
+- UI branding (icon name, primary color, 2–3-color confetti palette)
- capabilities (supportsCredits, supportsTokenCost, supportsStatusPolling, supportsLogin)
- fetch plan (allowed `--source` modes + ordered strategy pipeline)
- CLI metadata (cliName, aliases, version provider)
@@ -122,7 +122,11 @@ public enum ExampleProviderDescriptor {
branding: ProviderBranding(
iconStyle: .codex,
iconResourceName: "ProviderIcon-example",
- color: ProviderColor(red: 0.2, green: 0.6, blue: 0.8)),
+ color: ProviderColor(red: 0.2, green: 0.6, blue: 0.8),
+ confettiPalette: [
+ ProviderColor(hex: 0x3399CC),
+ ProviderColor(hex: 0x66C2FF),
+ ]),
tokenCost: ProviderTokenCostConfig(
supportsTokenCost: false,
noDataMessage: { "Example cost summary is not supported." }),
@@ -187,9 +191,10 @@ Checklist:
- Add `Sources/CodexBar/Providers/ 60 providers·usage windows, credits, resets·one status item each, or merged. 61 providers·usage windows, credits, resets·one status item each, or merged.Every AI coding limit, in your menu bar.
-