Skip to content

feat(grok): add Grok CLI usage tracking to desktop and VSIX - #5

Merged
sizzlebop merged 1 commit into
pinkpixel-dev:mainfrom
ozgur-d:feat/grok-provider
Sep 2, 2026
Merged

feat(grok): add Grok CLI usage tracking to desktop and VSIX#5
sizzlebop merged 1 commit into
pinkpixel-dev:mainfrom
ozgur-d:feat/grok-provider

Conversation

@ozgur-d

@ozgur-d ozgur-d commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds Grok (xAI Grok Build) as a fully integrated provider, in both the desktop app and the VS Code extension.

Two ways to connect, matching what the other providers offer:

  • xAI OIDC device-code login — opens accounts.x.ai, shows the user code, polls for the token
  • Local import — reads the credentials the Grok CLI already stored in ~/.grok/auth.json (honours GROK_HOME)

Usage comes from the Grok CLI billing endpoint (cli-chat-proxy.grok.com/v1/billing): credit window with reset time, monthly spend, on-demand spend, prepaid balance, and a per-product breakdown. Identity comes from /v1/user, plan tier from grok.com/rest/subscriptions.

Desktop

  • src-tauri/src/grok.rs — 8 Tauri commands (list, import, OAuth start/complete/cancel, refresh one, refresh all, delete)
  • src/data/grok.ts, src/App.tsx — dashboard card, account page, provider ordering, visibility toggle, pinning, notifications, JSON export, reauthentication alert
  • Raw tokens never leave the Rust backend; only display-safe data crosses IPC, which the tests assert
  • capabilities/default.json gains the accounts.x.ai / auth.x.ai opener entries, without which the "Open Grok" button silently does nothing

Existing users' saved provider order picks up grok automatically — readStoredProviderOrder already appends keys missing from a stored order.

VS Code extension

  • grokProvider.ts + grokUsage.ts, following the Kiro/Copilot provider shape
  • Tracks: grok.credits, grok.monthlySpend, grok.onDemand
  • Commands: connect, import-local, refresh, disconnect
  • Tokens live in SecretStorage, display-safe metadata in extension state — same as every other provider
  • Bumped to 1.2.0 and packaged

On the OAuth scopes

Worth calling out, since it is not guessable from the endpoint docs. The token must carry grok-cli:access and api:access on top of openid profile email offline_access. Without them the billing endpoint accepts the token and answers 403 rather than 401.

Because a refresh grant reissues the same scopes, a 403 is never retried through a token refresh — it is surfaced directly as "reconnect required" so the Reauthenticate button appears. A 401 still goes down the normal refresh path.

One other trap: sending X-XAI-Token-Auth with any value makes every request 401. Bearer only.

Scope note

Anyone upgrading from an earlier build has to disconnect and reconnect Grok once (or re-import from the CLI) — a stored token predating this change carries the narrow scopes, and refreshing will not widen them.

Testing

  • cargo test — 6 new Grok integration tests (import single/multi-account, credential-leak assertions, quota parsing, refresh-failure classification); full suite green at 26
  • node --test — 7 new VSIX unit tests, all passing
  • npm run typecheck and npm run build clean
  • Verified live against a real account: credit window, product breakdown, and tier all resolve

Pre-existing and untouched: test/antigravityUsage.test.js fails on non-English locales because it asserts a toLocaleString(undefined, …) result. Happy to fix that separately if useful.

Not included

Cursor is deliberately excluded from the VSIX, so I kept that boundary in mind — but Grok's CLI is editor-agnostic, so it is included in both. Say the word if you would rather keep it desktop-only.

Adds Grok (xAI Grok Build) as a fully integrated provider alongside the
existing six.

Desktop (src-tauri/src/grok.rs, src/data/grok.ts, src/App.tsx):
- xAI OIDC device-code login plus local import from ~/.grok/auth.json
- Usage from the Grok CLI billing endpoint: credit window, monthly spend,
  on-demand spend, prepaid balance, and per-product breakdown
- Dashboard card, account page, provider ordering, visibility toggle,
  pinning, notifications, JSON export, and reauthentication recovery
- Raw tokens stay in the Rust backend; only display-safe data crosses IPC

VSIX (quota-vscode/):
- New GrokProvider and grokUsage modules with the same auth paths
- Tracks: grok.credits, grok.monthlySpend, grok.onDemand
- Connect, import-local, refresh, and disconnect commands; tokens are kept
  in SecretStorage like every other provider
- Bumped to 1.2.0 and packaged

OAuth scopes include grok-cli:access and api:access. Without them the
billing endpoint accepts the token but answers 403, so a 403 is treated as
"reconnect required" rather than retried through a token refresh, which
would only reissue the same scopes.

Tests: 6 Rust integration tests, 7 VSIX unit tests.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FCkUjKhyShFJe3k7uVdDGh
@coderabbitai

coderabbitai Bot commented Aug 25, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d19c12d5-3bf5-4eba-95d7-6ea0b75ade34


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

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

Copy link
Copy Markdown

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: ae89b83bb2

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src-tauri/src/grok.rs
let storage_dir = quota_storage_dir()?;
let summary = upsert_token_response_in(&storage_dir, &response).await?;
set_pending_oauth(None);
refresh_account_in(&storage_dir, &summary.id).await

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 Return the connected account before refreshing usage

When device authorization succeeds but the first billing request fails because of a transient HTTP/network/JSON error, refresh_account_in returns Err even though the account has already been persisted and the pending login has been cleared. The frontend consequently reports the connection as failed, keeps an unusable login panel whose session is already gone, and does not show the stored account until a reload. Complete the login with the saved summary and perform the initial usage refresh as a best-effort step, as the other desktop OAuth flows do.

Useful? React with 👍 / 👎.

if (!email) throw new Error('Grok authorization did not return an account email.');

const principalId = identity.principalId ?? normalize(claims?.principal_id) ?? normalize(claims?.sub);
const id = existing?.id ?? buildAccountId(email, principalId);

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 Preserve the existing Grok account during reconnection

When a user reauthenticates an existing Grok account, connect() is the only caller of this method and never supplies existing, so the matching ID is saved with an empty usage object and fresh metadata before the billing refresh runs. If that refresh then encounters any error, refreshAccount saves the already-emptied object, permanently discarding the last safe quota data that reauthentication is intended to keep visible. Resolve the stored account after deriving id and use it when constructing the replacement.

Useful? React with 👍 / 👎.

@sizzlebop
sizzlebop merged commit ee9108b into pinkpixel-dev:main Sep 2, 2026
4 checks 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