@magpie-community/opencode-cursor-auth 0.2.4 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +11 -1
  2. package/index.mjs +41 -2
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -124,9 +124,19 @@ minutes), the way pi-cursor-sdk lists Cursor's catalog:
124
124
  and `service_tier` counting as for a listed model. The list doesn't show
125
125
  these ids: pick the `@<size>` model for a window that is the model's.
126
126
 
127
+ ## Usage
128
+
129
+ magpie shows Cursor Models, Other Models and Total for the billing period.
130
+ Accounts with a Grok Bot allowance also show its usage and reset time;
131
+ active trials are labelled separately. A spent Bot allowance doesn't stop
132
+ Cursor requests.
133
+
134
+ Sign in to the Cursor account linked in Grok Bot. A linked SuperGrok
135
+ subscription grants Bot access without a paid Cursor plan; see
136
+ [Grok Bot plans and billing](https://cursor.com/help/grok-bot/plans).
137
+
127
138
  ## Not included
128
139
 
129
- - Usage and plan limits.
130
140
  - Web search: Cursor's own web search is refused like its other tools.
131
141
  - Switching between several accounts. OpenCode keeps one sign-in per
132
142
  provider.
package/index.mjs CHANGED
@@ -422,6 +422,43 @@ async function usage(tok, ids) {
422
422
  }
423
423
  }
424
424
 
425
+ // Grok Bot's separate allowance, using the CLI JWT as a dashboard session.
426
+ async function botUsage(tok) {
427
+ try {
428
+ const subject = JSON.parse(Buffer.from(tok.split(".")[1], "base64url").toString()).sub
429
+ if (typeof subject !== "string") return []
430
+ const user = subject.split("|").filter(Boolean).at(-1)
431
+ if (!user || !/^[a-zA-Z0-9._-]+$/.test(user)) return []
432
+ const res = await fetch(WEBSITE + "/api/dashboard/get-sand-usage-status", {
433
+ method: "POST",
434
+ headers: {
435
+ "Content-Type": "application/json",
436
+ Accept: "application/json",
437
+ Origin: WEBSITE,
438
+ Cookie: "WorkosCursorSessionToken=" + encodeURIComponent(user + "::" + tok),
439
+ },
440
+ body: "{}",
441
+ redirect: "error",
442
+ signal: AbortSignal.timeout(5_000),
443
+ })
444
+ if (!res.ok) return []
445
+ const data = await res.json()
446
+ const paid = typeof data?.includedLimitZero === "boolean"
447
+ ? !data.includedLimitZero : data?.hasNonZeroIncludedLimit === true
448
+ const trial = !paid && typeof data?.sandTrialExpiresAt === "string" && Date.parse(data.sandTrialExpiresAt) > Date.now()
449
+ if ((!paid && !trial) || typeof data?.usagePercent !== "number" || !Number.isFinite(data.usagePercent)) return []
450
+ const reset = paid && typeof data.nextResetTimestampUtc === "string" ? Date.parse(data.nextResetTimestampUtc) : NaN
451
+ return [{
452
+ name: trial ? "Grok Bot (trial)" : "Grok Bot",
453
+ used: Math.max(0, Math.min(100, data.usagePercent)),
454
+ aside: true, // Bot exhaustion must not stop Cursor model requests.
455
+ ...(Number.isFinite(reset) ? { resetsAt: new Date(reset).toISOString(), span: 604800 } : {}),
456
+ }]
457
+ } catch {
458
+ return []
459
+ }
460
+ }
461
+
425
462
  // ---- models ----------------------------------------------------------------------
426
463
  //
427
464
  // The list is Cursor's model picker (AiService/AvailableModels, asked as the
@@ -2158,8 +2195,10 @@ export async function CursorAuthPlugin() {
2158
2195
  } catch (e) {
2159
2196
  return { error: e.message, windows: [], signIn: "kept" }
2160
2197
  }
2161
- const [u, plan] = await Promise.all([usage(tok, Object.keys(provider?.models ?? {})), planOf(tok)])
2162
- return { ...u, ...(plan ? { plan } : {}), signIn: "kept" }
2198
+ const [u, plan, bot] = await Promise.all([usage(tok, Object.keys(provider?.models ?? {})), planOf(tok), botUsage(tok)])
2199
+ // Put Bot before Total for magpie's three menu-bar rings.
2200
+ const windows = [...u.windows.filter((w) => !w.aside), ...bot, ...u.windows.filter((w) => w.aside)]
2201
+ return { ...u, windows, ...(plan ? { plan } : {}), signIn: "kept" }
2163
2202
  },
2164
2203
  },
2165
2204
  // the session the request is part of, for the conversation_id
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@magpie-community/opencode-cursor-auth",
3
- "version": "0.2.4",
3
+ "version": "0.2.5",
4
4
  "description": "Cursor subscriptions (Pro, Pro+, Ultra, Teams) in OpenCode and magpie, through the API cursor-agent talks to",
5
5
  "type": "module",
6
6
  "main": "./index.mjs",