@magpie-community/opencode-cursor-auth 0.2.3 → 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.
- package/README.md +11 -1
- package/index.mjs +47 -4
- 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
|
@@ -405,8 +405,12 @@ async function usage(tok, ids) {
|
|
|
405
405
|
return bucket.has(model) || firstParty(model)
|
|
406
406
|
}
|
|
407
407
|
// Auto is always one, so the pool's list is never empty (which would
|
|
408
|
-
// count every model)
|
|
409
|
-
|
|
408
|
+
// count every model). A model listed at its context sizes (grok-4.7@256k)
|
|
409
|
+
// is still asked for by its bare name (grok-4.7) where it was picked
|
|
410
|
+
// before the list had sizes, and runs as its default, so the pool names
|
|
411
|
+
// that too (Will on Discord)
|
|
412
|
+
const asked = ids.flatMap((id) => [id, id.replace(/@[^@]*$/, "")])
|
|
413
|
+
const pool = [...new Set(["auto", ...asked, ...(data.autoBucketModels ?? [])])].filter(inPool)
|
|
410
414
|
const num = (v) => (typeof v === "number" ? v : 0)
|
|
411
415
|
// the two pools fit the line; the total goes in its tooltip
|
|
412
416
|
return {
|
|
@@ -418,6 +422,43 @@ async function usage(tok, ids) {
|
|
|
418
422
|
}
|
|
419
423
|
}
|
|
420
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
|
+
|
|
421
462
|
// ---- models ----------------------------------------------------------------------
|
|
422
463
|
//
|
|
423
464
|
// The list is Cursor's model picker (AiService/AvailableModels, asked as the
|
|
@@ -2154,8 +2195,10 @@ export async function CursorAuthPlugin() {
|
|
|
2154
2195
|
} catch (e) {
|
|
2155
2196
|
return { error: e.message, windows: [], signIn: "kept" }
|
|
2156
2197
|
}
|
|
2157
|
-
const [u, plan] = await Promise.all([usage(tok, Object.keys(provider?.models ?? {})), planOf(tok)])
|
|
2158
|
-
|
|
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" }
|
|
2159
2202
|
},
|
|
2160
2203
|
},
|
|
2161
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.
|
|
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",
|