Skip to content

Add Xiaomi MiMo token plan usage tracking#651

Open
debpramanik wants to merge 16 commits intosteipete:mainfrom
debpramanik:feature/mimo-token-plan
Open

Add Xiaomi MiMo token plan usage tracking#651
debpramanik wants to merge 16 commits intosteipete:mainfrom
debpramanik:feature/mimo-token-plan

Conversation

@debpramanik
Copy link
Copy Markdown

Summary

Integrates Xiaomi MiMo token plan API endpoints to show credit usage alongside balance in CodexBar.

What this adds

  • Token plan credits bar: Shows e.g. 10,100,158 (used token value) / 200,000,000 (available token value as per token plan) Credits with percentage (5.05%)
  • Plan name display: Shows plan tier (e.g. "Standard") as identity label
  • Reset date: Shows subscription period end (e.g. 2026-05-04 23:59 UTC)
  • Balance fallback: Users without a token plan subscription still see their wallet balance (e.g. "Balance: $25.51")

API endpoints used

  • GET /api/v1/balance — existing, returns balance + currency
  • GET /api/v1/tokenPlan/detail — new, returns plan code, period end, expiry
  • GET /api/v1/tokenPlan/usage — new, returns used/limit/percent
    All 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)

  1. Open Chrome and go to https://platform.xiaomimimo.com/#/console/plan-manage
  2. Make sure you are logged in
  3. Open DevTools: Cmd + Option + I (Mac) or Ctrl + Shift + I (Windows/Linux)
  4. Go to the Network tab
  5. Refresh the page (Cmd + R)
  6. In the filter bar, type api/v1 to narrow down requests
  7. Click on any request (e.g. tokenPlan/usage or balance)
  8. In the right panel, scroll to Request Headers
  9. Find the Cookie: header and copy its entire value
  10. In CodexBar: Settings → Xiaomi MiMo → Cookie source → Manual
  11. Paste the copied value into the cookie field
    The cookie should look like:
    api-platform_serviceToken=eyJhbGc...; userId=5694760205; api-platform_ph=oDiz...; api-platform_slh=F2V5...

Tip: If the Cookie header is not visible (httpOnly cookies), open the DevTools Console tab and run:

chrome.cookies.getAll({domain:"platform.xiaomimimo.com"}, c => console.log(c.map(x=>x.name+'='+x.value).join('; ')))

Copy the output and paste it into CodexBar.

Files changed

File Change
MiMoUsageSnapshot.swift Added token plan fields, fills primary RateWindow
MiMoUsageFetcher.swift Parallel fetch of 3 endpoints, new parsers
MiMoProviderDescriptor.swift supportsCredits: true, updated labels
MenuCardView.swift Added .mimo to resetDescription display
MenuDescriptor.swift Added .mimo to primary window detail rendering
MiMoProviderTests.swift 5 new tests for token plan parsing
SettingsStoreTests.swift Added .mimo to provider list

Commands run

  • swift build — passes clean
  • swift test — 3 pre-existing errors in SettingsStoreTests.swift (identical to upstream main, not introduced by this PR)

Roland Kakonyi and others added 15 commits March 24, 2026 17:47
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.
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.
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment on lines +71 to +72
async let tokenDetailData = self.fetchAuthenticated(url: tokenDetailURL, cookie: normalizedCookie)
async let tokenUsageData = self.fetchAuthenticated(url: tokenUsageURL, cookie: normalizedCookie)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge 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 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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))
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant