diff --git a/CHANGELOG.md b/CHANGELOG.md index 123293ee10..23c181a5e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - Display: add optional workday markers for weekly progress bars (#1102). Thanks @Yuxin-Qiao! ### Fixed +- Claude: normalize OAuth extra-usage spend limits from minor units so Enterprise spend displays as currency instead of 100x too high (#1114, fixes #1111). Thanks @Yuxin-Qiao! - OpenCode Go: read local usage history before falling back to browser-cookie dashboard fetches (#1021). Thanks @sopenlaz0! - Menu bar: show extra-usage spend as currency text for Claude and Cursor when that metric is selected (#1107). Thanks @Yuxin-Qiao! - Codex: run regular credits and OpenAI dashboard refreshes in the background while coalescing overlapping refresh work (#1078). Thanks @ptstory! diff --git a/Sources/CodexBarCore/Providers/Claude/ClaudeUsageFetcher.swift b/Sources/CodexBarCore/Providers/Claude/ClaudeUsageFetcher.swift index 7ce2f8790e..d74a66785a 100644 --- a/Sources/CodexBarCore/Providers/Claude/ClaudeUsageFetcher.swift +++ b/Sources/CodexBarCore/Providers/Claude/ClaudeUsageFetcher.swift @@ -954,7 +954,7 @@ extension ClaudeUsageFetcher { let normalized = Self.normalizeClaudeExtraUsageAmounts( used: used, limit: limit, - treatAsMajorUnits: isSpendLimit) + treatAsMajorUnits: false) return ProviderCostSnapshot( used: normalized.used, limit: normalized.limit, diff --git a/Tests/CodexBarTests/ClaudeOAuthTests.swift b/Tests/CodexBarTests/ClaudeOAuthTests.swift index e180075db3..6773f40751 100644 --- a/Tests/CodexBarTests/ClaudeOAuthTests.swift +++ b/Tests/CodexBarTests/ClaudeOAuthTests.swift @@ -200,15 +200,15 @@ struct ClaudeOAuthTests { } @Test - func `maps enterprise O auth spend limit without session windows`() throws { + func `does not display spend limit 100x too high for enterprise O auth`() throws { let json = """ { "extra_usage": { "is_enabled": true, - "monthly_limit": 600, - "used_credits": 434.43, - "utilization": 72, - "currency": "USD" + "monthly_limit": 2000, + "used_credits": 763, + "utilization": 38.15, + "currency": "EUR" } } """ @@ -216,52 +216,55 @@ struct ClaudeOAuthTests { Data(json.utf8), subscriptionType: "enterprise") #expect(snap.loginMethod == "Claude Enterprise") - #expect(snap.primary.usedPercent == 72) + #expect(snap.primary.usedPercent == 38.15) #expect(snap.primaryWindowKind == .spendLimit) #expect(snap.primary.windowMinutes == nil) - #expect(snap.primary.resetDescription == "Spend limit: $434.43 / $600.00") + #expect(snap.primary.resetDescription == "Spend limit: €7.63 / €20.00") #expect(snap.secondary == nil) #expect(snap.providerCost?.period == "Spend limit") - #expect(snap.providerCost?.limit == 600) - #expect(snap.providerCost?.used == 434.43) + #expect(snap.providerCost?.currencyCode == "EUR") + #expect(snap.providerCost?.limit == 20) + #expect(snap.providerCost?.used == 7.63) let usage = ClaudeOAuthFetchStrategy._snapshotForTesting(from: snap) #expect(usage.primary == nil) #expect(usage.providerCost?.period == "Spend limit") - #expect(usage.providerCost?.used == 434.43) + #expect(usage.providerCost?.limit == 20) + #expect(usage.providerCost?.used == 7.63) } @Test - func `maps O auth spend limit without plan metadata as major units`() throws { + func `maps O auth spend limit without plan metadata from minor units`() throws { let json = """ { "extra_usage": { "is_enabled": true, - "monthly_limit": 600, - "used_credits": 434.43, - "utilization": 72, - "currency": "USD" + "monthly_limit": 2000, + "used_credits": 763, + "utilization": 38.15, + "currency": "EUR" } } """ let snap = try ClaudeUsageFetcher._mapOAuthUsageForTesting(Data(json.utf8)) #expect(snap.loginMethod == nil) #expect(snap.primaryWindowKind == .spendLimit) - #expect(snap.primary.usedPercent == 72) - #expect(snap.primary.resetDescription == "Spend limit: $434.43 / $600.00") + #expect(snap.primary.usedPercent == 38.15) + #expect(snap.primary.resetDescription == "Spend limit: €7.63 / €20.00") #expect(snap.providerCost?.period == "Spend limit") - #expect(snap.providerCost?.limit == 600) - #expect(snap.providerCost?.used == 434.43) + #expect(snap.providerCost?.currencyCode == "EUR") + #expect(snap.providerCost?.limit == 20) + #expect(snap.providerCost?.used == 7.63) } @Test - func `maps large enterprise O auth spend limit as major units`() throws { + func `maps large enterprise O auth spend limit from minor units`() throws { let json = """ { "extra_usage": { "is_enabled": true, - "monthly_limit": 10000, - "used_credits": 1234.56, + "monthly_limit": 1000000, + "used_credits": 123456, "utilization": 12.3456, "currency": "USD" }