Add Xiaomi MiMo token plan usage tracking#651
Add Xiaomi MiMo token plan usage tracking#651debpramanik wants to merge 16 commits intosteipete:mainfrom
Conversation
Introduce the Xiaomi MiMo provider across app, core, CLI, and widget surfaces.\n\nAdd MiMo-specific fetchers, settings, icons, and tests, and fix balance row formatting and cookie-source off handling discovered during review.
Add Xiaomi MiMo to the provider reference and update the configuration guide's provider ID list so the docs match the current branch.
…teipete#596) All 10 conflicted files had the same pattern: main added .perplexity while PR branch added .mimo. Resolution keeps both providers in every file: Providers.swift, ProviderSettingsSnapshot.swift, ProviderImplementationRegistry.swift, ProviderDescriptor.swift, UsageStore.swift, TokenAccountCLI.swift, CostUsageScanner.swift, CodexBarWidgetProvider.swift, CodexBarWidgetViews.swift, SettingsStoreTests.swift.
…or ProviderDetailView
Integrate three new API endpoints to show token plan credits alongside balance: - GET /api/v1/tokenPlan/detail (plan code, period end, expiry) - GET /api/v1/tokenPlan/usage (used/limit/percent) - Combined with existing /api/v1/balance MiMoUsageSnapshot now fills primary RateWindow with credit usage (e.g. 10,100,158 / 200,000,000 Credits, 5.05%) and shows plan name (Standard) as identity label. Falls back to balance display when no token plan is active. Fetches all three endpoints in parallel via async let.
Add .mimo to the resetDescription display path so the primary rate window shows '10,100,158 / 200,000,000 Credits' alongside the percentage bar, matching how Warp/Kilo display credit usage.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ecfef95985
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| async let tokenDetailData = self.fetchAuthenticated(url: tokenDetailURL, cookie: normalizedCookie) | ||
| async let tokenUsageData = self.fetchAuthenticated(url: tokenUsageURL, cookie: normalizedCookie) |
There was a problem hiding this comment.
Make MiMo token-plan requests best-effort
The new MiMo fetch path requires tokenPlan/detail and tokenPlan/usage to succeed because both are awaited as mandatory async let tasks before building the snapshot. If either endpoint returns a non-200, times out, or is unavailable for a given account, fetchAuthenticated throws and the whole provider fails, so users lose even the balance result instead of getting the intended balance fallback. These token-plan calls should be optional/best-effort so balance-only accounts still produce a valid snapshot.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed in commit cc35bac. Token-plan endpoints are now optional (try?) so balance always works even if tokenPlan/detail or tokenPlan/usage fails.
| options: [.regularExpression]) | ||
| .trimmingCharacters(in: .whitespacesAndNewlines) | ||
| let value = balanceValue.isEmpty ? loginMethodText : balanceValue | ||
| entries.append(.text("Balance: \(AccountFormatter.plan(value))", .secondary)) |
There was a problem hiding this comment.
Stop forcing MiMo plan text under a balance label
This branch always renders .mimo account text as Balance: ..., but MiMo now sets loginMethod to the plan name when a token plan exists (for example, Standard). In that case the menu shows misleading output like Balance: Standard for subscribed users. The MiMo path should only use a balance label when the value is actually a balance string, otherwise it should remain a plan label.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed in commit cc35bac. The MiMo path now checks localizedCaseInsensitiveContains("balance:") before applying the Balance label. When loginMethod is a plan name like "Standard", it renders as Plan: Standard instead of Balance: Standard.
Token-plan endpoints are now optional: if tokenPlan/detail or tokenPlan/usage fails, the balance result is still returned so users don't lose visibility entirely. MenuDescriptor now distinguishes balance vs plan text for MiMo: - 'Balance: $25.51' → renders as Balance label - 'Standard' → renders as Plan label (no longer shows 'Balance: Standard')
Summary
Integrates Xiaomi MiMo token plan API endpoints to show credit usage alongside balance in CodexBar.
What this adds
e.g. 10,100,158 (used token value) / 200,000,000 (available token value as per token plan) Creditswith percentage (5.05%)API endpoints used
GET /api/v1/balance— existing, returns balance + currencyGET /api/v1/tokenPlan/detail— new, returns plan code, period end, expiryGET /api/v1/tokenPlan/usage— new, returns used/limit/percentAll 3 fetched in parallel via
async let, same cookies, no new credentials.Context
This PR builds on top of #596 (original Xiaomi MiMo balance provider). Merge conflicts from #596 were resolved and the token plan feature was layered on top of that foundation.
How to get MiMo cookies (manual mode)
https://platform.xiaomimimo.com/#/console/plan-manageCmd + Option + I(Mac) orCtrl + Shift + I(Windows/Linux)Cmd + R)api/v1to narrow down requeststokenPlan/usageorbalance)Cookie:header and copy its entire valueThe cookie should look like:
api-platform_serviceToken=eyJhbGc...; userId=5694760205; api-platform_ph=oDiz...; api-platform_slh=F2V5...
Files changed
MiMoUsageSnapshot.swiftMiMoUsageFetcher.swiftMiMoProviderDescriptor.swiftsupportsCredits: true, updated labelsMenuCardView.swift.mimoto resetDescription displayMenuDescriptor.swift.mimoto primary window detail renderingMiMoProviderTests.swiftSettingsStoreTests.swift.mimoto provider listCommands run
swift build— passes cleanswift test— 3 pre-existing errors inSettingsStoreTests.swift(identical to upstream main, not introduced by this PR)