Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
d90282e
Fix Claude scoped weekly pace
smkwray Jul 21, 2026
7986d05
Fix Crof usage for PAYG credits-only API
cursoragent Jul 22, 2026
14467c1
Fix Crof test line length for SwiftLint
cursoragent Jul 22, 2026
a61c12a
fix: preserve optional Crof request quotas
steipete Jul 29, 2026
66bb13c
docs: describe optional Crof quotas
steipete Jul 29, 2026
47d3f8b
fix: limit Claude pace to weekly windows
steipete Jul 29, 2026
1196987
feat: add xAI platform billing provider
SilentKnight87 Jul 28, 2026
13964bc
Render xAI prepaid balance in CLI text output
SilentKnight87 Jul 28, 2026
42ca2f9
Preserve xAI login-method acronym and document ledger posting lag
SilentKnight87 Jul 28, 2026
c4313ca
chore: remove contributor changelog entry
steipete Jul 29, 2026
b82594e
refactor: simplify primary metric presentation
steipete Jul 29, 2026
4a29d80
fix(providers): classify StepFun plan by payload shape, not a hard-co…
Jul 29, 2026
4f6b23f
fix: recognize exhausted StepFun credit pools
steipete Jul 29, 2026
8909956
feat: multi-currency cost display with live exchange rates (Issue #2449)
Yuxin-Qiao Jul 29, 2026
d0f79d4
fix: resolve swiftlint warnings for currency exchange feature
Yuxin-Qiao Jul 29, 2026
e1e2cc2
fix: complete preferred currency support
Yuxin-Qiao Jul 29, 2026
75ef604
fix: support currency rate fetches on Linux
Yuxin-Qiao Jul 29, 2026
98272df
fix: make currency rates opt in
steipete Jul 29, 2026
d606183
fix: guard currency rate fetch call sites
steipete Jul 29, 2026
5bbb0d6
Exclude Crof PAYG balances from session quota alerts
cursoragent Jul 29, 2026
915a7a2
Narrow Crof quota exclusion to credits-only snapshots
cursoragent Jul 29, 2026
1617f76
Suppress quota warnings for credits-only Crof; extract Crof tests to …
steipete Jul 29, 2026
1a302e7
Merge main; regenerate parser hash
steipete Jul 29, 2026
8283b8e
Merge remote-tracking branch 'origin/main' into HEAD
steipete Jul 29, 2026
5213ebf
Merge pull request #2492 from LeoLin990405/fix/stepfun-plan-classific…
steipete Jul 29, 2026
35626eb
Merge pull request #2490 from Yuxin-Qiao/feat/currency-exchange-2449
steipete Jul 29, 2026
5e36df1
Merge pull request #2372 from smkwray/agent/claude-scoped-weekly-pace
steipete Jul 29, 2026
c801317
Merge pull request #2472 from SilentKnight87/feat/xai-platform-provider
steipete Jul 29, 2026
8ef8607
Merge pull request #2401 from baanish/main
steipete Jul 29, 2026
3f41d2a
Merge remote-tracking branch 'upstream/main' into automation/upstream…
ColumbusLabs Jul 29, 2026
cfb4d65
Adapt upstream xAI and currency changes for QuotaKit
ColumbusLabs Jul 29, 2026
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ on Columbus Labs QuotaKit releases and product-facing changes.
- Overview: raise the merged provider limit from three to six.

### Changed
- Synced upstream CodexBar changes through `8ef86077e`, including preferred-currency conversion, xAI billing history, Claude weekly pacing, optional Crof quota alerts, and StepFun support while preserving QuotaKit release ownership, public URLs, config paths, CloudKit setup, and all build numbers.
- CLI: redact stored credentials from `quotakit config dump` by default; use `--show-secrets` to reveal raw values.
- Menu bar: remove status-item hover tooltips while retaining VoiceOver titles.
- Cost displays: use consistent labels while preserving reported-versus-estimated provenance in settings and per-value hints.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ enum ProviderBrandAsset {
"vertexai",
"warp",
"windsurf",
"xai",
"zai",
"zed",
"zenmux",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ enum ProviderColorPalette {
(["deepgram"], RawColor(red: 0.49, green: 0.23, blue: 0.93)),
(["aiand", "ai&"], RawColor(red: 226 / 255, green: 92 / 255, blue: 43 / 255)),
(["zoommate"], RawColor(red: 64 / 255, green: 176 / 255, blue: 255 / 255)),
(["xai"], RawColor(red: 142 / 255, green: 142 / 255, blue: 160 / 255)),
(["devin"], RawColor(red: 70 / 255, green: 180 / 255, blue: 130 / 255)),
]

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"images" : [
{
"filename" : "ProviderIcon-xai.svg",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"preserves-vector-representation" : true,
"template-rendering-intent" : "template"
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ struct ProviderBrandAssetTests {
#expect(ProviderBrandAsset.assetName(for: "neuralwatt") == "ProviderIcon-neuralwatt")
#expect(ProviderBrandAsset.assetName(for: "qwencloud") == "ProviderIcon-qwencloud")
#expect(ProviderBrandAsset.assetName(for: "zoommate") == "ProviderIcon-zoommate")
#expect(ProviderBrandAsset.assetName(for: "xai") == "ProviderIcon-xai")
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ struct ProviderColorPaletteTests {
("longcat", 1, 209 / 255, 0),
("neuralwatt", 0.12, 0.72, 0.38),
("zoommate", 64 / 255, 176 / 255, 255 / 255),
("xai", 142 / 255, 142 / 255, 160 / 255),
]

for (provider, red, green, blue) in expected {
Expand All @@ -93,6 +94,7 @@ struct ProviderColorPaletteTests {
("Qoder", "qoder"),
("Qwen Cloud", "qwencloud"),
("ZoomMate", "zoommate"),
("xAI", "xai"),
]

for (displayName, providerID) in pairs {
Expand Down Expand Up @@ -148,7 +150,7 @@ private let knownDistinctProviders = [
"doubao", "sakana", "abacus", "mistral", "deepseek", "codebuff", "crof", "venice",
"commandcode", "qoder", "stepfun", "bedrock", "grok", "groq", "llmproxy", "litellm", "deepgram",
"crossmodel", "clinepass", "longcat", "deepinfra", "aiand",
"zenmux", "zoommate",
"zenmux", "zoommate", "xai",
]

private func expectDistinctColors(
Expand Down
26 changes: 14 additions & 12 deletions CodexBarMobile/CodexBarMobileTests/QuotaProviderListTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import Testing
@Suite("Quota provider list")
struct QuotaProviderListTests {
@Test
func `Total count is 58 including Qwen Cloud and ZoomMate`() {
func `Total count is 59 including xAI`() {
// Outcome: 25 → 27 in iOS 1.5.0 (Abacus + Mistral) →
// 38 in iOS 1.6.0 (11 new from Mac v0.24+v0.25 catch-up) →
// 40 in iOS 1.7.0 (2 new from Mac v0.26.0: moonshot + bedrock) →
Expand All @@ -29,17 +29,17 @@ struct QuotaProviderListTests {
// 49 in iOS 1.10.0 (Sakana AI from upstream v0.36.x) →
// 50 after Qoder, 51 after Sub2API, 52 after ZenMux, 54 after
// ClinePass and LongCat, 55 after Neuralwatt, 56 after DeepInfra,
// then 58 after Qwen Cloud and ZoomMate.
// then 58 after Qwen Cloud and ZoomMate, and 59 after xAI.
// ai& is spend-only and has no quota transitions, so it intentionally
// does not consume three CloudKit quota-zone subscriptions.
// If this number shifts without matching upstream updates,
// the push-subscription set drifts out of sync with Mac's
// actual emitting providers.
#expect(QuotaProviderList.providers.count == 58)
#expect(QuotaProviderList.providers.count == 59)
}

@Test
func `Subscription zone count is 174 (58 providers × 3 states)`() {
func `Subscription zone count is 177 (59 providers × 3 states)`() {
// iOS 1.5.0: 27 × 2 = 54 zones.
// iOS 1.6.0 / Mac 0.25.2: 38 × 3 (depleted/restored/warning) = 114.
// iOS 1.7.0 / Mac 0.26.2: 40 × 3 = 120 zones (+moonshot, +bedrock).
Expand All @@ -53,10 +53,11 @@ struct QuotaProviderListTests {
// Neuralwatt catch-up: 55 × 3 = 165 zones.
// DeepInfra catch-up: 56 × 3 = 168 zones.
// Qwen Cloud + ZoomMate catch-up: 58 × 3 = 174 zones.
// xAI platform billing: 59 × 3 = 177 zones.
// `QuotaTransitionSubscriptions.makeConfigs()` builds one
// `SubConfig` per (provider, state) — pinning here so a
// future state addition/removal can't drift silently.
#expect(QuotaProviderList.providers.count * 3 == 174)
#expect(QuotaProviderList.providers.count * 3 == 177)
}

@Test
Expand Down Expand Up @@ -132,7 +133,7 @@ struct QuotaProviderListTests {
/// re-create them all. Verify Abacus + Mistral + the 11 v0.24/v0.25
/// additions are appended at the END (additive), not interleaved.
@Test
func `Cause: new providers through ZoomMate are appended at the tail`() {
func `Cause: new providers through xAI are appended at the tail`() {
let providers = QuotaProviderList.providers
// Providers are append-only so per-(provider,state) CK subscription
// IDs stay stable across upgrades. Pin the recent tail so a careless
Expand All @@ -146,12 +147,13 @@ struct QuotaProviderListTests {
// - ZenMux, ClinePass, and LongCat occupy positions [51...53].
// - DeepInfra occupies position [55].
// - Qwen Cloud and ZoomMate occupy positions [56...57].
let tail = providers.suffix(18).map(\.id)
// - xAI occupies position [58].
let tail = providers.suffix(19).map(\.id)
#expect(tail == [
"grok", "groq", "elevenlabs", "deepgram", "llmproxy",
"azureopenai", "alibabatokenplan", "t3chat", "sakana", "qoder", "sub2api", "zenmux",
"clinepass", "longcat", "neuralwatt", "deepinfra", "qwencloud", "zoommate",
], "provider catch-up additions through ZoomMate must stay at the tail in this order")
"clinepass", "longcat", "neuralwatt", "deepinfra", "qwencloud", "zoommate", "xai",
], "provider catch-up additions through xAI must stay at the tail in this order")
}

// MARK: - iOS 1.6.0 · v0.24+v0.25 catch-up presence
Expand Down Expand Up @@ -250,9 +252,9 @@ struct QuotaProviderListTests {
/// (Zone count is providers × 3 states since iOS 1.6.0 added the
/// `warning` state alongside `depleted`/`restored`.)
@Test
func `Cause: catalog 58/174 numbers match the actual list`() {
#expect(QuotaProviderList.providers.count == 58)
#expect(QuotaProviderList.providers.count * 3 == 174)
func `Cause: catalog 59/177 numbers match the actual list`() {
#expect(QuotaProviderList.providers.count == 59)
#expect(QuotaProviderList.providers.count * 3 == 177)
}

@Test
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ Provider setup notes and Mac provider internals live in [docs/providers.md](docs
- [Moonshot / Kimi API](docs/moonshot.md) — API key for Moonshot/Kimi API account balance tracking.
- [Venice](docs/venice.md) — API key for DIEM or USD balance tracking.
- [Codebuff](docs/codebuff.md) — API token (or `~/.config/manicode/credentials.json`) for credit balance + weekly rate limit.
- [Crof](docs/crof.md) — API key for dollar credit balance and request quota tracking.
- [Crof](docs/crof.md) — API key for dollar credit balance and optional request quota tracking.
- [Command Code](docs/command-code.md) — Browser or manual cookies for monthly USD credits from Command Code billing.
- [Qoder](docs/qoder.md) — Browser or manual cookies for Qoder big model credit usage.
- [StepFun](docs/stepfun.md) — Username + password login for Step Plan rate limits (5‑hour + weekly windows) and subscription plan name.
Expand All @@ -127,6 +127,7 @@ Provider setup notes and Mac provider internals live in [docs/providers.md](docs
- [LongCat](docs/providers.md) — Browser or manual-cookie usage for LongCat plan quotas.
- [Neuralwatt](docs/neuralwatt.md) — API key for subscription kWh usage and prepaid credit balance.
- [ZenMux](docs/zenmux.md) — Management API key for rolling five-hour and seven-day quota windows plus PAYG balance.
- [xAI](docs/xai.md) — Management API key + team ID for prepaid credit balance and daily platform spend.
- Open to new providers: [provider authoring guide](docs/provider.md).

## Upstream And Credits
Expand Down
3 changes: 3 additions & 0 deletions Shared/Notifications/QuotaProviderList.swift
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,9 @@ public enum QuotaProviderList {
// remain stable.
Provider(id: "qwencloud", displayName: "Qwen Cloud"),
Provider(id: "zoommate", displayName: "ZoomMate"),
// xAI platform billing. Appended so all existing CloudKit subscription
// identifiers remain stable.
Provider(id: "xai", displayName: "xAI"),
]

/// Returns the CloudKit zone name for a given `(providerID, state)`. The
Expand Down
10 changes: 10 additions & 0 deletions Sources/CodexBar/CodexbarApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,16 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
guard let settings = self?.settings else { return }
AdaptiveActivityConsentPresenter.presentIfNeeded(settings: settings)
AppNotifications.shared.requestAuthorizationOnStartup()
// A persisted non-USD choice opts into the daily exchange-rate refresh. The service
// returns before networking for the default USD setting and Auto.
guard CurrencyExchange.requiresLiveRates(
preferredCurrencyCode: settings.preferredCurrencyCode)
else { return }
let ratesChanged = await CurrencyExchange.shared.fetchLatestRatesIfNeeded(
preferredCurrencyCode: settings.preferredCurrencyCode)
if ratesChanged {
NotificationCenter.default.post(name: .codexbarCurrencyExchangeRatesDidChange, object: nil)
}
}
KeyboardShortcuts.onKeyUp(for: .openMenu) { [weak self] in
// KeyboardShortcuts dispatches both normal and menu-tracking hotkeys on the main event loop.
Expand Down
Loading
Loading