@magpie-community/opencode-cursor-auth 0.2.22 → 0.2.24
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 +194 -14
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -197,6 +197,17 @@ minutes), the way pi-cursor-sdk lists Cursor's catalog:
|
|
|
197
197
|
has. A model the usable list has nothing of is the picker's alone
|
|
198
198
|
(GLM-5.3) and is kept whole; so is every model when Cursor can't give
|
|
199
199
|
the usable list.
|
|
200
|
+
- A family the usable list has and the picker doesn't (an account whose
|
|
201
|
+
picker lacks Claude Opus 5.5 while `cursor-agent models` lists
|
|
202
|
+
`claude-opus-5-5-low` to `-max`) is listed once under its family id
|
|
203
|
+
(`claude-opus-5-5`), its efforts as variants, and goes as the usable id
|
|
204
|
+
those parameters pick, never as the family id Cursor doesn't know. A
|
|
205
|
+
picker model whose chosen variant isn't one the account can use goes as
|
|
206
|
+
its family's nearest usable id the same way.
|
|
207
|
+
- An `@<size>` id the list no longer has (`claude-opus-5-5@1m` when only
|
|
208
|
+
300k is listed, or the model is listed unsized) runs at the model's
|
|
209
|
+
nearest size, in Max Mode when the size asked for is over the model's
|
|
210
|
+
window, never as the literal `@<size>` id.
|
|
200
211
|
- An id from before 0.2.0 still runs. A variant's own id
|
|
201
212
|
(`claude-opus-5-5-high`) is that variant; a family 0.1.x listed
|
|
202
213
|
(`claude-opus-5-5`, `claude-opus-5-5-fast`, `claude-haiku-5-5-thinking`,
|
package/index.mjs
CHANGED
|
@@ -117,6 +117,68 @@ function authFile() {
|
|
|
117
117
|
return join(process.env.XDG_CONFIG_HOME || join(home, ".config"), "cursor", "auth.json")
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
+
// cliConfigFile is cursor-agent's cli-config.json, where it keeps the team
|
|
121
|
+
// it signed in to (authInfo.activeTeamId); its directory found as the CLI
|
|
122
|
+
// finds it, on every OS.
|
|
123
|
+
function cliConfigFile() {
|
|
124
|
+
const dir = process.env.CURSOR_CONFIG_DIR?.trim()
|
|
125
|
+
|| (process.env.XDG_CONFIG_HOME?.trim() ? join(process.env.XDG_CONFIG_HOME, "cursor") : join(homedir(), ".cursor"))
|
|
126
|
+
return join(dir, "cli-config.json")
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// tokenSub is a JWT's subject (the auth id, "auth0|user_…"); "" when it
|
|
130
|
+
// doesn't say.
|
|
131
|
+
function tokenSub(tok) {
|
|
132
|
+
const parts = String(tok ?? "").split(".")
|
|
133
|
+
if (parts.length !== 3) return ""
|
|
134
|
+
try {
|
|
135
|
+
const sub = JSON.parse(Buffer.from(parts[1], "base64url").toString("utf8"))?.sub
|
|
136
|
+
return typeof sub === "string" ? sub : ""
|
|
137
|
+
} catch {
|
|
138
|
+
return ""
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const teamOf = (v) => (Number.isSafeInteger(v) && v > 0 ? v : undefined)
|
|
143
|
+
|
|
144
|
+
// activeTeamId is the team a request is billed to, as cursor-agent sends it
|
|
145
|
+
// (x-cursor-team-id): cli-config.json's authInfo.activeTeamId. Without it
|
|
146
|
+
// Cursor takes the token's default team, which in an organization may be one
|
|
147
|
+
// with on-demand spend turned off ("Team budget limit reached"). The config's
|
|
148
|
+
// team is only taken for the account cursor-agent signed in to: a token
|
|
149
|
+
// whose subject isn't its authInfo.authId, or a config with none, gets none.
|
|
150
|
+
// Read again after 10 s; cursor-agent rewrites the file in place, so a read
|
|
151
|
+
// that fails to parse keeps the last one, and only a missing file clears it.
|
|
152
|
+
const TEAM_TTL = 10_000
|
|
153
|
+
const teamRead = { at: 0, info: null }
|
|
154
|
+
async function activeTeamId(tok) {
|
|
155
|
+
if (Date.now() - teamRead.at >= TEAM_TTL) {
|
|
156
|
+
try {
|
|
157
|
+
teamRead.info = JSON.parse(await readFile(cliConfigFile(), "utf8"))?.authInfo ?? null
|
|
158
|
+
} catch (e) {
|
|
159
|
+
if (e?.code === "ENOENT") teamRead.info = null
|
|
160
|
+
}
|
|
161
|
+
teamRead.at = Date.now()
|
|
162
|
+
}
|
|
163
|
+
const info = teamRead.info
|
|
164
|
+
if (!info) return undefined
|
|
165
|
+
if (!info.authId || info.authId !== tokenSub(tok)) return undefined
|
|
166
|
+
return teamOf(info.activeTeamId)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// teamHeader names that team in a request's headers, and teamBody in
|
|
170
|
+
// GetFilteredUsageEvents' body; neither says anything when there is none.
|
|
171
|
+
// GetHardLimit and GetCurrentPeriodUsage go out with "{}", as cursor-agent
|
|
172
|
+
// sends them: the team rides in the header only.
|
|
173
|
+
async function teamHeader(tok) {
|
|
174
|
+
const id = await activeTeamId(tok)
|
|
175
|
+
return id ? { "x-cursor-team-id": String(id) } : {}
|
|
176
|
+
}
|
|
177
|
+
async function teamBody(tok) {
|
|
178
|
+
const id = await activeTeamId(tok)
|
|
179
|
+
return id ? { teamId: id } : {}
|
|
180
|
+
}
|
|
181
|
+
|
|
120
182
|
// TOKEN_TTL is how long a token read from the Keychain is taken as it: a
|
|
121
183
|
// sign-in reads it afresh, one made in cursor-agent is seen within it.
|
|
122
184
|
// KEYCHAIN_DENIED is how long a read the user may have been asked about,
|
|
@@ -218,6 +280,7 @@ async function headersFor(tok) {
|
|
|
218
280
|
"x-cursor-client-version": await clientVersion(),
|
|
219
281
|
"x-cursor-client-type": "cli",
|
|
220
282
|
"x-ghost-mode": "true",
|
|
283
|
+
...await teamHeader(tok),
|
|
221
284
|
}
|
|
222
285
|
}
|
|
223
286
|
|
|
@@ -456,7 +519,7 @@ async function hardLimit(tok) {
|
|
|
456
519
|
try {
|
|
457
520
|
const res = await fetch(API + "/aiserver.v1.DashboardService/GetHardLimit", {
|
|
458
521
|
method: "POST",
|
|
459
|
-
headers: { Authorization: `Bearer ${tok}`, "Content-Type": "application/json", "Connect-Protocol-Version": "1" },
|
|
522
|
+
headers: { Authorization: `Bearer ${tok}`, "Content-Type": "application/json", "Connect-Protocol-Version": "1", ...await teamHeader(tok) },
|
|
460
523
|
body: "{}",
|
|
461
524
|
signal: AbortSignal.timeout(15_000),
|
|
462
525
|
})
|
|
@@ -481,7 +544,7 @@ async function usage(tok, ids) {
|
|
|
481
544
|
const [res, hard] = await Promise.all([
|
|
482
545
|
fetch(API + "/aiserver.v1.DashboardService/GetCurrentPeriodUsage", {
|
|
483
546
|
method: "POST",
|
|
484
|
-
headers: { Authorization: `Bearer ${tok}`, "Content-Type": "application/json", "Connect-Protocol-Version": "1" },
|
|
547
|
+
headers: { Authorization: `Bearer ${tok}`, "Content-Type": "application/json", "Connect-Protocol-Version": "1", ...await teamHeader(tok) },
|
|
485
548
|
body: "{}",
|
|
486
549
|
signal: AbortSignal.timeout(15_000),
|
|
487
550
|
}),
|
|
@@ -672,12 +735,72 @@ function served(m, ids) {
|
|
|
672
735
|
return got.some((v) => v.legacySlug) ? got : vs
|
|
673
736
|
}
|
|
674
737
|
|
|
738
|
+
// familyOf is the family one of Cursor's own ids is of, fast or not:
|
|
739
|
+
// claude-opus-5-5-low-fast is of claude-opus-5-5, at low, fast.
|
|
740
|
+
function familyOf(id) {
|
|
741
|
+
let [family, effort] = splitID(id)
|
|
742
|
+
const fast = family.endsWith("-fast") && family.length > "-fast".length
|
|
743
|
+
if (fast) family = family.slice(0, -"-fast".length)
|
|
744
|
+
return { family, effort, fast }
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
// familiesOf is the usable list (GetUsableModels, what cursor-agent models
|
|
748
|
+
// shows: claude-opus-5-5-low, claude-opus-5-5-low-fast, …) by family: each
|
|
749
|
+
// id with its effort, whether it is fast, whether Cursor runs it in Max
|
|
750
|
+
// Mode, and its name.
|
|
751
|
+
function familiesOf(listed) {
|
|
752
|
+
const fams = new Map()
|
|
753
|
+
for (const u of listed ?? []) {
|
|
754
|
+
const id = String(u?.modelId ?? "")
|
|
755
|
+
if (!id) continue
|
|
756
|
+
const { family, effort, fast } = familyOf(id)
|
|
757
|
+
if (!fams.has(family)) fams.set(family, [])
|
|
758
|
+
fams.get(family).push({ id, effort, fast, maxMode: u.maxMode === true, name: clean(u.displayName || id) })
|
|
759
|
+
}
|
|
760
|
+
return fams
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
// fromUsable is the id of a family of the usable list's that a request
|
|
764
|
+
// runs as: fast as asked (when the family has both), at the effort asked or
|
|
765
|
+
// the nearest it has; with none asked, the one without an effort in its
|
|
766
|
+
// id, else medium, as Cursor's default is (claude-opus-5-5-medium), else
|
|
767
|
+
// the first.
|
|
768
|
+
function fromUsable(fam, effort, fast) {
|
|
769
|
+
let vs = fam.filter((u) => u.fast === !!fast)
|
|
770
|
+
if (!vs.length) vs = fam
|
|
771
|
+
if (effort === "off") effort = "none"
|
|
772
|
+
const at = effort ? fitEffort(effort, vs.map((u) => u.effort).filter(Boolean)) : ""
|
|
773
|
+
return (at && vs.find((u) => u.effort === at)) || vs.find((u) => u.effort === "") || vs.find((u) => u.effort === "medium") || vs[0]
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
// usableTitle is a usable id's name without what the id says apart: the
|
|
777
|
+
// effort, fast, and the 1M Cursor names every Max-capable Claude with
|
|
778
|
+
// ("Claude Opus 5.5 1M Low" is Claude Opus 5.5).
|
|
779
|
+
function usableTitle(name) {
|
|
780
|
+
const drop = new Set(["low", "medium", "high", "xhigh", "extra", "max", "minimal", "none", "fast", "1m", "(1m)"])
|
|
781
|
+
const ws = name.split(" ")
|
|
782
|
+
while (ws.length > 1 && drop.has(ws.at(-1).toLowerCase())) ws.pop()
|
|
783
|
+
return ws.join(" ")
|
|
784
|
+
}
|
|
785
|
+
|
|
675
786
|
// modelsOf is the picker's models as offered: one entry for each context
|
|
676
787
|
// size a model has, or one with Cursor's limit when it has none. A model
|
|
677
788
|
// served in part is offered at the sizes and efforts it is served at.
|
|
678
|
-
|
|
789
|
+
// listed is the usable list: a family of its ids the picker has nothing of
|
|
790
|
+
// (a Team's picker can leave out what cursor-agent models lists, magpie
|
|
791
|
+
// #3150 ysm119 on Discord) is offered too, once, with its efforts, and each
|
|
792
|
+
// entry keeps its family's usable ids, so a request goes as one of those
|
|
793
|
+
// and never as a name Cursor would answer "AI Model Not Found".
|
|
794
|
+
function modelsOf(picker, ids, listed = []) {
|
|
679
795
|
const out = []
|
|
680
796
|
const used = new Set()
|
|
797
|
+
const fams = familiesOf(listed)
|
|
798
|
+
// every id the picker names at all, shown or left out
|
|
799
|
+
const named = new Set()
|
|
800
|
+
for (const m of picker) {
|
|
801
|
+
if (!m?.name) continue
|
|
802
|
+
for (const x of [m.name, ...(m.legacySlugs ?? []), ...(m.idAliases ?? []), ...(m.variants ?? []).map((v) => v.legacySlug)]) if (x) named.add(x)
|
|
803
|
+
}
|
|
681
804
|
for (const m of picker) {
|
|
682
805
|
if (!m?.name || m.isHidden || m.isChatOnly || m.onlySupportsCmdK || m.supportsAgent === false || PICKER_SKIP.has(m.name)) continue
|
|
683
806
|
const defs = paramDefs(m)
|
|
@@ -687,7 +810,8 @@ function modelsOf(picker, ids) {
|
|
|
687
810
|
const def = defaultVariant({ variants })
|
|
688
811
|
const { pid, levels: all } = effortsOf(defs)
|
|
689
812
|
const levels = Object.fromEntries(Object.entries(all).filter(([, value]) => has(pid, value)))
|
|
690
|
-
const
|
|
813
|
+
const fam = fams.get(familyOf(def?.legacySlug || m.name).family) ?? []
|
|
814
|
+
const base = { run: m.name, title: clean(m.clientDisplayName || m.name), pid, levels, fast: !!defs.fast?.length, variants, def, partial, model: m, fam, ids }
|
|
691
815
|
const contexts = (defs.context ?? []).filter((c) => has("context", c))
|
|
692
816
|
if (contexts.length) {
|
|
693
817
|
for (const c of contexts) {
|
|
@@ -702,6 +826,15 @@ function modelsOf(picker, ids) {
|
|
|
702
826
|
out.push({ ...base, id: m.name === "default" ? "auto" : m.name, name: base.title, context: limit > 0 ? limit : DEFAULT_CONTEXT, size: "", offersFast: fastAt(variants, "") })
|
|
703
827
|
}
|
|
704
828
|
}
|
|
829
|
+
for (const [family, fam] of fams) {
|
|
830
|
+
if (fam.some((u) => named.has(u.id)) || named.has(family) || used.has(family)) continue
|
|
831
|
+
used.add(family)
|
|
832
|
+
const levels = Object.fromEntries(fam.filter((u) => LEVEL_RANK.includes(u.effort)).map((u) => [u.effort, u.effort]))
|
|
833
|
+
const def = fromUsable(fam, "", false)
|
|
834
|
+
// Cursor's context for it isn't known: its default's, as for a model
|
|
835
|
+
// the picker gives no limit for
|
|
836
|
+
out.push({ id: family, run: family, name: usableTitle(def.name), title: usableTitle(def.name), pid: "", levels, fast: false, variants: [], def: undefined, partial: false, model: { name: family }, fam, ids, usableOnly: true, context: DEFAULT_CONTEXT, size: "", offersFast: fam.some((u) => u.fast) })
|
|
837
|
+
}
|
|
705
838
|
return out
|
|
706
839
|
}
|
|
707
840
|
|
|
@@ -734,6 +867,11 @@ function nearest(vs, want) {
|
|
|
734
867
|
// variant the account has. seed is the variant an id of Cursor's own named
|
|
735
868
|
// (request), in the default's place.
|
|
736
869
|
function pick(entry, effort, fast, seed) {
|
|
870
|
+
// a family the usable list has and the picker doesn't: its own id
|
|
871
|
+
if (entry.usableOnly) {
|
|
872
|
+
const u = fromUsable(entry.fam, effort, fast)
|
|
873
|
+
return { id: u.id, params: [], maxMode: u.maxMode }
|
|
874
|
+
}
|
|
737
875
|
const def = entry.def
|
|
738
876
|
const want = { ...valuesOf(seed ?? def) }
|
|
739
877
|
if (entry.size) want.context = entry.size
|
|
@@ -761,6 +899,14 @@ function pick(entry, effort, fast, seed) {
|
|
|
761
899
|
// cursor-agent models lists it: claude-opus-5-5-high), not the picker's
|
|
762
900
|
// model name; the default's when no variant matched
|
|
763
901
|
const id = v?.legacySlug || def?.legacySlug || entry.run
|
|
902
|
+
// an id the usable list doesn't have, when it has the family's (a
|
|
903
|
+
// picker model without variants goes by its name, claude-opus-5-5,
|
|
904
|
+
// which Cursor doesn't serve): the family's usable id at the effort
|
|
905
|
+
if (entry.ids && !entry.ids.has(id) && entry.fam?.length) {
|
|
906
|
+
const level = entry.pid && entry.pid !== "thinking" ? String(want[entry.pid] ?? "").replace("extra-high", "xhigh") : ""
|
|
907
|
+
const u = fromUsable(entry.fam, effort || level, fast)
|
|
908
|
+
return { id: u.id, params: [], maxMode: maxMode || u.maxMode }
|
|
909
|
+
}
|
|
764
910
|
return { id, params, maxMode }
|
|
765
911
|
}
|
|
766
912
|
|
|
@@ -815,17 +961,15 @@ async function usable(tok) {
|
|
|
815
961
|
const h = createHash("sha256").update(tok).digest("hex")
|
|
816
962
|
const had = lists.get(h)
|
|
817
963
|
if (had && Date.now() - had.at < MODELS_KEEP) return had.raw
|
|
818
|
-
const [j,
|
|
964
|
+
const [j, listed] = await Promise.all([
|
|
819
965
|
unary(API, "aiserver.v1.AiService/AvailableModels", tok, { useModelParameters: true, doNotUseMarkdown: true }, 30_000),
|
|
820
966
|
unary(API, "agent.v1.AgentService/GetUsableModels", tok, {}, 8_000).then(
|
|
821
|
-
(u) =>
|
|
822
|
-
|
|
823
|
-
return ids.size ? ids : null
|
|
824
|
-
},
|
|
825
|
-
() => null,
|
|
967
|
+
(u) => (Array.isArray(u?.models) ? u.models : []),
|
|
968
|
+
() => [],
|
|
826
969
|
),
|
|
827
970
|
])
|
|
828
|
-
const
|
|
971
|
+
const ids = new Set(listed.flatMap((m) => [m?.modelId, m?.displayModelId]).filter(Boolean))
|
|
972
|
+
const raw = modelsOf(Array.isArray(j?.models) ? j.models : [], ids.size ? ids : null, listed)
|
|
829
973
|
if (!raw.length) throw new Error("Cursor listed no models")
|
|
830
974
|
lists.set(h, { at: Date.now(), raw })
|
|
831
975
|
return raw
|
|
@@ -858,8 +1002,33 @@ function named(raw, id) {
|
|
|
858
1002
|
}
|
|
859
1003
|
for (const e of models) {
|
|
860
1004
|
const m = e.model
|
|
1005
|
+
if (e.usableOnly) continue
|
|
861
1006
|
if ([m.name, ...(m.legacySlugs ?? []), ...(m.idAliases ?? [])].includes(id)) return { entry: at(e, e.def), seed: undefined, effort: "", fast: false }
|
|
862
1007
|
}
|
|
1008
|
+
// one of the usable list's own ids, or a family of them, that the picker
|
|
1009
|
+
// has nothing of: that family at the id's effort, fast when it is
|
|
1010
|
+
const of = familyOf(id)
|
|
1011
|
+
for (const e of models) {
|
|
1012
|
+
if (!e.usableOnly) continue
|
|
1013
|
+
const u = e.fam.find((x) => x.id === id)
|
|
1014
|
+
if (u) return { entry: e, seed: undefined, effort: u.effort, fast: u.fast }
|
|
1015
|
+
if (e.id === of.family) return { entry: e, seed: undefined, effort: of.effort, fast: of.fast }
|
|
1016
|
+
}
|
|
1017
|
+
// an id at a context size the list no longer has (claude-opus-5-5@1m,
|
|
1018
|
+
// picked from an earlier list, or from another account's): the model at
|
|
1019
|
+
// the nearest size it has; a model listed without sizes, in Max Mode for
|
|
1020
|
+
// a size over its window
|
|
1021
|
+
const sized = /^(.+)@([^@]+)$/.exec(id)
|
|
1022
|
+
if (sized) {
|
|
1023
|
+
const want = tokensOf(sized[2])
|
|
1024
|
+
const same = raw.filter((e) => e.run === sized[1] && e.size)
|
|
1025
|
+
if (same.length) {
|
|
1026
|
+
const near = same.reduce((a, b) => (Math.abs(tokensOf(b.size) - want) < Math.abs(tokensOf(a.size) - want) ? b : a))
|
|
1027
|
+
return { entry: near, seed: undefined, effort: "", fast: false }
|
|
1028
|
+
}
|
|
1029
|
+
const old = named(raw, sized[1])
|
|
1030
|
+
if (old) return { ...old, max: !old.entry.size && want > old.entry.context }
|
|
1031
|
+
}
|
|
863
1032
|
return null
|
|
864
1033
|
}
|
|
865
1034
|
|
|
@@ -870,8 +1039,17 @@ function named(raw, id) {
|
|
|
870
1039
|
function request(raw, model, effort, fast) {
|
|
871
1040
|
const entry = raw.find((m) => m.id === model)
|
|
872
1041
|
if (entry) return pick(entry, effort, fast)
|
|
1042
|
+
const bare = raw.find((m) => m.id === model.replace(/@[^@]*$/, ""))
|
|
1043
|
+
if (bare && model !== bare.id && !bare.size) {
|
|
1044
|
+
// a model now listed without sizes, asked at one
|
|
1045
|
+
const r = pick(bare, effort, fast)
|
|
1046
|
+
return tokensOf(model.split("@").at(-1)) > bare.context ? { ...r, maxMode: true } : r
|
|
1047
|
+
}
|
|
873
1048
|
const old = named(raw, model)
|
|
874
|
-
if (old)
|
|
1049
|
+
if (old) {
|
|
1050
|
+
const r = pick(old.entry, effort || old.effort, fast || old.fast, old.seed)
|
|
1051
|
+
return old.max ? { ...r, maxMode: true } : r
|
|
1052
|
+
}
|
|
875
1053
|
return { id: model === "auto" ? "default" : model, params: [], maxMode: false }
|
|
876
1054
|
}
|
|
877
1055
|
|
|
@@ -1515,7 +1693,7 @@ async function usageEvents(tok, conv, since, want, { poll = false, first = STEP_
|
|
|
1515
1693
|
const res = await fetch(API + "/aiserver.v1.DashboardService/GetFilteredUsageEvents", {
|
|
1516
1694
|
method: "POST",
|
|
1517
1695
|
headers: await headersFor(tok),
|
|
1518
|
-
body: JSON.stringify({
|
|
1696
|
+
body: JSON.stringify({ ...await teamBody(tok), startDate: String(since - 60_000), endDate: String(Date.now() + 60_000), page: 1, pageSize: 50 }),
|
|
1519
1697
|
signal: abortFetch && signal ? AbortSignal.any([signal, AbortSignal.timeout(STEP_WAIT.ask)]) : AbortSignal.timeout(STEP_WAIT.ask),
|
|
1520
1698
|
})
|
|
1521
1699
|
if (res.status >= 400 && res.status < 500 && res.status !== 429) {
|
|
@@ -2149,6 +2327,7 @@ async function runNative({ tok, base, id, tools, conv, convID, signal, maxMode,
|
|
|
2149
2327
|
"x-cursor-client-type": "cli", // else Cursor adds a prompt of its own
|
|
2150
2328
|
"x-ghost-mode": "true", // privacy mode: nothing kept for training
|
|
2151
2329
|
"x-request-id": randomUUID(),
|
|
2330
|
+
...await teamHeader(tok),
|
|
2152
2331
|
// none of Cursor's own tools, only the caller's
|
|
2153
2332
|
"x-cursor-agent-allowed-tools": "mcp_tool_call,get_mcp_tools_tool_call",
|
|
2154
2333
|
},
|
|
@@ -2237,6 +2416,7 @@ async function runOnce({ tok, base, id, tools, conv, convID, signal, maxMode, pa
|
|
|
2237
2416
|
"x-cursor-client-type": "cli", // else Cursor adds a prompt of its own
|
|
2238
2417
|
"x-ghost-mode": "true", // privacy mode: nothing kept for training
|
|
2239
2418
|
"x-request-id": randomUUID(),
|
|
2419
|
+
...await teamHeader(tok),
|
|
2240
2420
|
// none of Cursor's own tools, only the caller's
|
|
2241
2421
|
"x-cursor-agent-allowed-tools": "mcp_tool_call,get_mcp_tools_tool_call",
|
|
2242
2422
|
},
|
|
@@ -2887,4 +3067,4 @@ export async function CursorAuthPlugin() {
|
|
|
2887
3067
|
}
|
|
2888
3068
|
|
|
2889
3069
|
// for tests
|
|
2890
|
-
export const _internal = { keychain, keychainToken, nativeTransport, onDemandOf,resetH1: () => (h1Until = 0), onH1: () => Date.now() < h1Until, 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 }
|
|
3070
|
+
export const _internal = { 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.24",
|
|
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",
|