Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion Sources/CodexBar/StatusItemController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ final class StatusItemController: NSObject, NSMenuDelegate, StatusItemControllin
let usedPercent = (primary.usedPercent + secondary.usedPercent) / 2
return RateWindow(usedPercent: usedPercent, windowMinutes: nil, resetsAt: nil, resetDescription: nil)
case .automatic:
if provider == .factory {
if provider == .factory || provider == .kimi {
return snapshot?.secondary ?? snapshot?.primary
}
return snapshot?.primary ?? snapshot?.secondary
Expand Down
4 changes: 2 additions & 2 deletions Sources/CodexBar/UsageStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -314,8 +314,8 @@ final class UsageStore {
for provider in self.enabledProviders() {
guard let snapshot = self.snapshots[provider] else { continue }
// Use the same window selection logic as menuBarPercentWindow:
// Factory uses secondary (premium) first, others use primary (session) first.
let window: RateWindow? = if provider == .factory {
// Factory and Kimi use secondary first, others use primary first.
let window: RateWindow? = if provider == .factory || provider == .kimi {
snapshot.secondary ?? snapshot.primary
} else {
snapshot.primary ?? snapshot.secondary
Expand Down
39 changes: 39 additions & 0 deletions Tests/CodexBarTests/StatusItemAnimationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,45 @@ struct StatusItemAnimationTests {
#expect(window?.usedPercent == 42)
}

@Test
func menuBarPercentAutomaticPrefersRateLimitForKimi() {
let settings = SettingsStore(
configStore: testConfigStore(suiteName: "StatusItemAnimationTests-kimi-automatic"),
zaiTokenStore: NoopZaiTokenStore())
settings.statusChecksEnabled = false
settings.refreshFrequency = .manual
settings.mergeIcons = true
settings.selectedMenuProvider = .kimi
settings.setMenuBarMetricPreference(.automatic, for: .kimi)

let registry = ProviderRegistry.shared
if let kimiMeta = registry.metadata[.kimi] {
settings.setProviderEnabled(provider: .kimi, metadata: kimiMeta, enabled: true)
}

let fetcher = UsageFetcher()
let store = UsageStore(fetcher: fetcher, browserDetection: BrowserDetection(cacheTTL: 0), settings: settings)
let controller = StatusItemController(
store: store,
settings: settings,
account: fetcher.loadAccountInfo(),
updater: DisabledUpdaterController(),
preferencesSelection: PreferencesSelection(),
statusBar: self.makeStatusBarForTesting())

let snapshot = UsageSnapshot(
primary: RateWindow(usedPercent: 12, windowMinutes: nil, resetsAt: nil, resetDescription: nil),
secondary: RateWindow(usedPercent: 42, windowMinutes: 300, resetsAt: nil, resetDescription: nil),
updatedAt: Date())

store._setSnapshotForTesting(snapshot, provider: .kimi)
store._setErrorForTesting(nil, provider: .kimi)

let window = controller.menuBarMetricWindow(for: .kimi, snapshot: snapshot)

#expect(window?.usedPercent == 42)
}

@Test
func menuBarPercentUsesAverageForGemini() {
let settings = SettingsStore(
Expand Down
28 changes: 28 additions & 0 deletions Tests/CodexBarTests/UsageStoreCoverageTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,34 @@ struct UsageStoreCoverageTests {
#expect(label.contains("openai-web"))
}

@Test
func providerWithHighestUsagePrefersKimiRateLimitWindow() throws {
let settings = Self.makeSettingsStore(suite: "UsageStoreCoverageTests-kimi-highest")
let store = Self.makeUsageStore(settings: settings)
let metadata = ProviderRegistry.shared.metadata

try settings.setProviderEnabled(provider: .codex, metadata: #require(metadata[.codex]), enabled: true)
try settings.setProviderEnabled(provider: .kimi, metadata: #require(metadata[.kimi]), enabled: true)

let now = Date()
store._setSnapshotForTesting(
UsageSnapshot(
primary: RateWindow(usedPercent: 60, windowMinutes: nil, resetsAt: nil, resetDescription: nil),
secondary: nil,
updatedAt: now),
provider: .codex)
store._setSnapshotForTesting(
UsageSnapshot(
primary: RateWindow(usedPercent: 10, windowMinutes: nil, resetsAt: nil, resetDescription: nil),
secondary: RateWindow(usedPercent: 80, windowMinutes: 300, resetsAt: nil, resetDescription: nil),
updatedAt: now),
provider: .kimi)

let highest = store.providerWithHighestUsage()
#expect(highest?.provider == .kimi)
#expect(highest?.usedPercent == 80)
}

@Test
func providerAvailabilityAndSubscriptionDetection() {
let zaiStore = InMemoryZaiTokenStore(value: "zai-token")
Expand Down