@playwo/opencode-cursor-oauth 0.0.0-dev.762b07a81479 → 0.0.0-dev.7fe465ca080f
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/dist/cursor/bidi-session.d.ts +1 -2
- package/dist/cursor/bidi-session.js +153 -138
- package/dist/cursor/index.d.ts +1 -1
- package/dist/cursor/index.js +1 -1
- package/dist/cursor/unary-rpc.d.ts +0 -1
- package/dist/cursor/unary-rpc.js +2 -59
- package/dist/logger.d.ts +1 -0
- package/dist/logger.js +3 -0
- package/dist/openai/messages.d.ts +0 -1
- package/dist/openai/messages.js +0 -3
- package/dist/plugin/cursor-auth-plugin.js +0 -1
- package/dist/proxy/bridge-session.js +1 -3
- package/dist/proxy/bridge-streaming.d.ts +1 -1
- package/dist/proxy/bridge-streaming.js +103 -12
- package/dist/proxy/chat-completion.js +44 -12
- package/dist/proxy/server.js +23 -5
- package/dist/proxy/stream-dispatch.js +289 -23
- package/dist/proxy/types.d.ts +3 -0
- package/package.json +1 -2
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { create, toBinary } from "@bufbuild/protobuf";
|
|
2
|
-
import { AgentClientMessageSchema, ClientHeartbeatSchema, ConversationStateStructureSchema, BackgroundShellSpawnResultSchema, DeleteResultSchema, DeleteRejectedSchema, DiagnosticsResultSchema, ExecClientMessageSchema, FetchErrorSchema, FetchResultSchema, GetBlobResultSchema, GrepErrorSchema, GrepResultSchema, KvClientMessageSchema, LsRejectedSchema, LsResultSchema, McpResultSchema, ReadRejectedSchema, ReadResultSchema, RequestContextResultSchema, RequestContextSchema, RequestContextSuccessSchema, SetBlobResultSchema, ShellRejectedSchema, ShellResultSchema, WriteRejectedSchema, WriteResultSchema, WriteShellStdinErrorSchema, WriteShellStdinResultSchema, } from "../proto/agent_pb";
|
|
2
|
+
import { AgentClientMessageSchema, AskQuestionInteractionResponseSchema, AskQuestionRejectedSchema, AskQuestionResultSchema, ClientHeartbeatSchema, ConversationStateStructureSchema, BackgroundShellSpawnResultSchema, CreatePlanErrorSchema, CreatePlanRequestResponseSchema, CreatePlanResultSchema, DeleteResultSchema, DeleteRejectedSchema, DiagnosticsResultSchema, ExecClientMessageSchema, ExaFetchRequestResponseSchema, ExaFetchRequestResponse_RejectedSchema, ExaSearchRequestResponseSchema, ExaSearchRequestResponse_RejectedSchema, FetchErrorSchema, FetchResultSchema, GetBlobResultSchema, GrepErrorSchema, GrepResultSchema, InteractionResponseSchema, KvClientMessageSchema, LsRejectedSchema, LsResultSchema, McpResultSchema, ReadRejectedSchema, ReadResultSchema, RequestContextResultSchema, RequestContextSchema, RequestContextSuccessSchema, SetBlobResultSchema, ShellRejectedSchema, ShellResultSchema, SwitchModeRequestResponseSchema, SwitchModeRequestResponse_RejectedSchema, WebSearchRequestResponseSchema, WebSearchRequestResponse_RejectedSchema, WriteRejectedSchema, WriteResultSchema, WriteShellStdinErrorSchema, WriteShellStdinResultSchema, } from "../proto/agent_pb";
|
|
3
3
|
import { CONNECT_END_STREAM_FLAG } from "../cursor/config";
|
|
4
|
-
import { logPluginError, logPluginWarn } from "../logger";
|
|
4
|
+
import { logPluginError, logPluginInfo, logPluginWarn } from "../logger";
|
|
5
5
|
import { decodeMcpArgsMap } from "../openai/tools";
|
|
6
6
|
export function parseConnectEndStream(data) {
|
|
7
7
|
try {
|
|
@@ -128,8 +128,90 @@ export function computeUsage(state) {
|
|
|
128
128
|
const prompt_tokens = Math.max(0, total_tokens - completion_tokens);
|
|
129
129
|
return { prompt_tokens, completion_tokens, total_tokens };
|
|
130
130
|
}
|
|
131
|
+
function replacePendingExec(state, exec) {
|
|
132
|
+
const existingIndex = state.pendingExecs.findIndex((candidate) => candidate.toolCallId === exec.toolCallId);
|
|
133
|
+
if (existingIndex >= 0) {
|
|
134
|
+
state.pendingExecs[existingIndex] = exec;
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
state.pendingExecs.push(exec);
|
|
138
|
+
}
|
|
139
|
+
function hasUsableDecodedArgs(decodedArgs) {
|
|
140
|
+
const trimmed = decodedArgs.trim();
|
|
141
|
+
return trimmed !== "" && trimmed !== "{}";
|
|
142
|
+
}
|
|
143
|
+
function mergePendingExec(existing, incoming) {
|
|
144
|
+
const incomingHasExecMetadata = incoming.execMsgId !== 0;
|
|
145
|
+
const existingHasExecMetadata = existing.execMsgId !== 0;
|
|
146
|
+
return {
|
|
147
|
+
execId: incomingHasExecMetadata || !existing.execId ? incoming.execId : existing.execId,
|
|
148
|
+
execMsgId: incomingHasExecMetadata || !existingHasExecMetadata
|
|
149
|
+
? incoming.execMsgId
|
|
150
|
+
: existing.execMsgId,
|
|
151
|
+
toolCallId: existing.toolCallId || incoming.toolCallId,
|
|
152
|
+
toolName: incoming.toolName && incoming.toolName !== "unknown_mcp_tool"
|
|
153
|
+
? incoming.toolName
|
|
154
|
+
: existing.toolName,
|
|
155
|
+
decodedArgs: hasUsableDecodedArgs(incoming.decodedArgs)
|
|
156
|
+
? incoming.decodedArgs
|
|
157
|
+
: existing.decodedArgs,
|
|
158
|
+
source: incomingHasExecMetadata ? incoming.source : existing.source ?? incoming.source,
|
|
159
|
+
cursorCallId: existing.cursorCallId || incoming.cursorCallId,
|
|
160
|
+
modelCallId: existing.modelCallId || incoming.modelCallId,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
function emitPendingExec(exec, state, onMcpExec) {
|
|
164
|
+
const existing = state.pendingExecs.find((candidate) => candidate.toolCallId === exec.toolCallId);
|
|
165
|
+
const nextExec = existing ? mergePendingExec(existing, exec) : exec;
|
|
166
|
+
const hadActionableMetadata = (existing?.execMsgId ?? 0) !== 0;
|
|
167
|
+
const hasActionableMetadata = nextExec.execMsgId !== 0;
|
|
168
|
+
if (state.emittedToolCallIds.has(nextExec.toolCallId)) {
|
|
169
|
+
replacePendingExec(state, nextExec);
|
|
170
|
+
if (!hadActionableMetadata && hasActionableMetadata) {
|
|
171
|
+
logPluginInfo("Cursor MCP tool call metadata upgraded", {
|
|
172
|
+
toolCallId: nextExec.toolCallId,
|
|
173
|
+
toolName: nextExec.toolName,
|
|
174
|
+
source: nextExec.source,
|
|
175
|
+
execId: nextExec.execId,
|
|
176
|
+
execMsgId: nextExec.execMsgId,
|
|
177
|
+
cursorCallId: nextExec.cursorCallId,
|
|
178
|
+
modelCallId: nextExec.modelCallId,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
logPluginInfo("Ignored duplicate Cursor MCP tool call event", {
|
|
183
|
+
toolCallId: nextExec.toolCallId,
|
|
184
|
+
toolName: nextExec.toolName,
|
|
185
|
+
source: nextExec.source,
|
|
186
|
+
execId: nextExec.execId,
|
|
187
|
+
execMsgId: nextExec.execMsgId,
|
|
188
|
+
cursorCallId: nextExec.cursorCallId,
|
|
189
|
+
modelCallId: nextExec.modelCallId,
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
state.emittedToolCallIds.add(nextExec.toolCallId);
|
|
195
|
+
replacePendingExec(state, nextExec);
|
|
196
|
+
logPluginInfo("Emitting Cursor MCP tool call", {
|
|
197
|
+
toolCallId: nextExec.toolCallId,
|
|
198
|
+
toolName: nextExec.toolName,
|
|
199
|
+
source: nextExec.source,
|
|
200
|
+
execId: nextExec.execId,
|
|
201
|
+
execMsgId: nextExec.execMsgId,
|
|
202
|
+
cursorCallId: nextExec.cursorCallId,
|
|
203
|
+
modelCallId: nextExec.modelCallId,
|
|
204
|
+
decodedArgs: nextExec.decodedArgs,
|
|
205
|
+
});
|
|
206
|
+
onMcpExec(nextExec);
|
|
207
|
+
}
|
|
131
208
|
export function processServerMessage(msg, blobStore, mcpTools, sendFrame, state, onText, onMcpExec, onCheckpoint, onTurnEnded, onUnsupportedMessage, onUnhandledExec) {
|
|
132
209
|
const msgCase = msg.message.case;
|
|
210
|
+
if (msgCase !== "conversationCheckpointUpdate") {
|
|
211
|
+
logPluginInfo("Received Cursor server message", {
|
|
212
|
+
messageCase: msgCase ?? "undefined",
|
|
213
|
+
});
|
|
214
|
+
}
|
|
133
215
|
if (msgCase === "interactionUpdate") {
|
|
134
216
|
handleInteractionUpdate(msg.message.value, state, onText, onMcpExec, onTurnEnded, onUnsupportedMessage);
|
|
135
217
|
}
|
|
@@ -137,7 +219,7 @@ export function processServerMessage(msg, blobStore, mcpTools, sendFrame, state,
|
|
|
137
219
|
handleKvMessage(msg.message.value, blobStore, sendFrame);
|
|
138
220
|
}
|
|
139
221
|
else if (msgCase === "execServerMessage") {
|
|
140
|
-
handleExecMessage(msg.message.value, mcpTools, sendFrame, onMcpExec, onUnhandledExec);
|
|
222
|
+
handleExecMessage(msg.message.value, mcpTools, sendFrame, state, onMcpExec, onUnhandledExec);
|
|
141
223
|
}
|
|
142
224
|
else if (msgCase === "execServerControlMessage") {
|
|
143
225
|
onUnsupportedMessage?.({
|
|
@@ -146,10 +228,7 @@ export function processServerMessage(msg, blobStore, mcpTools, sendFrame, state,
|
|
|
146
228
|
});
|
|
147
229
|
}
|
|
148
230
|
else if (msgCase === "interactionQuery") {
|
|
149
|
-
onUnsupportedMessage
|
|
150
|
-
category: "interactionQuery",
|
|
151
|
-
caseName: msg.message.value.query.case ?? "undefined",
|
|
152
|
-
});
|
|
231
|
+
handleInteractionQuery(msg.message.value, sendFrame, onUnsupportedMessage);
|
|
153
232
|
}
|
|
154
233
|
else if (msgCase === "conversationCheckpointUpdate") {
|
|
155
234
|
const stateStructure = msg.message.value;
|
|
@@ -169,6 +248,16 @@ export function processServerMessage(msg, blobStore, mcpTools, sendFrame, state,
|
|
|
169
248
|
}
|
|
170
249
|
function handleInteractionUpdate(update, state, onText, onMcpExec, onTurnEnded, onUnsupportedMessage) {
|
|
171
250
|
const updateCase = update.message?.case;
|
|
251
|
+
if (updateCase !== "textDelta" &&
|
|
252
|
+
updateCase !== "thinkingDelta" &&
|
|
253
|
+
updateCase !== "tokenDelta") {
|
|
254
|
+
logPluginInfo("Received Cursor interaction update", {
|
|
255
|
+
updateCase: updateCase ?? "undefined",
|
|
256
|
+
callId: update.message?.value?.callId,
|
|
257
|
+
modelCallId: update.message?.value?.modelCallId,
|
|
258
|
+
toolCase: update.message?.value?.toolCall?.tool?.case,
|
|
259
|
+
});
|
|
260
|
+
}
|
|
172
261
|
if (updateCase === "textDelta") {
|
|
173
262
|
const delta = update.message.value.text || "";
|
|
174
263
|
if (delta)
|
|
@@ -185,19 +274,24 @@ function handleInteractionUpdate(update, state, onText, onMcpExec, onTurnEnded,
|
|
|
185
274
|
else if (updateCase === "partialToolCall") {
|
|
186
275
|
const partial = update.message.value;
|
|
187
276
|
if (partial.callId && partial.argsTextDelta) {
|
|
188
|
-
state.interactionToolArgsText.
|
|
277
|
+
const existing = state.interactionToolArgsText.get(partial.callId) ?? "";
|
|
278
|
+
state.interactionToolArgsText.set(partial.callId, `${existing}${partial.argsTextDelta}`);
|
|
189
279
|
}
|
|
190
280
|
}
|
|
191
281
|
else if (updateCase === "toolCallCompleted") {
|
|
192
282
|
const exec = decodeInteractionToolCall(update.message.value, state);
|
|
193
|
-
if (exec)
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
283
|
+
if (exec) {
|
|
284
|
+
logPluginInfo("Received Cursor interaction MCP tool call", {
|
|
285
|
+
toolCallId: exec.toolCallId,
|
|
286
|
+
toolName: exec.toolName,
|
|
287
|
+
source: exec.source,
|
|
288
|
+
execId: exec.execId,
|
|
289
|
+
execMsgId: exec.execMsgId,
|
|
290
|
+
cursorCallId: exec.cursorCallId,
|
|
291
|
+
modelCallId: exec.modelCallId,
|
|
292
|
+
decodedArgs: exec.decodedArgs,
|
|
200
293
|
});
|
|
294
|
+
emitPendingExec(exec, state, onMcpExec);
|
|
201
295
|
}
|
|
202
296
|
}
|
|
203
297
|
else if (updateCase === "turnEnded") {
|
|
@@ -221,9 +315,10 @@ function handleInteractionUpdate(update, state, onText, onMcpExec, onTurnEnded,
|
|
|
221
315
|
caseName: updateCase ?? "undefined",
|
|
222
316
|
});
|
|
223
317
|
}
|
|
224
|
-
// toolCallStarted, partialToolCall, toolCallDelta,
|
|
225
|
-
// are
|
|
226
|
-
//
|
|
318
|
+
// toolCallStarted, partialToolCall, toolCallDelta, and non-MCP
|
|
319
|
+
// toolCallCompleted updates are informational only. Actionable MCP tool
|
|
320
|
+
// calls may still appear here on some models, so we surface those, but we
|
|
321
|
+
// do not abort the bridge for native Cursor tool-call progress events.
|
|
227
322
|
}
|
|
228
323
|
function decodeInteractionToolCall(update, state) {
|
|
229
324
|
const callId = update.callId ?? "";
|
|
@@ -234,8 +329,6 @@ function decodeInteractionToolCall(update, state) {
|
|
|
234
329
|
if (!mcpArgs)
|
|
235
330
|
return null;
|
|
236
331
|
const toolCallId = mcpArgs.toolCallId || callId || crypto.randomUUID();
|
|
237
|
-
if (state.emittedToolCallIds.has(toolCallId))
|
|
238
|
-
return null;
|
|
239
332
|
const decodedMap = decodeMcpArgsMap(mcpArgs.args ?? {});
|
|
240
333
|
const partialArgsText = callId
|
|
241
334
|
? state.interactionToolArgsText.get(callId)?.trim()
|
|
@@ -247,7 +340,6 @@ function decodeInteractionToolCall(update, state) {
|
|
|
247
340
|
else if (partialArgsText) {
|
|
248
341
|
decodedArgs = partialArgsText;
|
|
249
342
|
}
|
|
250
|
-
state.emittedToolCallIds.add(toolCallId);
|
|
251
343
|
if (callId)
|
|
252
344
|
state.interactionToolArgsText.delete(callId);
|
|
253
345
|
return {
|
|
@@ -256,8 +348,95 @@ function decodeInteractionToolCall(update, state) {
|
|
|
256
348
|
toolCallId,
|
|
257
349
|
toolName: mcpArgs.toolName || mcpArgs.name || "unknown_mcp_tool",
|
|
258
350
|
decodedArgs,
|
|
351
|
+
source: "interaction",
|
|
352
|
+
cursorCallId: callId || undefined,
|
|
353
|
+
modelCallId: update.modelCallId,
|
|
259
354
|
};
|
|
260
355
|
}
|
|
356
|
+
function handleInteractionQuery(query, sendFrame, onUnsupportedMessage) {
|
|
357
|
+
const queryCase = query.query.case;
|
|
358
|
+
if (queryCase === "webSearchRequestQuery") {
|
|
359
|
+
const response = create(WebSearchRequestResponseSchema, {
|
|
360
|
+
result: {
|
|
361
|
+
case: "rejected",
|
|
362
|
+
value: create(WebSearchRequestResponse_RejectedSchema, {
|
|
363
|
+
reason: "Native Cursor web search is not available in this environment. Use the provided MCP tool `websearch` instead.",
|
|
364
|
+
}),
|
|
365
|
+
},
|
|
366
|
+
});
|
|
367
|
+
sendInteractionResponse(query.id, "webSearchRequestResponse", response, sendFrame);
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
if (queryCase === "askQuestionInteractionQuery") {
|
|
371
|
+
const response = create(AskQuestionInteractionResponseSchema, {
|
|
372
|
+
result: create(AskQuestionResultSchema, {
|
|
373
|
+
result: {
|
|
374
|
+
case: "rejected",
|
|
375
|
+
value: create(AskQuestionRejectedSchema, {
|
|
376
|
+
reason: "Native Cursor question prompts are not available in this environment. Use the provided MCP tool `question` instead.",
|
|
377
|
+
}),
|
|
378
|
+
},
|
|
379
|
+
}),
|
|
380
|
+
});
|
|
381
|
+
sendInteractionResponse(query.id, "askQuestionInteractionResponse", response, sendFrame);
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
if (queryCase === "switchModeRequestQuery") {
|
|
385
|
+
const response = create(SwitchModeRequestResponseSchema, {
|
|
386
|
+
result: {
|
|
387
|
+
case: "rejected",
|
|
388
|
+
value: create(SwitchModeRequestResponse_RejectedSchema, {
|
|
389
|
+
reason: "Cursor mode switching is not available in this environment. Continue using the current agent and the provided MCP tools.",
|
|
390
|
+
}),
|
|
391
|
+
},
|
|
392
|
+
});
|
|
393
|
+
sendInteractionResponse(query.id, "switchModeRequestResponse", response, sendFrame);
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
if (queryCase === "exaSearchRequestQuery") {
|
|
397
|
+
const response = create(ExaSearchRequestResponseSchema, {
|
|
398
|
+
result: {
|
|
399
|
+
case: "rejected",
|
|
400
|
+
value: create(ExaSearchRequestResponse_RejectedSchema, {
|
|
401
|
+
reason: "Native Cursor Exa search is not available in this environment. Use the provided MCP tool `websearch` instead.",
|
|
402
|
+
}),
|
|
403
|
+
},
|
|
404
|
+
});
|
|
405
|
+
sendInteractionResponse(query.id, "exaSearchRequestResponse", response, sendFrame);
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
if (queryCase === "exaFetchRequestQuery") {
|
|
409
|
+
const response = create(ExaFetchRequestResponseSchema, {
|
|
410
|
+
result: {
|
|
411
|
+
case: "rejected",
|
|
412
|
+
value: create(ExaFetchRequestResponse_RejectedSchema, {
|
|
413
|
+
reason: "Native Cursor Exa fetch is not available in this environment. Use the provided MCP tools `websearch` and `webfetch` instead.",
|
|
414
|
+
}),
|
|
415
|
+
},
|
|
416
|
+
});
|
|
417
|
+
sendInteractionResponse(query.id, "exaFetchRequestResponse", response, sendFrame);
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
if (queryCase === "createPlanRequestQuery") {
|
|
421
|
+
const response = create(CreatePlanRequestResponseSchema, {
|
|
422
|
+
result: create(CreatePlanResultSchema, {
|
|
423
|
+
planUri: "",
|
|
424
|
+
result: {
|
|
425
|
+
case: "error",
|
|
426
|
+
value: create(CreatePlanErrorSchema, {
|
|
427
|
+
error: "Native Cursor plan creation is not available in this environment. Use the provided MCP planning tools instead.",
|
|
428
|
+
}),
|
|
429
|
+
},
|
|
430
|
+
}),
|
|
431
|
+
});
|
|
432
|
+
sendInteractionResponse(query.id, "createPlanRequestResponse", response, sendFrame);
|
|
433
|
+
return;
|
|
434
|
+
}
|
|
435
|
+
onUnsupportedMessage?.({
|
|
436
|
+
category: "interactionQuery",
|
|
437
|
+
caseName: queryCase ?? "undefined",
|
|
438
|
+
});
|
|
439
|
+
}
|
|
261
440
|
/** Send a KV client response back to Cursor. */
|
|
262
441
|
function sendKvResponse(kvMsg, messageCase, value, sendFrame) {
|
|
263
442
|
const response = create(KvClientMessageSchema, {
|
|
@@ -269,6 +448,16 @@ function sendKvResponse(kvMsg, messageCase, value, sendFrame) {
|
|
|
269
448
|
});
|
|
270
449
|
sendFrame(toBinary(AgentClientMessageSchema, clientMsg));
|
|
271
450
|
}
|
|
451
|
+
function sendInteractionResponse(queryId, messageCase, value, sendFrame) {
|
|
452
|
+
const response = create(InteractionResponseSchema, {
|
|
453
|
+
id: queryId,
|
|
454
|
+
result: { case: messageCase, value: value },
|
|
455
|
+
});
|
|
456
|
+
const clientMessage = create(AgentClientMessageSchema, {
|
|
457
|
+
message: { case: "interactionResponse", value: response },
|
|
458
|
+
});
|
|
459
|
+
sendFrame(toBinary(AgentClientMessageSchema, clientMessage));
|
|
460
|
+
}
|
|
272
461
|
function handleKvMessage(kvMsg, blobStore, sendFrame) {
|
|
273
462
|
const kvCase = kvMsg.message.case;
|
|
274
463
|
if (kvCase === "getBlobArgs") {
|
|
@@ -289,9 +478,19 @@ function handleKvMessage(kvMsg, blobStore, sendFrame) {
|
|
|
289
478
|
sendKvResponse(kvMsg, "setBlobResult", create(SetBlobResultSchema, {}), sendFrame);
|
|
290
479
|
}
|
|
291
480
|
}
|
|
292
|
-
function handleExecMessage(execMsg, mcpTools, sendFrame, onMcpExec, onUnhandledExec) {
|
|
481
|
+
function handleExecMessage(execMsg, mcpTools, sendFrame, state, onMcpExec, onUnhandledExec) {
|
|
293
482
|
const execCase = execMsg.message.case;
|
|
483
|
+
logPluginInfo("Received Cursor exec message", {
|
|
484
|
+
execCase: execCase ?? "undefined",
|
|
485
|
+
execId: execMsg.execId,
|
|
486
|
+
execMsgId: execMsg.id,
|
|
487
|
+
});
|
|
294
488
|
if (execCase === "requestContextArgs") {
|
|
489
|
+
logPluginInfo("Responding to Cursor requestContextArgs", {
|
|
490
|
+
execId: execMsg.execId,
|
|
491
|
+
execMsgId: execMsg.id,
|
|
492
|
+
mcpToolCount: mcpTools.length,
|
|
493
|
+
});
|
|
295
494
|
const requestContext = create(RequestContextSchema, {
|
|
296
495
|
rules: [],
|
|
297
496
|
repositoryInfo: [],
|
|
@@ -314,13 +513,23 @@ function handleExecMessage(execMsg, mcpTools, sendFrame, onMcpExec, onUnhandledE
|
|
|
314
513
|
if (execCase === "mcpArgs") {
|
|
315
514
|
const mcpArgs = execMsg.message.value;
|
|
316
515
|
const decoded = decodeMcpArgsMap(mcpArgs.args ?? {});
|
|
317
|
-
|
|
516
|
+
const exec = {
|
|
318
517
|
execId: execMsg.execId,
|
|
319
518
|
execMsgId: execMsg.id,
|
|
320
519
|
toolCallId: mcpArgs.toolCallId || crypto.randomUUID(),
|
|
321
520
|
toolName: mcpArgs.toolName || mcpArgs.name,
|
|
322
521
|
decodedArgs: JSON.stringify(decoded),
|
|
522
|
+
source: "exec",
|
|
523
|
+
};
|
|
524
|
+
logPluginInfo("Received Cursor exec MCP tool metadata", {
|
|
525
|
+
toolCallId: exec.toolCallId,
|
|
526
|
+
toolName: exec.toolName,
|
|
527
|
+
source: exec.source,
|
|
528
|
+
execId: exec.execId,
|
|
529
|
+
execMsgId: exec.execMsgId,
|
|
530
|
+
decodedArgs: exec.decodedArgs,
|
|
323
531
|
});
|
|
532
|
+
emitPendingExec(exec, state, onMcpExec);
|
|
324
533
|
return;
|
|
325
534
|
}
|
|
326
535
|
// --- Reject native Cursor tools ---
|
|
@@ -328,6 +537,11 @@ function handleExecMessage(execMsg, mcpTools, sendFrame, onMcpExec, onUnhandledE
|
|
|
328
537
|
// so it falls back to our MCP tools (registered via RequestContext).
|
|
329
538
|
const REJECT_REASON = "Tool not available in this environment. Use the MCP tools provided instead.";
|
|
330
539
|
if (execCase === "readArgs") {
|
|
540
|
+
logPluginInfo("Rejecting native Cursor read tool in favor of MCP", {
|
|
541
|
+
execId: execMsg.execId,
|
|
542
|
+
execMsgId: execMsg.id,
|
|
543
|
+
path: execMsg.message.value.path,
|
|
544
|
+
});
|
|
331
545
|
const args = execMsg.message.value;
|
|
332
546
|
const result = create(ReadResultSchema, {
|
|
333
547
|
result: {
|
|
@@ -342,6 +556,11 @@ function handleExecMessage(execMsg, mcpTools, sendFrame, onMcpExec, onUnhandledE
|
|
|
342
556
|
return;
|
|
343
557
|
}
|
|
344
558
|
if (execCase === "lsArgs") {
|
|
559
|
+
logPluginInfo("Rejecting native Cursor ls tool in favor of MCP", {
|
|
560
|
+
execId: execMsg.execId,
|
|
561
|
+
execMsgId: execMsg.id,
|
|
562
|
+
path: execMsg.message.value.path,
|
|
563
|
+
});
|
|
345
564
|
const args = execMsg.message.value;
|
|
346
565
|
const result = create(LsResultSchema, {
|
|
347
566
|
result: {
|
|
@@ -356,6 +575,10 @@ function handleExecMessage(execMsg, mcpTools, sendFrame, onMcpExec, onUnhandledE
|
|
|
356
575
|
return;
|
|
357
576
|
}
|
|
358
577
|
if (execCase === "grepArgs") {
|
|
578
|
+
logPluginInfo("Rejecting native Cursor grep tool in favor of MCP", {
|
|
579
|
+
execId: execMsg.execId,
|
|
580
|
+
execMsgId: execMsg.id,
|
|
581
|
+
});
|
|
359
582
|
const result = create(GrepResultSchema, {
|
|
360
583
|
result: {
|
|
361
584
|
case: "error",
|
|
@@ -366,6 +589,11 @@ function handleExecMessage(execMsg, mcpTools, sendFrame, onMcpExec, onUnhandledE
|
|
|
366
589
|
return;
|
|
367
590
|
}
|
|
368
591
|
if (execCase === "writeArgs") {
|
|
592
|
+
logPluginInfo("Rejecting native Cursor write tool in favor of MCP", {
|
|
593
|
+
execId: execMsg.execId,
|
|
594
|
+
execMsgId: execMsg.id,
|
|
595
|
+
path: execMsg.message.value.path,
|
|
596
|
+
});
|
|
369
597
|
const args = execMsg.message.value;
|
|
370
598
|
const result = create(WriteResultSchema, {
|
|
371
599
|
result: {
|
|
@@ -380,6 +608,11 @@ function handleExecMessage(execMsg, mcpTools, sendFrame, onMcpExec, onUnhandledE
|
|
|
380
608
|
return;
|
|
381
609
|
}
|
|
382
610
|
if (execCase === "deleteArgs") {
|
|
611
|
+
logPluginInfo("Rejecting native Cursor delete tool in favor of MCP", {
|
|
612
|
+
execId: execMsg.execId,
|
|
613
|
+
execMsgId: execMsg.id,
|
|
614
|
+
path: execMsg.message.value.path,
|
|
615
|
+
});
|
|
383
616
|
const args = execMsg.message.value;
|
|
384
617
|
const result = create(DeleteResultSchema, {
|
|
385
618
|
result: {
|
|
@@ -394,6 +627,13 @@ function handleExecMessage(execMsg, mcpTools, sendFrame, onMcpExec, onUnhandledE
|
|
|
394
627
|
return;
|
|
395
628
|
}
|
|
396
629
|
if (execCase === "shellArgs" || execCase === "shellStreamArgs") {
|
|
630
|
+
logPluginInfo("Rejecting native Cursor shell tool in favor of MCP", {
|
|
631
|
+
execId: execMsg.execId,
|
|
632
|
+
execMsgId: execMsg.id,
|
|
633
|
+
command: execMsg.message.value.command ?? "",
|
|
634
|
+
workingDirectory: execMsg.message.value.workingDirectory ?? "",
|
|
635
|
+
execCase,
|
|
636
|
+
});
|
|
397
637
|
const args = execMsg.message.value;
|
|
398
638
|
const result = create(ShellResultSchema, {
|
|
399
639
|
result: {
|
|
@@ -410,6 +650,12 @@ function handleExecMessage(execMsg, mcpTools, sendFrame, onMcpExec, onUnhandledE
|
|
|
410
650
|
return;
|
|
411
651
|
}
|
|
412
652
|
if (execCase === "backgroundShellSpawnArgs") {
|
|
653
|
+
logPluginInfo("Rejecting native Cursor background shell tool in favor of MCP", {
|
|
654
|
+
execId: execMsg.execId,
|
|
655
|
+
execMsgId: execMsg.id,
|
|
656
|
+
command: execMsg.message.value.command ?? "",
|
|
657
|
+
workingDirectory: execMsg.message.value.workingDirectory ?? "",
|
|
658
|
+
});
|
|
413
659
|
const args = execMsg.message.value;
|
|
414
660
|
const result = create(BackgroundShellSpawnResultSchema, {
|
|
415
661
|
result: {
|
|
@@ -426,6 +672,10 @@ function handleExecMessage(execMsg, mcpTools, sendFrame, onMcpExec, onUnhandledE
|
|
|
426
672
|
return;
|
|
427
673
|
}
|
|
428
674
|
if (execCase === "writeShellStdinArgs") {
|
|
675
|
+
logPluginInfo("Rejecting native Cursor shell stdin tool in favor of MCP", {
|
|
676
|
+
execId: execMsg.execId,
|
|
677
|
+
execMsgId: execMsg.id,
|
|
678
|
+
});
|
|
429
679
|
const result = create(WriteShellStdinResultSchema, {
|
|
430
680
|
result: {
|
|
431
681
|
case: "error",
|
|
@@ -436,6 +686,11 @@ function handleExecMessage(execMsg, mcpTools, sendFrame, onMcpExec, onUnhandledE
|
|
|
436
686
|
return;
|
|
437
687
|
}
|
|
438
688
|
if (execCase === "fetchArgs") {
|
|
689
|
+
logPluginInfo("Rejecting native Cursor fetch tool in favor of MCP", {
|
|
690
|
+
execId: execMsg.execId,
|
|
691
|
+
execMsgId: execMsg.id,
|
|
692
|
+
url: execMsg.message.value.url,
|
|
693
|
+
});
|
|
439
694
|
const args = execMsg.message.value;
|
|
440
695
|
const result = create(FetchResultSchema, {
|
|
441
696
|
result: {
|
|
@@ -450,6 +705,11 @@ function handleExecMessage(execMsg, mcpTools, sendFrame, onMcpExec, onUnhandledE
|
|
|
450
705
|
return;
|
|
451
706
|
}
|
|
452
707
|
if (execCase === "diagnosticsArgs") {
|
|
708
|
+
logPluginInfo("Rejecting native Cursor diagnostics tool in favor of MCP", {
|
|
709
|
+
execId: execMsg.execId,
|
|
710
|
+
execMsgId: execMsg.id,
|
|
711
|
+
path: execMsg.message.value.path,
|
|
712
|
+
});
|
|
453
713
|
const result = create(DiagnosticsResultSchema, {});
|
|
454
714
|
sendExecResult(execMsg, "diagnosticsResult", result, sendFrame);
|
|
455
715
|
return;
|
|
@@ -463,6 +723,12 @@ function handleExecMessage(execMsg, mcpTools, sendFrame, onMcpExec, onUnhandledE
|
|
|
463
723
|
};
|
|
464
724
|
const resultCase = miscCaseMap[execCase];
|
|
465
725
|
if (resultCase) {
|
|
726
|
+
logPluginInfo("Responding to miscellaneous Cursor exec message", {
|
|
727
|
+
execCase,
|
|
728
|
+
execId: execMsg.execId,
|
|
729
|
+
execMsgId: execMsg.id,
|
|
730
|
+
resultCase,
|
|
731
|
+
});
|
|
466
732
|
sendExecResult(execMsg, resultCase, create(McpResultSchema, {}), sendFrame);
|
|
467
733
|
return;
|
|
468
734
|
}
|
package/dist/proxy/types.d.ts
CHANGED
|
@@ -14,6 +14,9 @@ export interface PendingExec {
|
|
|
14
14
|
toolName: string;
|
|
15
15
|
/** Decoded arguments JSON string for SSE tool_calls emission. */
|
|
16
16
|
decodedArgs: string;
|
|
17
|
+
source?: "interaction" | "exec";
|
|
18
|
+
cursorCallId?: string;
|
|
19
|
+
modelCallId?: string;
|
|
17
20
|
}
|
|
18
21
|
/** A live Cursor session kept alive across requests for tool result continuation. */
|
|
19
22
|
export interface ActiveBridge {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@playwo/opencode-cursor-oauth",
|
|
3
|
-
"version": "0.0.0-dev.
|
|
3
|
+
"version": "0.0.0-dev.7fe465ca080f",
|
|
4
4
|
"description": "OpenCode plugin that connects Cursor's API to OpenCode via OAuth, model discovery, and a local OpenAI-compatible proxy.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -19,7 +19,6 @@
|
|
|
19
19
|
],
|
|
20
20
|
"scripts": {
|
|
21
21
|
"build": "tsc -p tsconfig.json",
|
|
22
|
-
"test": "bun test/smoke.ts",
|
|
23
22
|
"prepublishOnly": "npm run build"
|
|
24
23
|
},
|
|
25
24
|
"repository": {
|