@magpie-community/opencode-cursor-auth 0.2.30 → 0.2.31
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 +15 -0
- package/index.mjs +42 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -265,6 +265,21 @@ reaching its included allowance doesn't count the account as used up.
|
|
|
265
265
|
On-demand also shows the team's spend when known, with its limit when it
|
|
266
266
|
has one. A reached on-demand limit counts the account as used up.
|
|
267
267
|
|
|
268
|
+
### Included usage only (optional)
|
|
269
|
+
|
|
270
|
+
In magpie, open the Cursor provider, turn on **Included usage only** under
|
|
271
|
+
**Plugin options**, and save (or set `"pluginOptions": {"cursor":
|
|
272
|
+
{"included_only": true}}` in magpie's settings.json). It is off by default,
|
|
273
|
+
applies to every Cursor account, and takes effect at each account's next
|
|
274
|
+
usage reading.
|
|
275
|
+
|
|
276
|
+
When on, Cursor Models and Other Models (an Enterprise account's allowance)
|
|
277
|
+
are what keep an account in routing: once one is used up, magpie moves its
|
|
278
|
+
models to the next account until the period resets, even when on-demand
|
|
279
|
+
could still pay for them. On-demand and Total are still shown but never
|
|
280
|
+
keep an account in routing. Use it when on-demand is a shared or paid pool
|
|
281
|
+
you don't want spent. When off, on-demand works as described above.
|
|
282
|
+
|
|
268
283
|
Sign in to the Cursor account linked in Grok Bot. A linked SuperGrok
|
|
269
284
|
subscription grants Bot access without a paid Cursor plan; see
|
|
270
285
|
[Grok Bot plans and billing](https://cursor.com/help/grok-bot/plans).
|
package/index.mjs
CHANGED
|
@@ -532,13 +532,21 @@ 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
|
+
// INCLUDED_ONLY is the switch (magpie's plugin options, off by default)
|
|
536
|
+
// that keeps an account in routing only while its included usage lasts
|
|
537
|
+
// (magpie-community/plugins#485): on, the included pools (Cursor Models and
|
|
538
|
+
// Other Models; an Enterprise account's allowance) are what stops it, and
|
|
539
|
+
// On-demand and Total are shown only, a budget with room or none at all
|
|
540
|
+
// keeping nothing in routing. Off, on-demand that can still pay keeps it.
|
|
541
|
+
const INCLUDED_ONLY = "included_only"
|
|
542
|
+
|
|
535
543
|
// enterpriseUsage is the allowance GetCurrentPeriodUsage leaves out on an
|
|
536
544
|
// Enterprise account. That call answers with only the billing cycle there;
|
|
537
545
|
// the website's usage-summary has individualUsage.overall, in cents, and
|
|
538
546
|
// the account's membership. The CLI JWT is also the website's dashboard
|
|
539
547
|
// session, as botUsage builds it. undefined when the summary says nothing
|
|
540
548
|
// this can show, so a failed read stays an empty card, as before.
|
|
541
|
-
async function enterpriseUsage(tok) {
|
|
549
|
+
async function enterpriseUsage(tok, includedOnly = false) {
|
|
542
550
|
try {
|
|
543
551
|
const subject = JSON.parse(Buffer.from(tok.split(".")[1], "base64url").toString()).sub
|
|
544
552
|
if (typeof subject !== "string") return undefined
|
|
@@ -569,8 +577,9 @@ async function enterpriseUsage(tok) {
|
|
|
569
577
|
const unlimited = od?.enabled === true && od.limit === null
|
|
570
578
|
const fixed = od?.enabled === true && typeof od.limit === "number" && Number.isFinite(od.limit) && od.limit > 0 && spent
|
|
571
579
|
// Only an explicitly unlimited budget or a measured budget with room
|
|
572
|
-
// lets a spent included allowance stay available to magpie's routing
|
|
573
|
-
|
|
580
|
+
// lets a spent included allowance stay available to magpie's routing,
|
|
581
|
+
// and neither does with INCLUDED_ONLY on.
|
|
582
|
+
const aside = !includedOnly && (unlimited || (fixed && od.used < od.limit))
|
|
574
583
|
const windows = [{
|
|
575
584
|
name: "Enterprise",
|
|
576
585
|
used: Math.max(0, Math.min(100, (100 * used) / limit)),
|
|
@@ -589,6 +598,7 @@ async function enterpriseUsage(tok) {
|
|
|
589
598
|
limit: od.limit / 100,
|
|
590
599
|
unit: "USD",
|
|
591
600
|
...resets,
|
|
601
|
+
...(includedOnly ? { aside: true } : {}),
|
|
592
602
|
})
|
|
593
603
|
else if (unlimited && spent) windows.push({ name: "On-demand", used: 0, display: dollars(od.used / 100), ...resets, aside: true })
|
|
594
604
|
return windows
|
|
@@ -603,9 +613,11 @@ async function enterpriseUsage(tok) {
|
|
|
603
613
|
// Discord: a team that pays for more) is still served when the pools are
|
|
604
614
|
// spent, so they are shown aside, and its On-demand spend is what can run
|
|
605
615
|
// out: at its limit (a team member with none of their own: the team's
|
|
606
|
-
// pool), or never when it has none.
|
|
607
|
-
//
|
|
608
|
-
|
|
616
|
+
// pool), or never when it has none. With includedOnly (INCLUDED_ONLY on)
|
|
617
|
+
// the pools are the allowance whatever on-demand allows, and On-demand is
|
|
618
|
+
// shown only. An Enterprise account's period has no planUsage; its
|
|
619
|
+
// allowance comes from usage-summary instead.
|
|
620
|
+
async function usage(tok, ids, includedOnly = false) {
|
|
609
621
|
const [res, hard] = await Promise.all([
|
|
610
622
|
fetch(API + "/aiserver.v1.DashboardService/GetCurrentPeriodUsage", {
|
|
611
623
|
method: "POST",
|
|
@@ -620,7 +632,7 @@ async function usage(tok, ids) {
|
|
|
620
632
|
const u = data?.planUsage
|
|
621
633
|
if (!u) {
|
|
622
634
|
// Prefer measured Enterprise usage before any reset-date-only fallback.
|
|
623
|
-
const windows = await enterpriseUsage(tok)
|
|
635
|
+
const windows = await enterpriseUsage(tok, includedOnly)
|
|
624
636
|
return windows ? { windows } : { windows: [] }
|
|
625
637
|
}
|
|
626
638
|
const ms = /^[+-]?\d+$/.test(data.billingCycleEnd ?? "") ? Number(data.billingCycleEnd) : 0
|
|
@@ -642,10 +654,10 @@ async function usage(tok, ids) {
|
|
|
642
654
|
const pool = [...new Set(["auto", ...asked, ...(data.autoBucketModels ?? [])])].filter(inPool)
|
|
643
655
|
const num = (v) => (typeof v === "number" ? v : 0)
|
|
644
656
|
const od = onDemandOf(data, hard)
|
|
645
|
-
const pooled = od.kind === "fixed" || od.kind === "unlimited" ? { aside: true } : {}
|
|
657
|
+
const pooled = !includedOnly && (od.kind === "fixed" || od.kind === "unlimited") ? { aside: true } : {}
|
|
646
658
|
const onDemand =
|
|
647
659
|
od.kind === "fixed"
|
|
648
|
-
? [{ name: "On-demand", used: Math.max(0, Math.min(100, (100 * od.usedDollars) / od.limitDollars)), display: `${dollars(od.usedDollars)} / ${dollars(od.limitDollars)}` + (od.mineDollars === undefined ? "" : ` (you: ${dollars(od.mineDollars)})`), ...resets }]
|
|
660
|
+
? [{ name: "On-demand", used: Math.max(0, Math.min(100, (100 * od.usedDollars) / od.limitDollars)), display: `${dollars(od.usedDollars)} / ${dollars(od.limitDollars)}` + (od.mineDollars === undefined ? "" : ` (you: ${dollars(od.mineDollars)})`), ...resets, ...(includedOnly ? { aside: true } : {}) }]
|
|
649
661
|
: od.kind === "unlimited"
|
|
650
662
|
? [{ name: "On-demand", used: 0, display: dollars(od.usedDollars), ...resets, aside: true }]
|
|
651
663
|
: []
|
|
@@ -3172,7 +3184,16 @@ async function answerOf(auth, chat, signal, session = "") {
|
|
|
3172
3184
|
|
|
3173
3185
|
// ---- the plugin ---------------------------------------------------------------------------
|
|
3174
3186
|
|
|
3175
|
-
export async function CursorAuthPlugin() {
|
|
3187
|
+
export async function CursorAuthPlugin(input) {
|
|
3188
|
+
// includedOnly is the user's INCLUDED_ONLY as magpie has it now, read at
|
|
3189
|
+
// each usage reading so a change needs no restart; false outside magpie
|
|
3190
|
+
const includedOnly = () => {
|
|
3191
|
+
try {
|
|
3192
|
+
return input?.magpie?.option?.(ID, INCLUDED_ONLY) === true
|
|
3193
|
+
} catch {
|
|
3194
|
+
return false
|
|
3195
|
+
}
|
|
3196
|
+
}
|
|
3176
3197
|
return {
|
|
3177
3198
|
auth: {
|
|
3178
3199
|
provider: ID,
|
|
@@ -3205,6 +3226,16 @@ export async function CursorAuthPlugin() {
|
|
|
3205
3226
|
{ type: "oauth", label: "cursor-agent's sign-in", authorize: cliSignIn },
|
|
3206
3227
|
{ type: "api", label: "Cursor API key (cursor.com/dashboard → Integrations)" },
|
|
3207
3228
|
],
|
|
3229
|
+
// magpie's own switches (input.magpie.option), read at each usage
|
|
3230
|
+
// reading
|
|
3231
|
+
options: [
|
|
3232
|
+
{
|
|
3233
|
+
key: INCLUDED_ONLY,
|
|
3234
|
+
label: "Included usage only",
|
|
3235
|
+
description:
|
|
3236
|
+
"Keeps an account in routing only while its included usage lasts: once Cursor Models or Other Models is used up, magpie moves those models to the next account until the period resets, even if on-demand could pay. On-demand and Total are still shown but never keep an account in routing.",
|
|
3237
|
+
},
|
|
3238
|
+
],
|
|
3208
3239
|
// magpie's: how much of the plan's included usage is gone (the plan
|
|
3209
3240
|
// is the one the sign-in read). The built-in's read, clean or not,
|
|
3210
3241
|
// neither marked the account nor cleared it.
|
|
@@ -3215,7 +3246,7 @@ export async function CursorAuthPlugin() {
|
|
|
3215
3246
|
} catch (e) {
|
|
3216
3247
|
return { error: e.message, windows: [], signIn: "kept" }
|
|
3217
3248
|
}
|
|
3218
|
-
const [u, plan, bot] = await Promise.all([usage(tok, Object.keys(provider?.models ?? {})), planOf(tok), botUsage(tok)])
|
|
3249
|
+
const [u, plan, bot] = await Promise.all([usage(tok, Object.keys(provider?.models ?? {}), includedOnly()), planOf(tok), botUsage(tok)])
|
|
3219
3250
|
// Bot goes among magpie's three menu-bar rings: before Total, and
|
|
3220
3251
|
// before an On-demand with no limit, which is only a dollar figure on
|
|
3221
3252
|
// a ring that never fills (magpie #2213, Morganwan90). An On-demand
|
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.31",
|
|
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",
|