@magpie-community/opencode-cursor-auth 0.2.38 → 0.2.39
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 +30 -11
- package/index.mjs +84 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -208,17 +208,36 @@ minutes), the way pi-cursor-sdk lists Cursor's catalog:
|
|
|
208
208
|
has. A model the usable list has nothing of is the picker's alone
|
|
209
209
|
(GLM-5.3) and is kept whole; so is every model when Cursor can't give
|
|
210
210
|
the usable list.
|
|
211
|
-
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
(`
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
211
|
+
- The full catalog (`AvailableModels` with `scope: 3`, asked alongside the
|
|
212
|
+
other two; it also lists the models Cursor hides from an account, Claude
|
|
213
|
+
from a Pro one) supplies the Anthropic models the picker lacks: each live
|
|
214
|
+
one (not `isHidden`, not Auto, not chat-only or Tab-only) with a variant
|
|
215
|
+
the usable list has an id for is listed as the picker's models are, once
|
|
216
|
+
for each context size (`claude-opus-5-5@300k`, `claude-opus-5-5@1m`; name
|
|
217
|
+
"Claude Opus 5.5 @ 300k"), thinking a parameter, the efforts the account
|
|
218
|
+
is served, and the larger size in Max Mode with that `context`. A catalog
|
|
219
|
+
variant without its own id gets the one of the model's ids that says its
|
|
220
|
+
effort, thinking and fast; with none or several it is not offered. Only
|
|
221
|
+
the parameters the model defines are sent (the catalog's variants also
|
|
222
|
+
carry `cyber=false`, which the picker's don't and cursor-agent never
|
|
223
|
+
sends). With no effort asked, a model goes at Cursor's default variant
|
|
224
|
+
(Opus 5 and 4.8: high), as the picker's models do, not at medium as the
|
|
225
|
+
fallback entries did. The picker's models and every model that is not
|
|
226
|
+
Anthropic's don't change.
|
|
227
|
+
An id saved from an earlier list (`claude-opus-5-5`,
|
|
228
|
+
`claude-opus-4-8-thinking@1m`) runs as the model at the nearest size it
|
|
229
|
+
has, as a usable id.
|
|
230
|
+
- When Cursor can't give the catalog, a family the usable list has and the
|
|
231
|
+
picker doesn't (`claude-opus-5-5-low` to `-max`) is listed once under its
|
|
232
|
+
family id (`claude-opus-5-5`), its efforts as variants, and goes as the
|
|
233
|
+
usable id those parameters pick, never as the family id Cursor doesn't
|
|
234
|
+
know; it has no window in the usable list, so 200K is assumed. A picker
|
|
235
|
+
model whose chosen variant isn't one the account can use goes as its
|
|
236
|
+
family's nearest usable id the same way. Such a family is named without
|
|
237
|
+
the tier Cursor's names carry ("Claude Opus 5 1M Medium Thinking" is
|
|
238
|
+
listed as Claude Opus 5 Thinking): the tier is the reasoning level the
|
|
239
|
+
agent asks for (low to max, as the account has them), fast the request's
|
|
240
|
+
`service_tier`.
|
|
222
241
|
- An id for a model with thinking that the account lists only without it
|
|
223
242
|
(`claude-haiku-5-5-thinking` when the list has Claude Haiku 5.5 alone),
|
|
224
243
|
or the other way round, runs as the model the account has. So does a
|
package/index.mjs
CHANGED
|
@@ -1082,6 +1082,69 @@ function modelsOf(picker, ids, listed = []) {
|
|
|
1082
1082
|
return out
|
|
1083
1083
|
}
|
|
1084
1084
|
|
|
1085
|
+
// slugFor is the id of a variant the full catalog (AvailableModels with
|
|
1086
|
+
// scope 3) gives no legacySlug: the one of the model's legacySlugs that says
|
|
1087
|
+
// the variant's effort (any, when it has none), thinking and fast; an id
|
|
1088
|
+
// with no effort in it (gpt-5.3-codex) stands for the default's effort. With
|
|
1089
|
+
// none, or more than one, "": a guess could send an id Cursor refuses.
|
|
1090
|
+
function slugFor(m, v) {
|
|
1091
|
+
if (v.legacySlug) return v.legacySlug
|
|
1092
|
+
const have = valuesOf(v)
|
|
1093
|
+
const level = (p) => String(p[EFFORT_PARAMS.find((k) => p[k])] ?? "").replace("extra-high", "xhigh")
|
|
1094
|
+
const effort = level(have)
|
|
1095
|
+
const slugs = (Array.isArray(m.legacySlugs) ? m.legacySlugs : []).filter((id) => typeof id === "string" && id).map((id) => ({ id, ...familyOf(id) }))
|
|
1096
|
+
const says = (s, at) =>
|
|
1097
|
+
(at === null || s.effort === at) &&
|
|
1098
|
+
(have.thinking === undefined || s.family.endsWith("-thinking") === (have.thinking === "true")) &&
|
|
1099
|
+
(have.fast === undefined || s.fast === (have.fast === "true"))
|
|
1100
|
+
let hits = slugs.filter((s) => says(s, effort || null))
|
|
1101
|
+
const def = m.variants.find((x) => x?.isDefaultNonMaxConfig)
|
|
1102
|
+
if (!hits.length && effort && level(valuesOf(def)) === effort) hits = slugs.filter((s) => says(s, ""))
|
|
1103
|
+
return hits.length === 1 ? hits[0].id : ""
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1106
|
+
// withSlugs is a catalog model with each variant's own id filled in, and
|
|
1107
|
+
// only the parameters the model defines: the full catalog is the admin
|
|
1108
|
+
// settings one, and carries what the picker's variants don't (cyber=false
|
|
1109
|
+
// on Opus 4.7 to 5.5, which cursor-agent never sends). A variant slugFor
|
|
1110
|
+
// can't name keeps no id of its own, but never goes without one: served()
|
|
1111
|
+
// leaves a variant with no legacySlug in, and one the account can't run
|
|
1112
|
+
// would be listed. So it gets a mark no usable id has, and modelsOf lists
|
|
1113
|
+
// it as it does a variant the account hasn't got. The variants are never
|
|
1114
|
+
// null.
|
|
1115
|
+
const NO_ID = "\u0000no-id"
|
|
1116
|
+
function withSlugs(m) {
|
|
1117
|
+
const defined = new Set((Array.isArray(m.parameterDefinitions) ? m.parameterDefinitions : []).map((d) => d?.id))
|
|
1118
|
+
const vs = (Array.isArray(m.variants) ? m.variants : [])
|
|
1119
|
+
.filter((v) => v && typeof v === "object" && Array.isArray(v.parameterValues ?? []))
|
|
1120
|
+
.map((v) => ({ ...v, parameterValues: (v.parameterValues ?? []).filter((p) => defined.has(p?.id)) }))
|
|
1121
|
+
const full = { ...m, variants: vs }
|
|
1122
|
+
return { ...full, variants: vs.map((v) => (v.legacySlug ? v : { ...v, legacySlug: slugFor(full, v) || NO_ID })) }
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
// fromCatalog is the live models of Cursor's full catalog (AvailableModels
|
|
1126
|
+
// with scope 3, which also lists the models Cursor hides from some accounts:
|
|
1127
|
+
// Claude, from a Pro one) that the picker lacks, as picker models, with only
|
|
1128
|
+
// the variants the account can run (withSlugs). modelsOf lists them as it
|
|
1129
|
+
// does the picker's: once for each context size, thinking a parameter, the
|
|
1130
|
+
// efforts the account is served. Only Anthropic's are taken: the models the
|
|
1131
|
+
// picker lists, and every other id of the usable list, stay as they are.
|
|
1132
|
+
// Not offered: one the picker has or lists under another name, a hidden one
|
|
1133
|
+
// (isHidden: no longer offered), Auto, one the picker leaves out (chat-only,
|
|
1134
|
+
// Tab-only, no agent), and one with no variant the account has an id for.
|
|
1135
|
+
function fromCatalog(picker, catalog, ids) {
|
|
1136
|
+
const have = new Set(picker.map((m) => m?.name))
|
|
1137
|
+
const out = []
|
|
1138
|
+
for (const m of Array.isArray(catalog) ? catalog : []) {
|
|
1139
|
+
if (!m?.name || have.has(m.name) || m.isHidden || m.name === "default") continue
|
|
1140
|
+
if (m.vendor?.id !== "MODEL_VENDOR_ID_ANTHROPIC") continue
|
|
1141
|
+
if (m.isChatOnly || m.onlySupportsCmdK || m.supportsAgent === false || PICKER_SKIP.has(m.name)) continue
|
|
1142
|
+
const full = withSlugs(m)
|
|
1143
|
+
if (full.variants.some((v) => ids.has(v.legacySlug))) out.push(full)
|
|
1144
|
+
}
|
|
1145
|
+
return out
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1085
1148
|
// fastAt is whether Cursor has a fast variant the account is served at
|
|
1086
1149
|
// the context size (any, for a model without sizes): what magpie offers
|
|
1087
1150
|
// fast for, which 0.1.x said with a -fast model of its own.
|
|
@@ -1215,15 +1278,23 @@ function listing(tok, h) {
|
|
|
1215
1278
|
let p = listings.get(h)
|
|
1216
1279
|
if (p) return p
|
|
1217
1280
|
p = (async () => {
|
|
1218
|
-
const [j, listed] = await Promise.all([
|
|
1281
|
+
const [j, listed, catalog] = await Promise.all([
|
|
1219
1282
|
unary(API, "aiserver.v1.AiService/AvailableModels", tok, { useModelParameters: true, doNotUseMarkdown: true }, 30_000),
|
|
1220
1283
|
unary(API, "agent.v1.AgentService/GetUsableModels", tok, {}, 8_000).then(
|
|
1221
1284
|
(u) => (Array.isArray(u?.models) ? u.models : []),
|
|
1222
1285
|
() => [],
|
|
1223
1286
|
),
|
|
1287
|
+
// the full catalog, scope 3: the live models the picker lacks (Claude,
|
|
1288
|
+
// on an account Cursor blocks it for); without it the list is the
|
|
1289
|
+
// picker's and the usable list's, as before
|
|
1290
|
+
unary(API, "aiserver.v1.AiService/AvailableModels", tok, { useModelParameters: true, doNotUseMarkdown: true, scope: 3 }, 8_000).then(
|
|
1291
|
+
(c) => (Array.isArray(c?.models) ? c.models : []),
|
|
1292
|
+
() => [],
|
|
1293
|
+
),
|
|
1224
1294
|
])
|
|
1225
1295
|
const ids = new Set(listed.flatMap((m) => [m?.modelId, m?.displayModelId]).filter(Boolean))
|
|
1226
|
-
const
|
|
1296
|
+
const picker = Array.isArray(j?.models) ? j.models : []
|
|
1297
|
+
const raw = modelsOf(ids.size ? [...picker, ...fromCatalog(picker, catalog, ids)] : picker, ids.size ? ids : null, listed)
|
|
1227
1298
|
if (!raw.length) throw new Error("Cursor listed no models")
|
|
1228
1299
|
lists.set(h, { at: Date.now(), raw })
|
|
1229
1300
|
listFailed.delete(h)
|
|
@@ -1330,7 +1401,16 @@ function named(raw, id) {
|
|
|
1330
1401
|
return { entry: near, seed: undefined, effort: "", fast: false }
|
|
1331
1402
|
}
|
|
1332
1403
|
const old = named(raw, sized[1])
|
|
1333
|
-
if (old)
|
|
1404
|
+
if (old) {
|
|
1405
|
+
// the name's model at the nearest size it has (claude-opus-4-8-thinking@1m,
|
|
1406
|
+
// an id an earlier list had, is Opus 4.8 at 1m with thinking)
|
|
1407
|
+
const sizes = raw.filter((e) => e.size && e.model === old.entry.model)
|
|
1408
|
+
if (old.entry.size && sizes.length) {
|
|
1409
|
+
const near = sizes.reduce((a, b) => (Math.abs(tokensOf(b.size) - want) < Math.abs(tokensOf(a.size) - want) ? b : a))
|
|
1410
|
+
return { ...old, entry: near }
|
|
1411
|
+
}
|
|
1412
|
+
return { ...old, max: !old.entry.size && want > old.entry.context }
|
|
1413
|
+
}
|
|
1334
1414
|
}
|
|
1335
1415
|
return null
|
|
1336
1416
|
}
|
|
@@ -3535,4 +3615,4 @@ export async function CursorAuthPlugin(input) {
|
|
|
3535
3615
|
}
|
|
3536
3616
|
|
|
3537
3617
|
// for tests
|
|
3538
|
-
export const _internal = { credits, kvReply, listFor, lists, keychain, keychainToken, nativeTransport, onDemandOf,resetH1: () => (h1Until = 0), onH1: () => Date.now() < h1Until, resetTeam: () => { teamRead.at = 0; teamRead.info = null }, expireTeam: () => (teamRead.at = 0),H2, H1, h2Blocked, open, openH1, openH2, STEP_WAIT, stepUsage, usageKey, ledger, owed, flights, misses, unreadable, catalog, usable, request, modelsOf, tokensOf, maxRequired, conversationID, usageOf, sessionOf, SESSION, errorResponse, kept, poolBase, conversation, buildRun, decode, exec, fields, pb, pbValue, pbAny, frame, frames, failure, toolsOf, expiry }
|
|
3618
|
+
export const _internal = { slugFor, fromCatalog, credits, kvReply, listFor, lists, keychain, keychainToken, nativeTransport, onDemandOf,resetH1: () => (h1Until = 0), onH1: () => Date.now() < h1Until, resetTeam: () => { teamRead.at = 0; teamRead.info = null }, expireTeam: () => (teamRead.at = 0),H2, H1, h2Blocked, open, openH1, openH2, STEP_WAIT, stepUsage, usageKey, ledger, owed, flights, misses, unreadable, catalog, usable, request, modelsOf, tokensOf, maxRequired, conversationID, usageOf, sessionOf, SESSION, errorResponse, kept, poolBase, conversation, buildRun, decode, exec, fields, pb, pbValue, pbAny, frame, frames, failure, toolsOf, expiry }
|
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.39",
|
|
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": "./opencode.mjs",
|