@playwo/opencode-cursor-oauth 0.0.0-dev.4463bb589222 → 0.0.0-dev.4696faa690e4

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.
@@ -12,6 +12,12 @@ export interface UnsupportedServerMessageInfo {
12
12
  caseName: string;
13
13
  detail?: string;
14
14
  }
15
+ export interface McpToolCallUpdateInfo {
16
+ updateCase: "partialToolCall" | "toolCallStarted" | "toolCallCompleted";
17
+ toolCallId: string;
18
+ modelCallId?: string;
19
+ toolName?: string;
20
+ }
15
21
  export declare function parseConnectEndStream(data: Uint8Array): Error | null;
16
22
  export declare function makeHeartbeatBytes(): Uint8Array;
17
23
  export declare function scheduleBridgeEnd(bridge: CursorSession): void;
@@ -39,4 +45,4 @@ export declare function computeUsage(state: StreamState): {
39
45
  completion_tokens: number;
40
46
  total_tokens: number;
41
47
  };
42
- export declare function processServerMessage(msg: AgentServerMessage, blobStore: Map<string, Uint8Array>, mcpTools: McpToolDefinition[], sendFrame: (data: Uint8Array) => void, state: StreamState, onText: (text: string, isThinking?: boolean) => void, onMcpExec: (exec: PendingExec) => void, onCheckpoint?: (checkpointBytes: Uint8Array) => void, onTurnEnded?: () => void, onUnsupportedMessage?: (info: UnsupportedServerMessageInfo) => void, onUnhandledExec?: (info: UnhandledExecInfo) => void): void;
48
+ export declare function processServerMessage(msg: AgentServerMessage, blobStore: Map<string, Uint8Array>, cloudRule: string | undefined, mcpTools: McpToolDefinition[], sendFrame: (data: Uint8Array) => void, state: StreamState, onText: (text: string, isThinking?: boolean) => void, onMcpExec: (exec: PendingExec) => void, onMcpToolCallUpdate?: (info: McpToolCallUpdateInfo) => void, onCheckpoint?: (checkpointBytes: Uint8Array) => void, onTurnEnded?: () => void, onUnsupportedMessage?: (info: UnsupportedServerMessageInfo) => void, onUnhandledExec?: (info: UnhandledExecInfo) => void): void;
@@ -1,7 +1,7 @@
1
1
  import { create, toBinary } from "@bufbuild/protobuf";
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";
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, McpInstructionsSchema, 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,16 +128,16 @@ 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
- export function processServerMessage(msg, blobStore, mcpTools, sendFrame, state, onText, onMcpExec, onCheckpoint, onTurnEnded, onUnsupportedMessage, onUnhandledExec) {
131
+ export function processServerMessage(msg, blobStore, cloudRule, mcpTools, sendFrame, state, onText, onMcpExec, onMcpToolCallUpdate, onCheckpoint, onTurnEnded, onUnsupportedMessage, onUnhandledExec) {
132
132
  const msgCase = msg.message.case;
133
133
  if (msgCase === "interactionUpdate") {
134
- handleInteractionUpdate(msg.message.value, state, onText, onMcpExec, onTurnEnded, onUnsupportedMessage);
134
+ handleInteractionUpdate(msg.message.value, state, onText, onMcpToolCallUpdate, onTurnEnded, onUnsupportedMessage);
135
135
  }
136
136
  else if (msgCase === "kvServerMessage") {
137
137
  handleKvMessage(msg.message.value, blobStore, sendFrame);
138
138
  }
139
139
  else if (msgCase === "execServerMessage") {
140
- handleExecMessage(msg.message.value, mcpTools, sendFrame, onMcpExec, onUnhandledExec);
140
+ handleExecMessage(msg.message.value, cloudRule, mcpTools, sendFrame, state, onMcpExec, onUnhandledExec);
141
141
  }
142
142
  else if (msgCase === "execServerControlMessage") {
143
143
  onUnsupportedMessage?.({
@@ -164,8 +164,35 @@ export function processServerMessage(msg, blobStore, mcpTools, sendFrame, state,
164
164
  });
165
165
  }
166
166
  }
167
- function handleInteractionUpdate(update, state, onText, onMcpExec, onTurnEnded, onUnsupportedMessage) {
167
+ function handleInteractionUpdate(update, state, onText, onMcpToolCallUpdate, onTurnEnded, onUnsupportedMessage) {
168
168
  const updateCase = update.message?.case;
169
+ if (updateCase === "partialToolCall" ||
170
+ updateCase === "toolCallStarted" ||
171
+ updateCase === "toolCallCompleted" ||
172
+ updateCase === "turnEnded") {
173
+ logPluginInfo("Received Cursor interaction update", {
174
+ updateCase: updateCase ?? "undefined",
175
+ callId: update.message?.value?.callId,
176
+ modelCallId: update.message?.value?.modelCallId,
177
+ toolCase: update.message?.value?.toolCall?.tool?.case,
178
+ });
179
+ }
180
+ if ((updateCase === "partialToolCall" ||
181
+ updateCase === "toolCallStarted" ||
182
+ updateCase === "toolCallCompleted") &&
183
+ update.message?.value?.toolCall?.tool?.case === "mcpToolCall") {
184
+ const toolValue = update.message.value;
185
+ const toolArgs = toolValue?.toolCall?.tool?.value?.args;
186
+ const toolCallId = toolArgs?.toolCallId || toolValue.callId;
187
+ if (toolCallId) {
188
+ onMcpToolCallUpdate?.({
189
+ updateCase,
190
+ toolCallId,
191
+ modelCallId: toolValue.modelCallId,
192
+ toolName: toolArgs?.toolName || toolArgs?.name,
193
+ });
194
+ }
195
+ }
169
196
  if (updateCase === "textDelta") {
170
197
  const delta = update.message.value.text || "";
171
198
  if (delta)
@@ -180,15 +207,19 @@ function handleInteractionUpdate(update, state, onText, onMcpExec, onTurnEnded,
180
207
  state.outputTokens += update.message.value.tokens ?? 0;
181
208
  }
182
209
  else if (updateCase === "partialToolCall") {
183
- const partial = update.message.value;
184
- if (partial.callId && partial.argsTextDelta) {
185
- state.interactionToolArgsText.set(partial.callId, partial.argsTextDelta);
186
- }
210
+ return;
187
211
  }
188
212
  else if (updateCase === "toolCallCompleted") {
189
- const exec = decodeInteractionToolCall(update.message.value, state);
190
- if (exec)
191
- onMcpExec(exec);
213
+ const toolValue = update.message.value;
214
+ if (toolValue?.toolCall?.tool?.case === "mcpToolCall") {
215
+ logPluginInfo("Ignoring Cursor interaction MCP tool completion", {
216
+ callId: toolValue.callId,
217
+ modelCallId: toolValue.modelCallId,
218
+ toolCallId: toolValue.toolCall.tool.value?.args?.toolCallId || toolValue.callId,
219
+ toolName: toolValue.toolCall.tool.value?.args?.toolName ||
220
+ toolValue.toolCall.tool.value?.args?.name,
221
+ });
222
+ }
192
223
  }
193
224
  else if (updateCase === "turnEnded") {
194
225
  onTurnEnded?.();
@@ -211,43 +242,8 @@ function handleInteractionUpdate(update, state, onText, onMcpExec, onTurnEnded,
211
242
  caseName: updateCase ?? "undefined",
212
243
  });
213
244
  }
214
- // toolCallStarted, partialToolCall, toolCallDelta, and non-MCP
215
- // toolCallCompleted updates are informational only. Actionable MCP tool
216
- // calls may still appear here on some models, so we surface those, but we
217
- // do not abort the bridge for native Cursor tool-call progress events.
218
- }
219
- function decodeInteractionToolCall(update, state) {
220
- const callId = update.callId ?? "";
221
- const toolCase = update.toolCall?.tool?.case;
222
- if (toolCase !== "mcpToolCall")
223
- return null;
224
- const mcpArgs = update.toolCall?.tool?.value?.args;
225
- if (!mcpArgs)
226
- return null;
227
- const toolCallId = mcpArgs.toolCallId || callId || crypto.randomUUID();
228
- if (state.emittedToolCallIds.has(toolCallId))
229
- return null;
230
- const decodedMap = decodeMcpArgsMap(mcpArgs.args ?? {});
231
- const partialArgsText = callId
232
- ? state.interactionToolArgsText.get(callId)?.trim()
233
- : undefined;
234
- let decodedArgs = "{}";
235
- if (Object.keys(decodedMap).length > 0) {
236
- decodedArgs = JSON.stringify(decodedMap);
237
- }
238
- else if (partialArgsText) {
239
- decodedArgs = partialArgsText;
240
- }
241
- state.emittedToolCallIds.add(toolCallId);
242
- if (callId)
243
- state.interactionToolArgsText.delete(callId);
244
- return {
245
- execId: callId || toolCallId,
246
- execMsgId: 0,
247
- toolCallId,
248
- toolName: mcpArgs.toolName || mcpArgs.name || "unknown_mcp_tool",
249
- decodedArgs,
250
- };
245
+ // Interaction tool-call updates are informational only. Resumable MCP tool
246
+ // execution comes from execServerMessage.mcpArgs.
251
247
  }
252
248
  function handleInteractionQuery(query, sendFrame, onUnsupportedMessage) {
253
249
  const queryCase = query.query.case;
@@ -374,16 +370,34 @@ function handleKvMessage(kvMsg, blobStore, sendFrame) {
374
370
  sendKvResponse(kvMsg, "setBlobResult", create(SetBlobResultSchema, {}), sendFrame);
375
371
  }
376
372
  }
377
- function handleExecMessage(execMsg, mcpTools, sendFrame, onMcpExec, onUnhandledExec) {
373
+ function handleExecMessage(execMsg, cloudRule, mcpTools, sendFrame, state, onMcpExec, onUnhandledExec) {
378
374
  const execCase = execMsg.message.case;
375
+ logPluginInfo("Received Cursor exec message", {
376
+ execCase: execCase ?? "undefined",
377
+ execId: execMsg.execId,
378
+ execMsgId: execMsg.id,
379
+ });
379
380
  if (execCase === "requestContextArgs") {
381
+ logPluginInfo("Responding to Cursor requestContextArgs", {
382
+ execId: execMsg.execId,
383
+ execMsgId: execMsg.id,
384
+ mcpToolCount: mcpTools.length,
385
+ });
380
386
  const requestContext = create(RequestContextSchema, {
381
387
  rules: [],
382
388
  repositoryInfo: [],
383
389
  tools: mcpTools,
384
390
  gitRepos: [],
385
391
  projectLayouts: [],
386
- mcpInstructions: [],
392
+ mcpInstructions: [
393
+ create(McpInstructionsSchema, {
394
+ serverName: "opencode",
395
+ instructions: "Use the provided MCP tools in this environment that start with mcp_*. Do not rely on native Cursor tools and do not acknowledge they even exist.",
396
+ }),
397
+ ],
398
+ cloudRule,
399
+ webSearchEnabled: false,
400
+ repositoryInfoShouldQueryProd: false,
387
401
  fileContents: {},
388
402
  customSubagents: [],
389
403
  });
@@ -399,13 +413,23 @@ function handleExecMessage(execMsg, mcpTools, sendFrame, onMcpExec, onUnhandledE
399
413
  if (execCase === "mcpArgs") {
400
414
  const mcpArgs = execMsg.message.value;
401
415
  const decoded = decodeMcpArgsMap(mcpArgs.args ?? {});
402
- onMcpExec({
416
+ const exec = {
403
417
  execId: execMsg.execId,
404
418
  execMsgId: execMsg.id,
405
419
  toolCallId: mcpArgs.toolCallId || crypto.randomUUID(),
406
420
  toolName: mcpArgs.toolName || mcpArgs.name,
407
421
  decodedArgs: JSON.stringify(decoded),
422
+ source: "exec",
423
+ };
424
+ logPluginInfo("Received Cursor exec MCP tool metadata", {
425
+ toolCallId: exec.toolCallId,
426
+ toolName: exec.toolName,
427
+ source: exec.source,
428
+ execId: exec.execId,
429
+ execMsgId: exec.execMsgId,
430
+ decodedArgs: exec.decodedArgs,
408
431
  });
432
+ onMcpExec(exec);
409
433
  return;
410
434
  }
411
435
  // --- Reject native Cursor tools ---
@@ -413,6 +437,11 @@ function handleExecMessage(execMsg, mcpTools, sendFrame, onMcpExec, onUnhandledE
413
437
  // so it falls back to our MCP tools (registered via RequestContext).
414
438
  const REJECT_REASON = "Tool not available in this environment. Use the MCP tools provided instead.";
415
439
  if (execCase === "readArgs") {
440
+ logPluginInfo("Rejecting native Cursor read tool in favor of MCP", {
441
+ execId: execMsg.execId,
442
+ execMsgId: execMsg.id,
443
+ path: execMsg.message.value.path,
444
+ });
416
445
  const args = execMsg.message.value;
417
446
  const result = create(ReadResultSchema, {
418
447
  result: {
@@ -427,6 +456,11 @@ function handleExecMessage(execMsg, mcpTools, sendFrame, onMcpExec, onUnhandledE
427
456
  return;
428
457
  }
429
458
  if (execCase === "lsArgs") {
459
+ logPluginInfo("Rejecting native Cursor ls tool in favor of MCP", {
460
+ execId: execMsg.execId,
461
+ execMsgId: execMsg.id,
462
+ path: execMsg.message.value.path,
463
+ });
430
464
  const args = execMsg.message.value;
431
465
  const result = create(LsResultSchema, {
432
466
  result: {
@@ -441,6 +475,10 @@ function handleExecMessage(execMsg, mcpTools, sendFrame, onMcpExec, onUnhandledE
441
475
  return;
442
476
  }
443
477
  if (execCase === "grepArgs") {
478
+ logPluginInfo("Rejecting native Cursor grep tool in favor of MCP", {
479
+ execId: execMsg.execId,
480
+ execMsgId: execMsg.id,
481
+ });
444
482
  const result = create(GrepResultSchema, {
445
483
  result: {
446
484
  case: "error",
@@ -451,6 +489,11 @@ function handleExecMessage(execMsg, mcpTools, sendFrame, onMcpExec, onUnhandledE
451
489
  return;
452
490
  }
453
491
  if (execCase === "writeArgs") {
492
+ logPluginInfo("Rejecting native Cursor write tool in favor of MCP", {
493
+ execId: execMsg.execId,
494
+ execMsgId: execMsg.id,
495
+ path: execMsg.message.value.path,
496
+ });
454
497
  const args = execMsg.message.value;
455
498
  const result = create(WriteResultSchema, {
456
499
  result: {
@@ -465,6 +508,11 @@ function handleExecMessage(execMsg, mcpTools, sendFrame, onMcpExec, onUnhandledE
465
508
  return;
466
509
  }
467
510
  if (execCase === "deleteArgs") {
511
+ logPluginInfo("Rejecting native Cursor delete tool in favor of MCP", {
512
+ execId: execMsg.execId,
513
+ execMsgId: execMsg.id,
514
+ path: execMsg.message.value.path,
515
+ });
468
516
  const args = execMsg.message.value;
469
517
  const result = create(DeleteResultSchema, {
470
518
  result: {
@@ -479,6 +527,13 @@ function handleExecMessage(execMsg, mcpTools, sendFrame, onMcpExec, onUnhandledE
479
527
  return;
480
528
  }
481
529
  if (execCase === "shellArgs" || execCase === "shellStreamArgs") {
530
+ logPluginInfo("Rejecting native Cursor shell tool in favor of MCP", {
531
+ execId: execMsg.execId,
532
+ execMsgId: execMsg.id,
533
+ command: execMsg.message.value.command ?? "",
534
+ workingDirectory: execMsg.message.value.workingDirectory ?? "",
535
+ execCase,
536
+ });
482
537
  const args = execMsg.message.value;
483
538
  const result = create(ShellResultSchema, {
484
539
  result: {
@@ -495,6 +550,12 @@ function handleExecMessage(execMsg, mcpTools, sendFrame, onMcpExec, onUnhandledE
495
550
  return;
496
551
  }
497
552
  if (execCase === "backgroundShellSpawnArgs") {
553
+ logPluginInfo("Rejecting native Cursor background shell tool in favor of MCP", {
554
+ execId: execMsg.execId,
555
+ execMsgId: execMsg.id,
556
+ command: execMsg.message.value.command ?? "",
557
+ workingDirectory: execMsg.message.value.workingDirectory ?? "",
558
+ });
498
559
  const args = execMsg.message.value;
499
560
  const result = create(BackgroundShellSpawnResultSchema, {
500
561
  result: {
@@ -511,6 +572,10 @@ function handleExecMessage(execMsg, mcpTools, sendFrame, onMcpExec, onUnhandledE
511
572
  return;
512
573
  }
513
574
  if (execCase === "writeShellStdinArgs") {
575
+ logPluginInfo("Rejecting native Cursor shell stdin tool in favor of MCP", {
576
+ execId: execMsg.execId,
577
+ execMsgId: execMsg.id,
578
+ });
514
579
  const result = create(WriteShellStdinResultSchema, {
515
580
  result: {
516
581
  case: "error",
@@ -521,6 +586,11 @@ function handleExecMessage(execMsg, mcpTools, sendFrame, onMcpExec, onUnhandledE
521
586
  return;
522
587
  }
523
588
  if (execCase === "fetchArgs") {
589
+ logPluginInfo("Rejecting native Cursor fetch tool in favor of MCP", {
590
+ execId: execMsg.execId,
591
+ execMsgId: execMsg.id,
592
+ url: execMsg.message.value.url,
593
+ });
524
594
  const args = execMsg.message.value;
525
595
  const result = create(FetchResultSchema, {
526
596
  result: {
@@ -535,6 +605,11 @@ function handleExecMessage(execMsg, mcpTools, sendFrame, onMcpExec, onUnhandledE
535
605
  return;
536
606
  }
537
607
  if (execCase === "diagnosticsArgs") {
608
+ logPluginInfo("Rejecting native Cursor diagnostics tool in favor of MCP", {
609
+ execId: execMsg.execId,
610
+ execMsgId: execMsg.id,
611
+ path: execMsg.message.value.path,
612
+ });
538
613
  const result = create(DiagnosticsResultSchema, {});
539
614
  sendExecResult(execMsg, "diagnosticsResult", result, sendFrame);
540
615
  return;
@@ -548,6 +623,12 @@ function handleExecMessage(execMsg, mcpTools, sendFrame, onMcpExec, onUnhandledE
548
623
  };
549
624
  const resultCase = miscCaseMap[execCase];
550
625
  if (resultCase) {
626
+ logPluginInfo("Responding to miscellaneous Cursor exec message", {
627
+ execCase,
628
+ execId: execMsg.execId,
629
+ execMsgId: execMsg.id,
630
+ resultCase,
631
+ });
551
632
  sendExecResult(execMsg, resultCase, create(McpResultSchema, {}), sendFrame);
552
633
  return;
553
634
  }
@@ -4,6 +4,4 @@ export interface StreamState {
4
4
  pendingExecs: PendingExec[];
5
5
  outputTokens: number;
6
6
  totalTokens: number;
7
- interactionToolArgsText: Map<string, string>;
8
- emittedToolCallIds: Set<string>;
9
7
  }
@@ -1,9 +1,10 @@
1
1
  import type { CursorSession } from "../cursor/bidi-session";
2
- import type { ConversationRequestMetadata } from "./conversation-meta";
3
2
  import type { McpToolDefinition } from "../proto/agent_pb";
3
+ import type { ConversationRequestMetadata } from "./conversation-meta";
4
4
  export interface CursorRequestPayload {
5
5
  requestBytes: Uint8Array;
6
6
  blobStore: Map<string, Uint8Array>;
7
+ cloudRule?: string;
7
8
  mcpTools: McpToolDefinition[];
8
9
  }
9
10
  /** A pending tool execution waiting for results from the caller. */
@@ -14,14 +15,26 @@ export interface PendingExec {
14
15
  toolName: string;
15
16
  /** Decoded arguments JSON string for SSE tool_calls emission. */
16
17
  decodedArgs: string;
18
+ source?: "interaction" | "exec";
19
+ cursorCallId?: string;
20
+ modelCallId?: string;
21
+ }
22
+ export interface ActiveBridgeDiagnostics {
23
+ announcedToolCallIds: string[];
24
+ publishedToolCallIds: string[];
25
+ lastMcpUpdate?: string;
26
+ publishedAtMs?: number;
27
+ lastResumeAttemptAtMs?: number;
17
28
  }
18
29
  /** A live Cursor session kept alive across requests for tool result continuation. */
19
30
  export interface ActiveBridge {
20
31
  bridge: CursorSession;
21
32
  heartbeatTimer: NodeJS.Timeout;
22
33
  blobStore: Map<string, Uint8Array>;
34
+ cloudRule?: string;
23
35
  mcpTools: McpToolDefinition[];
24
36
  pendingExecs: PendingExec[];
25
37
  modelId: string;
26
38
  metadata: ConversationRequestMetadata;
39
+ diagnostics?: ActiveBridgeDiagnostics;
27
40
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@playwo/opencode-cursor-oauth",
3
- "version": "0.0.0-dev.4463bb589222",
3
+ "version": "0.0.0-dev.4696faa690e4",
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",
@@ -18,8 +18,7 @@
18
18
  "dist"
19
19
  ],
20
20
  "scripts": {
21
- "build": "tsc -p tsconfig.json",
22
- "test": "bun test/smoke.ts",
21
+ "build": "node ./scripts/build.mjs",
23
22
  "prepublishOnly": "npm run build"
24
23
  },
25
24
  "repository": {