Skip to content

feat(quota-bottle): show the Token Plan quota from your own credential - #116

Merged
MyPrototypeWhat merged 3 commits into
MiniMax-AI:mainfrom
7723qqq:feat/quota-bottle
Nov 9, 2026
Merged

MyPrototypeWhat merged 3 commits into
MiniMax-AI:mainfrom
7723qqq:feat/quota-bottle

Conversation

@7723qqq

@7723qqq 7723qqq commented Nov 8, 2026 •

Copy link
Copy Markdown
Contributor

Adds quota-bottle: an octopus-shaped glass bottle that floats in a 220 × 300 window and shows how much Token Plan quota is left. The liquid level and its opacity follow the remaining share; at 100% the liquid reaches the mouth, so the ears, neck and mouth are filled too.

Review follow-up

This revision addresses the three review items and the login failure found while testing it.

  • No host session. The auth-lease path is gone: desktop-lease.mjs, desktop-session.mjs and their tests are removed. The bottle no longer reads mcode-auth-lease-v1.cap or any other Host credential.
  • No CLI config writes. The panel login and token refresh write <context.dataDir>/credentials.json. ~/.mmx/config.json is read-only; its api_key, base_url and other fields are never removed.
  • Host SQLite is opt-in. The local usage scan is off by default and exposed as a panel switch. Its data root comes only from MINIMAX_DATA_DIR, MAVIS_HOME or ~/.minimax; the path and schema are documented as unpublished Host layout.
  • Login expiry fix. The account service returns expired_in as an absolute millisecond timestamp about 48 hours out. The old 24-hour cap treated a successful login as an error; token expiry now allows a 30-day horizon while a device code keeps the 24-hour cap.

Version 1.15.3.

Where the number comes from

The live quota has one source: a credential you configure yourself.

  1. The plugin's own login. The panel's device-code login stores an OAuth token in <context.dataDir>/credentials.json and refreshes it there. GET <baseUrl>/v1/token_plan/remains with Authorization: Bearer <token>.
  2. A credential already in the CLI config. ~/.mmx/config.json (or $MMX_CONFIG_DIR/config.json) is read, never written: an API key, or an OAuth access token that is still valid. A CLI-owned token is not refreshed or rotated; when it expires the panel offers its own login.

If neither can answer, the page falls back to a manual total plus an opt-in local token-usage estimate. The scan is off by default; when on, it reads a read-only SQLite snapshot of <data root>/v2/sqlite/runtime-state.sqlite, table local_runtime_token_usage, and removes the snapshot after the query. Usage above the saved total is reported as its own state, not clamped into a believable-looking empty bottle.

The window

surface.window is 220 × 300, frameless, transparent, always-on-top, non-resizable. Two client behaviours are handled:

  • Remembered bounds. MiniMax Code stores a popped-out window's bounds per plugin and lets that memory outrank the manifest, so a window reopens at the size it last had. When the client reports a different size the page asks for its own, carrying a visible position because the Host rejects a geometry patch that would leave the screen.
  • Dragging. The content is an -webkit-app-region: drag handle for renderers that honour it, and the page also moves the window itself in screen coordinates, because a webview guest ignores the app-region. Only one path is ever live: where the drag region exists it swallows the pointer events first.

The compact meter shows the percentage and token amount, then the reset countdown, the weekly quota and the video model's used share when the response carries them.

Known client-side limitation. On the webview renderer backend the guest surface is opaque, so the window is a black rectangle even though the page paints nothing (a headless render of the same page has alpha 0 at all four corners). The same package is transparent on the native backend. Tracked in MiniMax-AI/minimax-code#597.

Interface

Chinese and English. The page follows the client's language on first run (navigator.language) and the 中 / EN buttons in the header switch it and remember the choice.

Data & access

  • Files read: <context.dataDir>/credentials.json; ~/.mmx/config.json or $MMX_CONFIG_DIR/config.json read-only; <data root>/v2/sqlite/runtime-state.sqlite read-only and only when the usage scan is on; its own page, quota.json and settings.json.
  • Files written: <context.dataDir>/credentials.json; <context.dataDir>/quota.json; <context.dataDir>/settings.json; temporary SQLite snapshots under dataDir, only when the scan is on, removed after each read. No CLI or Host file is written.
  • Network: account.minimaxi.com / account.minimax.io, api.minimaxi.com / api.minimax.io. Credentialed requests never follow redirects. Tokens never reach the page, a log, or an error response.
  • No agentAccess, toolAccess or deviceAccess: no Agent turns, no conversations read, no tools called, no microphone.

Verification

  • node --test "tests/*.test.mjs": 85 tests pass.
  • node scripts/validate.mjs plugins/7723qqq/quota-bottle: OK.
  • A live device-code login on Windows/CN completed and the panel rendered a live Token Plan quota; the floating window showed 100%, the reset countdown, the weekly quota and video usage.
  • Not verified in this revision: macOS/Linux, the global region, and the native renderer backend on a machine where the webview backend is active.

Autofix with [code]smith
Open in [code]smith · Need help with this PR? Tag @codesmith-bot with what you need.

@MyPrototypeWhat MyPrototypeWhat left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks for this, the quota bottle is a genuinely useful idea. Three things need to change before we can merge:

  1. Don't borrow the desktop's signed-in session. miniapp/node/desktop-lease.mjs reads <data root>/run/mcode-auth-lease-v1.cap and takes a lease on MiniMax Code's token. The host reserves that lease for its built-in tools; it isn't open to MiniApps. Please remove this path and rely only on an API key or OAuth the user configures themselves.
  2. Don't remove fields from the user's ~/.mmx/config.json. When the user signs in from the panel, saveOauth in auth/auth.mjs deletes their existing api_key and base_url. The UI says the token will be saved there, but not that anything gets removed. Please store credentials in the plugin's own data directory, or if you must write the shared config, ask first and keep existing fields.
  3. Make reading the host database optional and off by default. Reading v2/sqlite/runtime-state.sqlite depends on an unpublished host schema that can break on upgrade, and it touches local usage data. Please put it behind a default-off switch and document in the README what it reads and why.

Ping me when it's updated and I'll take another look.

* The lease endpoint lives next to the runtime state, not inside it.
* @param {string} dataDir
*/
export function resolveDesktopDataRoot(dataDir) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This walks up from the plugin's dataDir to locate the host's data root. MiniApps shouldn't depend on or reach into the host's directory layout.

if (signal?.aborted) return { ok: false, code: 'desktop_unavailable' };
let capability;
try {
capability = (await readFile(capabilityFile, 'utf8')).trim();

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reading the host's mcode-auth-lease-v1.cap is the core issue: the lease is reserved for the host's built-in tools, not MiniApps. Please remove this path.

// The client's region is not ours to know: the first read discovers it,
// and later reads start with the region that answered.
const preferred = lastLiveRegion ?? (await readConfiguredRegion());
const session = await fetchDesktopSessionQuota(context, {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The desktop-session path is the default here. Once the lease path is removed, this should fall back to the user's own API key / OAuth.

export async function saveOauth(region, credentials, signal) {
await updateConfigFile((raw) => {
if (signal?.aborted) throw new Error('aborted');
delete raw.api_key;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This silently deletes the user's existing api_key in the shared CLI config. Please don't remove fields the user set.

delete raw.api_key;
raw.oauth = { ...credentials, region };
raw.region = region;
delete raw.base_url;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Same for base_url. Prefer storing credentials in the plugin's own data directory.

7723qqq added a commit to 7723qqq/MiniMax-Code-MiniApps that referenced this pull request Nov 9, 2026
…usage

Review follow-up on MiniMax-AI#116.

- Remove the host auth-lease path; the live quota now comes only from a
  device-code login stored under context.dataDir or a read-only API key /
  OAuth access token the user configured in the CLI config.
- Stop rewriting ~/.mmx/config.json. Login and refresh write
  dataDir/credentials.json; CLI fields are never removed.
- Make the host SQLite usage scan opt-in (default off) with a panel switch,
  and resolve its data root only from MINIMAX_DATA_DIR / MAVIS_HOME /
  ~/.minimax.
- Accept the account service's absolute 48-hour token expiry; the old
  24-hour cap made a successful login look like an error.
- Fill the ears, neck and mouth at 100%, and show the reset countdown,
  weekly quota and video usage in the floating window.
Version 1.15.3.
@7723qqq 7723qqq changed the title feat(quota-bottle): read the Token Plan quota from the signed-in desktop feat(quota-bottle): show the Token Plan quota from your own credential Nov 9, 2026
An octopus-shaped glass bottle that floats in a 220 × 300 window and shows
the remaining Token Plan quota the desktop itself reports, with a device-code
login and a local token-usage estimate as fallbacks.

- Quota source: the desktop's own session, borrowed through its auth lease.
  One GET /v1/api/openplatform/coding_plan/remains with the leased token; no
  client signature and no group lookup.
- The account region is discovered, not guessed: the leased token is offered
  to both Token Plan origins and the one that answers is the client's.
- The page follows the client's language (Chinese or English) and carries a
  中 / EN switch.
- The window is dragged from page code with screen coordinates, because
  -webkit-app-region is inert in a webview guest; the page also asks for its
  size again when the client remembers another one.
- The page paints no backdrop, so the window is transparent on the native
  renderer; on the webview backend the guest surface is opaque, a client
  limitation tracked in MiniMax-AI/minimax-code#597.

Verification: node --test "tests/*.test.mjs" passes 84 tests;
node scripts/validate.mjs plugins/7723qqq/quota-bottle reports OK; a live
desktop session on the CN region returned a quota without a second login.
…usage

Review follow-up on MiniMax-AI#116.

- Remove the host auth-lease path; the live quota now comes only from a
  device-code login stored under context.dataDir or a read-only API key /
  OAuth access token the user configured in the CLI config.
- Stop rewriting ~/.mmx/config.json. Login and refresh write
  dataDir/credentials.json; CLI fields are never removed.
- Make the host SQLite usage scan opt-in (default off) with a panel switch,
  and resolve its data root only from MINIMAX_DATA_DIR / MAVIS_HOME /
  ~/.minimax.
- Accept the account service's absolute 48-hour token expiry; the old
  24-hour cap made a successful login look like an error.
- Fill the ears, neck and mouth at 100%, and show the reset countdown,
  weekly quota and video usage in the floating window.
Version 1.15.3.
@7723qqq

7723qqq commented Nov 9, 2026

Copy link
Copy Markdown
Contributor Author

Updated — rebased onto latest main (80857c2), so the PR is mergeable again.

The three review items are addressed:

  • the host auth lease is removed; the bottle no longer reads the capability file or any Host credential;
  • credentials are stored in <context.dataDir>/credentials.json, and ~/.mmx/config.json is read-only (no field is removed);
  • the host SQLite usage scan is opt-in and off by default, with the path/schema documented.

Also fixed the login failure: the account service returns expired_in as an absolute timestamp about 48 hours out, and the old 24-hour cap treated a successful device login as an error.

Ready for another look. @MyPrototypeWhat

Copy link
Copy Markdown
Collaborator

Thanks, all three points are addressed: the auth-lease path is gone, the plugin now keeps its own token in its data dir and only reads ~/.mmx/config.json, and the local SQLite read is behind an off-by-default switch documented in the README. One small thing left: README.zh-CN.md adds a row for 提示词优化 (plugins/7723qqq/prompt-optimizer), which isn't in this PR or on main, so the link is dead and the English README has no matching row. Could you drop that row? After that, this looks good to merge.

@7723qqq

7723qqq commented Nov 9, 2026

Copy link
Copy Markdown
Contributor Author

Done — dropped the 提示词优化 row from README.zh-CN.md and pushed (96c1429). The English README has no such row. Ready to merge.

@MyPrototypeWhat MyPrototypeWhat left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Looks good, thanks!

@MyPrototypeWhat
MyPrototypeWhat merged commit 93f09b9 into MiniMax-AI:main Nov 9, 2026
1 check passed
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.

2 participants