@magpie-community/opencode-cursor-auth 0.2.28 → 0.2.29
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 +4 -2
- package/index.mjs +43 -15
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -51,8 +51,10 @@ plugin's `fetch` answers them on Cursor's agent API:
|
|
|
51
51
|
(refused, no network) or a stream the server refused leaves the next Run
|
|
52
52
|
to try HTTP/2 again. A region error over HTTP/1.1 sends the Run back to
|
|
53
53
|
HTTP/2 at the region's agent host. BidiAppends go up numbered in order,
|
|
54
|
-
up to 16 at a time as cursor-agent sends them
|
|
55
|
-
|
|
54
|
+
up to 16 at a time as cursor-agent sends them. A native session's Run
|
|
55
|
+
sends only its KV replies (the history's blobs) that way; a tool result
|
|
56
|
+
or anything else waits for the appends before it, goes alone, and is
|
|
57
|
+
written once Cursor answered it, so it is never uncertain. A BidiAppend
|
|
56
58
|
with no answer in 60 s (more for a large one) ends the Run, as
|
|
57
59
|
cursor-agent does.
|
|
58
60
|
- A new Run imports the whole conversation as AI SDK messages kept as blobs
|
package/index.mjs
CHANGED
|
@@ -2038,10 +2038,11 @@ async function agentURL(tok, fresh) {
|
|
|
2038
2038
|
// H2.retryAfter, or until a region error sends one back (answerOf); a
|
|
2039
2039
|
// connection that failed (refused, no network) or a stream the server
|
|
2040
2040
|
// refused leaves the next Run to try HTTP/2 again. atOnce is how many
|
|
2041
|
-
// BidiAppends openH1 may have on their way at once
|
|
2041
|
+
// BidiAppends openH1 may have on their way at once, overlaps which messages
|
|
2042
|
+
// may be among them (openH1).
|
|
2042
2043
|
let h1Until = 0
|
|
2043
2044
|
const cancelledOpen = () => ({ error: { status: 410, message: "the request was cancelled" }, h2Failed: false })
|
|
2044
|
-
async function open(base, headers, signal, atOnce = H1.atOnce) {
|
|
2045
|
+
async function open(base, headers, signal, atOnce = H1.atOnce, overlaps) {
|
|
2045
2046
|
if (signal?.aborted) return cancelledOpen()
|
|
2046
2047
|
if (Date.now() >= h1Until) {
|
|
2047
2048
|
const o = await openH2(base, headers, signal)
|
|
@@ -2055,7 +2056,7 @@ async function open(base, headers, signal, atOnce = H1.atOnce) {
|
|
|
2055
2056
|
if (o.blocked) h1Until = Date.now() + H2.retryAfter
|
|
2056
2057
|
}
|
|
2057
2058
|
if (signal?.aborted) return cancelledOpen()
|
|
2058
|
-
return openH1(headers, signal, atOnce)
|
|
2059
|
+
return openH1(headers, signal, atOnce, overlaps)
|
|
2059
2060
|
}
|
|
2060
2061
|
|
|
2061
2062
|
const H2 = {
|
|
@@ -2128,10 +2129,19 @@ const H1 = {
|
|
|
2128
2129
|
// keeps them: one at a time, a new Run's history (a blob a message,
|
|
2129
2130
|
// hundreds for a long conversation, all asked for at once) took a round
|
|
2130
2131
|
// trip to Cursor each before the model could start. A native session's
|
|
2131
|
-
// Run
|
|
2132
|
+
// Run sends only its KV replies that way (kvReply); each of its other
|
|
2133
|
+
// messages waits for every append before it, and goes alone (runNative).
|
|
2132
2134
|
atOnce: 16,
|
|
2133
2135
|
}
|
|
2134
2136
|
|
|
2137
|
+
// kvReply is whether a client message (an AgentClientMessage, unframed) is
|
|
2138
|
+
// a KV reply, kv_client_message: a blob Cursor asked for, which nothing
|
|
2139
|
+
// else waits on. Cursor asks for a new Run's whole history at once.
|
|
2140
|
+
function kvReply(msg) {
|
|
2141
|
+
const b = Buffer.isBuffer(msg) ? msg : Buffer.from(msg ?? EMPTY)
|
|
2142
|
+
return b.length > 0 && b[0] === 0x1a // field 3, length-delimited
|
|
2143
|
+
}
|
|
2144
|
+
|
|
2135
2145
|
// connectCode is Connect's code for an HTTP status that came with no
|
|
2136
2146
|
// Connect error of its own
|
|
2137
2147
|
function connectCode(status) {
|
|
@@ -2144,8 +2154,11 @@ function connectCode(status) {
|
|
|
2144
2154
|
// the stream it reads, Connect's frames as the HTTP/2 Run's. Its response
|
|
2145
2155
|
// is a 200 at once; an error Cursor says later, or a call that fails,
|
|
2146
2156
|
// ends the stream with Connect's end frame, which runOnce reads as the
|
|
2147
|
-
// Run's own.
|
|
2148
|
-
|
|
2157
|
+
// Run's own. overlaps says of a message whether it may go up while appends
|
|
2158
|
+
// before it are on their way (up to atOnce of them); one that may not waits
|
|
2159
|
+
// for all of them, goes alone, and its write's callback is its own append
|
|
2160
|
+
// answered.
|
|
2161
|
+
function openH1(headers, signal, atOnce = H1.atOnce, overlaps = () => true) {
|
|
2149
2162
|
if (signal?.aborted) return Promise.resolve(cancelledOpen())
|
|
2150
2163
|
const ac = new AbortController()
|
|
2151
2164
|
const id = headers["x-request-id"]
|
|
@@ -2159,11 +2172,20 @@ function openH1(headers, signal, atOnce = H1.atOnce) {
|
|
|
2159
2172
|
write(chunk, _enc, cb) {
|
|
2160
2173
|
// runOnce writes one whole frame each time
|
|
2161
2174
|
const msg = Buffer.from(chunk).subarray(5)
|
|
2162
|
-
const
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2175
|
+
const go = () => {
|
|
2176
|
+
const p = append(msg, seq++)
|
|
2177
|
+
going.add(p)
|
|
2178
|
+
const gone = () => going.delete(p)
|
|
2179
|
+
p.then(gone, gone)
|
|
2180
|
+
return p
|
|
2181
|
+
}
|
|
2182
|
+
if (!overlaps(msg)) {
|
|
2183
|
+
// alone: after every append before it is answered, and answered
|
|
2184
|
+
// itself before the next write
|
|
2185
|
+
Promise.allSettled([...going]).then(go).then(() => cb(), (e) => cb(e))
|
|
2186
|
+
return
|
|
2187
|
+
}
|
|
2188
|
+
go()
|
|
2167
2189
|
// Up to atOnce appends go at once; past that the write stays
|
|
2168
2190
|
// buffered until one finishes, so callbacks and drain reflect the
|
|
2169
2191
|
// pending upload rather than an unbounded promise chain. At one,
|
|
@@ -2432,9 +2454,15 @@ async function runNative({ tok, base, id, tools, conv, convID, signal, maxMode,
|
|
|
2432
2454
|
"x-cursor-agent-allowed-tools": "mcp_tool_call,get_mcp_tools_tool_call",
|
|
2433
2455
|
},
|
|
2434
2456
|
native.ac.signal,
|
|
2435
|
-
//
|
|
2436
|
-
//
|
|
2437
|
-
|
|
2457
|
+
// Over HTTP/1.1 the history's blobs go up H1.atOnce at a time, as
|
|
2458
|
+
// cursor-agent sends them; one at a time, a Run with a long history
|
|
2459
|
+
// waited a round trip to api2 a blob before its first token (ysm119 on
|
|
2460
|
+
// Discord: 135 blobs, 37 s against 3 s over HTTP/2). Everything else
|
|
2461
|
+
// goes alone, after the appends before it were answered, and counts as
|
|
2462
|
+
// written only once Cursor answered it, so a tool result is never
|
|
2463
|
+
// uncertain.
|
|
2464
|
+
H1.atOnce,
|
|
2465
|
+
kvReply,
|
|
2438
2466
|
)
|
|
2439
2467
|
if (o.error) {
|
|
2440
2468
|
native.fail(o.error)
|
|
@@ -3167,4 +3195,4 @@ export async function CursorAuthPlugin() {
|
|
|
3167
3195
|
}
|
|
3168
3196
|
|
|
3169
3197
|
// for tests
|
|
3170
|
-
export const _internal = { 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 }
|
|
3198
|
+
export const _internal = { 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.29",
|
|
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",
|