@playwo/opencode-cursor-oauth 0.0.0-dev.67ecd4697583 → 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.
@@ -212,8 +212,22 @@ function createBridgeStreamResponse(bridge, heartbeatTimer, blobStore, mcpTools,
212
212
  stopKeepalive();
213
213
  }
214
214
  }, SSE_KEEPALIVE_INTERVAL_MS);
215
+ logPluginInfo("Opened Cursor streaming bridge", {
216
+ modelId,
217
+ bridgeKey,
218
+ convKey,
219
+ mcpToolCount: mcpTools.length,
220
+ });
215
221
  bridge.onData(processChunk);
216
222
  bridge.onClose((code) => {
223
+ logPluginInfo("Cursor streaming bridge closed", {
224
+ modelId,
225
+ bridgeKey,
226
+ convKey,
227
+ code,
228
+ mcpExecReceived,
229
+ hadEndStreamError: Boolean(endStreamError),
230
+ });
217
231
  clearInterval(heartbeatTimer);
218
232
  stopKeepalive();
219
233
  syncStoredBlobStore(convKey, blobStore);
@@ -263,6 +277,12 @@ function createBridgeStreamResponse(bridge, heartbeatTimer, blobStore, mcpTools,
263
277
  return new Response(stream, { headers: SSE_HEADERS });
264
278
  }
265
279
  export async function handleStreamingResponse(payload, accessToken, modelId, bridgeKey, convKey, metadata) {
280
+ logPluginInfo("Starting Cursor streaming response", {
281
+ modelId,
282
+ bridgeKey,
283
+ convKey,
284
+ mcpToolCount: payload.mcpTools.length,
285
+ });
266
286
  const { bridge, heartbeatTimer } = await startBridge(accessToken, payload.requestBytes);
267
287
  return createBridgeStreamResponse(bridge, heartbeatTimer, payload.blobStore, payload.mcpTools, modelId, bridgeKey, convKey, metadata);
268
288
  }
@@ -10,6 +10,19 @@ export function handleChatCompletion(body, accessToken, context = {}) {
10
10
  const { systemPrompt, userText, turns, toolResults, pendingAssistantSummary, completedTurnsFingerprint, } = parsed;
11
11
  const modelId = body.model;
12
12
  const normalizedAgentKey = normalizeAgentKey(context.agentKey);
13
+ logPluginInfo("Handling Cursor chat completion request", {
14
+ modelId,
15
+ stream: body.stream !== false,
16
+ messageCount: body.messages.length,
17
+ toolCount: body.tools?.length ?? 0,
18
+ toolChoice: body.tool_choice,
19
+ sessionId: context.sessionId,
20
+ agentKey: normalizedAgentKey,
21
+ parsedUserText: userText,
22
+ parsedToolResults: toolResults,
23
+ hasPendingAssistantSummary: pendingAssistantSummary.trim().length > 0,
24
+ turnCount: turns.length,
25
+ });
13
26
  const titleDetection = detectTitleRequest(body);
14
27
  const isTitleAgent = titleDetection.matched;
15
28
  if (isTitleAgent) {
@@ -38,6 +51,14 @@ export function handleChatCompletion(body, accessToken, context = {}) {
38
51
  const bridgeKey = deriveBridgeKey(modelId, body.messages, context.sessionId, context.agentKey);
39
52
  const convKey = deriveConversationKey(body.messages, context.sessionId, context.agentKey);
40
53
  const activeBridge = activeBridges.get(bridgeKey);
54
+ logPluginInfo("Resolved Cursor conversation keys", {
55
+ modelId,
56
+ bridgeKey,
57
+ convKey,
58
+ hasActiveBridge: Boolean(activeBridge),
59
+ sessionId: context.sessionId,
60
+ agentKey: normalizedAgentKey,
61
+ });
41
62
  if (activeBridge && toolResults.length > 0) {
42
63
  logPluginInfo("Matched OpenAI tool results to active Cursor bridge", {
43
64
  bridgeKey,
@@ -101,6 +122,16 @@ export function handleChatCompletion(body, accessToken, context = {}) {
101
122
  : userText;
102
123
  const payload = buildCursorRequest(modelId, systemPrompt, effectiveUserText, replayTurns, stored.conversationId, stored.checkpoint, stored.blobStore);
103
124
  payload.mcpTools = mcpTools;
125
+ logPluginInfo("Built Cursor run request payload", {
126
+ modelId,
127
+ bridgeKey,
128
+ convKey,
129
+ mcpToolCount: mcpTools.length,
130
+ conversationId: stored.conversationId,
131
+ hasCheckpoint: Boolean(stored.checkpoint),
132
+ replayTurnCount: replayTurns.length,
133
+ effectiveUserText,
134
+ });
104
135
  if (body.stream === false) {
105
136
  return handleNonStreamingResponse(payload, accessToken, modelId, convKey, {
106
137
  systemPrompt,
@@ -207,6 +207,11 @@ function emitPendingExec(exec, state, onMcpExec) {
207
207
  }
208
208
  export function processServerMessage(msg, blobStore, mcpTools, sendFrame, state, onText, onMcpExec, onCheckpoint, onTurnEnded, onUnsupportedMessage, onUnhandledExec) {
209
209
  const msgCase = msg.message.case;
210
+ if (msgCase !== "conversationCheckpointUpdate") {
211
+ logPluginInfo("Received Cursor server message", {
212
+ messageCase: msgCase ?? "undefined",
213
+ });
214
+ }
210
215
  if (msgCase === "interactionUpdate") {
211
216
  handleInteractionUpdate(msg.message.value, state, onText, onMcpExec, onTurnEnded, onUnsupportedMessage);
212
217
  }
@@ -243,6 +248,16 @@ export function processServerMessage(msg, blobStore, mcpTools, sendFrame, state,
243
248
  }
244
249
  function handleInteractionUpdate(update, state, onText, onMcpExec, onTurnEnded, onUnsupportedMessage) {
245
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
+ }
246
261
  if (updateCase === "textDelta") {
247
262
  const delta = update.message.value.text || "";
248
263
  if (delta)
@@ -465,7 +480,17 @@ function handleKvMessage(kvMsg, blobStore, sendFrame) {
465
480
  }
466
481
  function handleExecMessage(execMsg, mcpTools, sendFrame, state, onMcpExec, onUnhandledExec) {
467
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
+ });
468
488
  if (execCase === "requestContextArgs") {
489
+ logPluginInfo("Responding to Cursor requestContextArgs", {
490
+ execId: execMsg.execId,
491
+ execMsgId: execMsg.id,
492
+ mcpToolCount: mcpTools.length,
493
+ });
469
494
  const requestContext = create(RequestContextSchema, {
470
495
  rules: [],
471
496
  repositoryInfo: [],
@@ -512,6 +537,11 @@ function handleExecMessage(execMsg, mcpTools, sendFrame, state, onMcpExec, onUnh
512
537
  // so it falls back to our MCP tools (registered via RequestContext).
513
538
  const REJECT_REASON = "Tool not available in this environment. Use the MCP tools provided instead.";
514
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
+ });
515
545
  const args = execMsg.message.value;
516
546
  const result = create(ReadResultSchema, {
517
547
  result: {
@@ -526,6 +556,11 @@ function handleExecMessage(execMsg, mcpTools, sendFrame, state, onMcpExec, onUnh
526
556
  return;
527
557
  }
528
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
+ });
529
564
  const args = execMsg.message.value;
530
565
  const result = create(LsResultSchema, {
531
566
  result: {
@@ -540,6 +575,10 @@ function handleExecMessage(execMsg, mcpTools, sendFrame, state, onMcpExec, onUnh
540
575
  return;
541
576
  }
542
577
  if (execCase === "grepArgs") {
578
+ logPluginInfo("Rejecting native Cursor grep tool in favor of MCP", {
579
+ execId: execMsg.execId,
580
+ execMsgId: execMsg.id,
581
+ });
543
582
  const result = create(GrepResultSchema, {
544
583
  result: {
545
584
  case: "error",
@@ -550,6 +589,11 @@ function handleExecMessage(execMsg, mcpTools, sendFrame, state, onMcpExec, onUnh
550
589
  return;
551
590
  }
552
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
+ });
553
597
  const args = execMsg.message.value;
554
598
  const result = create(WriteResultSchema, {
555
599
  result: {
@@ -564,6 +608,11 @@ function handleExecMessage(execMsg, mcpTools, sendFrame, state, onMcpExec, onUnh
564
608
  return;
565
609
  }
566
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
+ });
567
616
  const args = execMsg.message.value;
568
617
  const result = create(DeleteResultSchema, {
569
618
  result: {
@@ -578,6 +627,13 @@ function handleExecMessage(execMsg, mcpTools, sendFrame, state, onMcpExec, onUnh
578
627
  return;
579
628
  }
580
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
+ });
581
637
  const args = execMsg.message.value;
582
638
  const result = create(ShellResultSchema, {
583
639
  result: {
@@ -594,6 +650,12 @@ function handleExecMessage(execMsg, mcpTools, sendFrame, state, onMcpExec, onUnh
594
650
  return;
595
651
  }
596
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
+ });
597
659
  const args = execMsg.message.value;
598
660
  const result = create(BackgroundShellSpawnResultSchema, {
599
661
  result: {
@@ -610,6 +672,10 @@ function handleExecMessage(execMsg, mcpTools, sendFrame, state, onMcpExec, onUnh
610
672
  return;
611
673
  }
612
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
+ });
613
679
  const result = create(WriteShellStdinResultSchema, {
614
680
  result: {
615
681
  case: "error",
@@ -620,6 +686,11 @@ function handleExecMessage(execMsg, mcpTools, sendFrame, state, onMcpExec, onUnh
620
686
  return;
621
687
  }
622
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
+ });
623
694
  const args = execMsg.message.value;
624
695
  const result = create(FetchResultSchema, {
625
696
  result: {
@@ -634,6 +705,11 @@ function handleExecMessage(execMsg, mcpTools, sendFrame, state, onMcpExec, onUnh
634
705
  return;
635
706
  }
636
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
+ });
637
713
  const result = create(DiagnosticsResultSchema, {});
638
714
  sendExecResult(execMsg, "diagnosticsResult", result, sendFrame);
639
715
  return;
@@ -647,6 +723,12 @@ function handleExecMessage(execMsg, mcpTools, sendFrame, state, onMcpExec, onUnh
647
723
  };
648
724
  const resultCase = miscCaseMap[execCase];
649
725
  if (resultCase) {
726
+ logPluginInfo("Responding to miscellaneous Cursor exec message", {
727
+ execCase,
728
+ execId: execMsg.execId,
729
+ execMsgId: execMsg.id,
730
+ resultCase,
731
+ });
650
732
  sendExecResult(execMsg, resultCase, create(McpResultSchema, {}), sendFrame);
651
733
  return;
652
734
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@playwo/opencode-cursor-oauth",
3
- "version": "0.0.0-dev.67ecd4697583",
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": {