@magpie-community/opencode-cursor-auth 0.2.29 → 0.2.30
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 -0
- package/index.mjs +75 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -254,6 +254,17 @@ own spends the team's pool: On-demand shows the pool's spend and limit,
|
|
|
254
254
|
with the member's own spend beside it, and the account is used up when
|
|
255
255
|
the pool is.
|
|
256
256
|
|
|
257
|
+
An Enterprise account's period has no Cursor Models, Other Models or Total
|
|
258
|
+
in `GetCurrentPeriodUsage`: Cursor reports its overall allowance through
|
|
259
|
+
the website's `usage-summary` instead. Magpie shows that as Enterprise,
|
|
260
|
+
for example `49.45 / 800 USD · 6.2% used`, or
|
|
261
|
+
`750.55 / 800 USD · 93.8% left` with Magpie's Used / Left choice, reset at
|
|
262
|
+
the billing cycle's end. When the summary says team on-demand is enabled
|
|
263
|
+
and unlimited or still has room, the Enterprise window is informational:
|
|
264
|
+
reaching its included allowance doesn't count the account as used up.
|
|
265
|
+
On-demand also shows the team's spend when known, with its limit when it
|
|
266
|
+
has one. A reached on-demand limit counts the account as used up.
|
|
267
|
+
|
|
257
268
|
Sign in to the Cursor account linked in Grok Bot. A linked SuperGrok
|
|
258
269
|
subscription grants Bot access without a paid Cursor plan; see
|
|
259
270
|
[Grok Bot plans and billing](https://cursor.com/help/grok-bot/plans).
|
package/index.mjs
CHANGED
|
@@ -532,14 +532,79 @@ async function hardLimit(tok) {
|
|
|
532
532
|
// dollars, thousands grouped: a team's pool runs to six figures ($451,200.00)
|
|
533
533
|
const dollars = (n) => "$" + n.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 })
|
|
534
534
|
|
|
535
|
-
//
|
|
536
|
-
//
|
|
537
|
-
//
|
|
538
|
-
//
|
|
535
|
+
// enterpriseUsage is the allowance GetCurrentPeriodUsage leaves out on an
|
|
536
|
+
// Enterprise account. That call answers with only the billing cycle there;
|
|
537
|
+
// the website's usage-summary has individualUsage.overall, in cents, and
|
|
538
|
+
// the account's membership. The CLI JWT is also the website's dashboard
|
|
539
|
+
// session, as botUsage builds it. undefined when the summary says nothing
|
|
540
|
+
// this can show, so a failed read stays an empty card, as before.
|
|
541
|
+
async function enterpriseUsage(tok) {
|
|
542
|
+
try {
|
|
543
|
+
const subject = JSON.parse(Buffer.from(tok.split(".")[1], "base64url").toString()).sub
|
|
544
|
+
if (typeof subject !== "string") return undefined
|
|
545
|
+
const user = subject.split("|").filter(Boolean).at(-1)
|
|
546
|
+
if (!user || !/^[a-zA-Z0-9._-]+$/.test(user)) return undefined
|
|
547
|
+
const res = await fetch(WEBSITE + "/api/usage-summary", {
|
|
548
|
+
method: "GET",
|
|
549
|
+
headers: {
|
|
550
|
+
Accept: "application/json",
|
|
551
|
+
Origin: WEBSITE,
|
|
552
|
+
Cookie: "WorkosCursorSessionToken=" + encodeURIComponent(user + "::" + tok),
|
|
553
|
+
},
|
|
554
|
+
redirect: "error",
|
|
555
|
+
signal: AbortSignal.timeout(15_000),
|
|
556
|
+
})
|
|
557
|
+
if (!res.ok) return undefined
|
|
558
|
+
const data = await res.json()
|
|
559
|
+
if (String(data?.membershipType).toLowerCase() !== "enterprise") return undefined
|
|
560
|
+
const overall = data?.individualUsage?.overall
|
|
561
|
+
if (overall?.enabled !== true) return undefined
|
|
562
|
+
const { used, limit } = overall
|
|
563
|
+
if (typeof used !== "number" || !Number.isFinite(used) || used < 0) return undefined
|
|
564
|
+
if (typeof limit !== "number" || !Number.isFinite(limit) || limit <= 0) return undefined
|
|
565
|
+
const end = Date.parse(data.billingCycleEnd ?? "")
|
|
566
|
+
const resets = Number.isFinite(end) ? { resetsAt: new Date(end).toISOString() } : {}
|
|
567
|
+
const od = data.teamUsage?.onDemand
|
|
568
|
+
const spent = typeof od?.used === "number" && Number.isFinite(od.used) && od.used >= 0
|
|
569
|
+
const unlimited = od?.enabled === true && od.limit === null
|
|
570
|
+
const fixed = od?.enabled === true && typeof od.limit === "number" && Number.isFinite(od.limit) && od.limit > 0 && spent
|
|
571
|
+
// Only an explicitly unlimited budget or a measured budget with room
|
|
572
|
+
// lets a spent included allowance stay available to magpie's routing.
|
|
573
|
+
const aside = unlimited || (fixed && od.used < od.limit)
|
|
574
|
+
const windows = [{
|
|
575
|
+
name: "Enterprise",
|
|
576
|
+
used: Math.max(0, Math.min(100, (100 * used) / limit)),
|
|
577
|
+
display: `${dollars(used / 100)} / ${dollars(limit / 100)}`,
|
|
578
|
+
amount: used / 100,
|
|
579
|
+
limit: limit / 100,
|
|
580
|
+
unit: "USD",
|
|
581
|
+
...resets,
|
|
582
|
+
...(aside ? { aside: true } : {}),
|
|
583
|
+
}]
|
|
584
|
+
if (fixed) windows.push({
|
|
585
|
+
name: "On-demand",
|
|
586
|
+
used: Math.min(100, (100 * od.used) / od.limit),
|
|
587
|
+
display: `${dollars(od.used / 100)} / ${dollars(od.limit / 100)}`,
|
|
588
|
+
amount: od.used / 100,
|
|
589
|
+
limit: od.limit / 100,
|
|
590
|
+
unit: "USD",
|
|
591
|
+
...resets,
|
|
592
|
+
})
|
|
593
|
+
else if (unlimited && spent) windows.push({ name: "On-demand", used: 0, display: dollars(od.used / 100), ...resets, aside: true })
|
|
594
|
+
return windows
|
|
595
|
+
} catch {
|
|
596
|
+
return undefined
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
// usage is the account's windows this billing period. ids are the models it
|
|
601
|
+
// can be asked for, each counted by the pool Cursor bills it to. An account
|
|
602
|
+
// that may spend on-demand once its included usage is gone (fottencity on
|
|
539
603
|
// Discord: a team that pays for more) is still served when the pools are
|
|
540
604
|
// spent, so they are shown aside, and its On-demand spend is what can run
|
|
541
605
|
// out: at its limit (a team member with none of their own: the team's
|
|
542
|
-
// pool), or never when it has none.
|
|
606
|
+
// pool), or never when it has none. An Enterprise account's period has no
|
|
607
|
+
// planUsage; its allowance comes from usage-summary instead.
|
|
543
608
|
async function usage(tok, ids) {
|
|
544
609
|
const [res, hard] = await Promise.all([
|
|
545
610
|
fetch(API + "/aiserver.v1.DashboardService/GetCurrentPeriodUsage", {
|
|
@@ -553,7 +618,11 @@ async function usage(tok, ids) {
|
|
|
553
618
|
if (!res.ok) return { error: statusText(res.status), windows: [] }
|
|
554
619
|
const data = await res.json()
|
|
555
620
|
const u = data?.planUsage
|
|
556
|
-
if (!u)
|
|
621
|
+
if (!u) {
|
|
622
|
+
// Prefer measured Enterprise usage before any reset-date-only fallback.
|
|
623
|
+
const windows = await enterpriseUsage(tok)
|
|
624
|
+
return windows ? { windows } : { windows: [] }
|
|
625
|
+
}
|
|
557
626
|
const ms = /^[+-]?\d+$/.test(data.billingCycleEnd ?? "") ? Number(data.billingCycleEnd) : 0
|
|
558
627
|
const resets = ms > 0 ? { resetsAt: new Date(ms).toISOString() } : {}
|
|
559
628
|
const bucket = new Set((data.autoBucketModels ?? []).map(poolBase))
|
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.30",
|
|
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",
|