@rama_nigg/open-cursor 2.4.4 → 2.4.5

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.
@@ -298,6 +298,15 @@ function resolveCursorAgentBinary(deps = {}) {
298
298
  log.warn("cursor-agent not found at known paths, falling back to PATH", { checkedPaths: knownPaths });
299
299
  return "cursor-agent";
300
300
  }
301
+ function formatShellCommandForPlatform(command, platform = process.platform) {
302
+ if (platform !== "win32") {
303
+ return command;
304
+ }
305
+ if (command.startsWith('"') && command.endsWith('"')) {
306
+ return command;
307
+ }
308
+ return `"${command}"`;
309
+ }
301
310
  var log;
302
311
  var init_binary = __esm(() => {
303
312
  init_logger();
@@ -298,6 +298,15 @@ function resolveCursorAgentBinary(deps = {}) {
298
298
  log.warn("cursor-agent not found at known paths, falling back to PATH", { checkedPaths: knownPaths });
299
299
  return "cursor-agent";
300
300
  }
301
+ function formatShellCommandForPlatform(command, platform = process.platform) {
302
+ if (platform !== "win32") {
303
+ return command;
304
+ }
305
+ if (command.startsWith('"') && command.endsWith('"')) {
306
+ return command;
307
+ }
308
+ return `"${command}"`;
309
+ }
301
310
  var log;
302
311
  var init_binary = __esm(() => {
303
312
  init_logger();
package/dist/index.js CHANGED
@@ -456,6 +456,15 @@ function resolveCursorAgentBinary(deps = {}) {
456
456
  log.warn("cursor-agent not found at known paths, falling back to PATH", { checkedPaths: knownPaths });
457
457
  return "cursor-agent";
458
458
  }
459
+ function formatShellCommandForPlatform(command, platform = process.platform) {
460
+ if (platform !== "win32") {
461
+ return command;
462
+ }
463
+ if (command.startsWith('"') && command.endsWith('"')) {
464
+ return command;
465
+ }
466
+ return `"${command}"`;
467
+ }
459
468
  var log;
460
469
  var init_binary = __esm(() => {
461
470
  init_logger();
@@ -505,7 +514,7 @@ async function pollForAuthFile(timeoutMs = AUTH_POLL_TIMEOUT, intervalMs = AUTH_
505
514
  async function startCursorOAuth() {
506
515
  return new Promise((resolve, reject) => {
507
516
  log2.info("Starting cursor-cli login process");
508
- const proc = spawn(resolveCursorAgentBinary(), ["login"], {
517
+ const proc = spawn(formatShellCommandForPlatform(resolveCursorAgentBinary()), ["login"], {
509
518
  stdio: ["pipe", "pipe", "pipe"],
510
519
  shell: process.platform === "win32"
511
520
  });
@@ -699,29 +708,6 @@ class LineBuffer {
699
708
  }
700
709
  }
701
710
 
702
- // src/streaming/types.ts
703
- var hasTextContent = (event) => event.message.content.some((content) => content.type === "text"), hasThinkingContent = (event) => event.message.content.some((content) => content.type === "thinking"), isAssistantText = (event) => event.type === "assistant" && hasTextContent(event), isThinking = (event) => {
704
- if (event.type === "thinking") {
705
- return true;
706
- }
707
- return event.type === "assistant" && hasThinkingContent(event);
708
- }, isToolCall = (event) => event.type === "tool_call", isResult = (event) => event.type === "result", extractText = (event) => event.message.content.filter((content) => content.type === "text").map((content) => content.text).join(""), extractThinking = (event) => {
709
- if (event.type === "thinking") {
710
- return event.text ?? "";
711
- }
712
- return event.message.content.filter((content) => content.type === "thinking").map((content) => content.thinking).join("");
713
- }, inferToolName = (event) => {
714
- const [key] = Object.keys(event.tool_call ?? {});
715
- if (!key) {
716
- return "";
717
- }
718
- if (key.endsWith("ToolCall")) {
719
- const base = key.slice(0, -"ToolCall".length);
720
- return base.charAt(0).toLowerCase() + base.slice(1);
721
- }
722
- return key;
723
- };
724
-
725
711
  // src/streaming/delta-tracker.ts
726
712
  class DeltaTracker {
727
713
  lastText = "";
@@ -759,14 +745,70 @@ class DeltaTracker {
759
745
  }
760
746
  }
761
747
 
748
+ class MixedDeltaTracker {
749
+ emittedText = "";
750
+ emittedThinking = "";
751
+ nextText(value) {
752
+ const delta = this.diff(this.emittedText, value);
753
+ if (delta) {
754
+ this.emittedText += delta;
755
+ }
756
+ return delta;
757
+ }
758
+ nextThinking(value) {
759
+ const delta = this.diff(this.emittedThinking, value);
760
+ if (delta) {
761
+ this.emittedThinking += delta;
762
+ }
763
+ return delta;
764
+ }
765
+ reset() {
766
+ this.emittedText = "";
767
+ this.emittedThinking = "";
768
+ }
769
+ diff(emitted, current) {
770
+ if (!emitted) {
771
+ return current;
772
+ }
773
+ if (current.startsWith(emitted)) {
774
+ return current.slice(emitted.length);
775
+ }
776
+ if (emitted.startsWith(current)) {
777
+ return "";
778
+ }
779
+ return current;
780
+ }
781
+ }
782
+
783
+ // src/streaming/types.ts
784
+ var hasTextContent = (event) => event.message.content.some((content) => content.type === "text"), hasThinkingContent = (event) => event.message.content.some((content) => content.type === "thinking"), isAssistantText = (event) => event.type === "assistant" && hasTextContent(event), isThinking = (event) => {
785
+ if (event.type === "thinking") {
786
+ return true;
787
+ }
788
+ return event.type === "assistant" && hasThinkingContent(event);
789
+ }, isToolCall = (event) => event.type === "tool_call", isResult = (event) => event.type === "result", extractText = (event) => event.message.content.filter((content) => content.type === "text").map((content) => content.text).join(""), extractThinking = (event) => {
790
+ if (event.type === "thinking") {
791
+ return event.text ?? "";
792
+ }
793
+ return event.message.content.filter((content) => content.type === "thinking").map((content) => content.thinking).join("");
794
+ }, inferToolName = (event) => {
795
+ const [key] = Object.keys(event.tool_call ?? {});
796
+ if (!key) {
797
+ return "";
798
+ }
799
+ if (key.endsWith("ToolCall")) {
800
+ const base = key.slice(0, -"ToolCall".length);
801
+ return base.charAt(0).toLowerCase() + base.slice(1);
802
+ }
803
+ return key;
804
+ };
805
+
762
806
  // src/streaming/openai-sse.ts
763
807
  class StreamToSseConverter {
764
808
  id;
765
809
  created;
766
810
  model;
767
- tracker = new DeltaTracker;
768
- sawAssistantPartials = false;
769
- sawThinkingPartials = false;
811
+ tracker = new MixedDeltaTracker;
770
812
  constructor(model, options) {
771
813
  this.model = model;
772
814
  this.id = options?.id ?? `cursor-acp-${Date.now()}`;
@@ -774,35 +816,17 @@ class StreamToSseConverter {
774
816
  }
775
817
  handleEvent(event) {
776
818
  if (isAssistantText(event)) {
777
- const isPartial = typeof event.timestamp_ms === "number";
778
- if (isPartial) {
779
- const text = extractText(event);
780
- if (text) {
781
- this.sawAssistantPartials = true;
782
- return [this.chunkWith({ content: text })];
783
- }
784
- return [];
785
- }
786
- if (this.sawAssistantPartials) {
819
+ const text = extractText(event);
820
+ if (!text)
787
821
  return [];
788
- }
789
- const delta = this.tracker.nextText(extractText(event));
822
+ const delta = this.tracker.nextText(text);
790
823
  return delta ? [this.chunkWith({ content: delta })] : [];
791
824
  }
792
825
  if (isThinking(event)) {
793
- const isPartial = typeof event.timestamp_ms === "number";
794
- if (isPartial) {
795
- const text = extractThinking(event);
796
- if (text) {
797
- this.sawThinkingPartials = true;
798
- return [this.chunkWith({ reasoning_content: text })];
799
- }
800
- return [];
801
- }
802
- if (this.sawThinkingPartials) {
826
+ const text = extractThinking(event);
827
+ if (!text)
803
828
  return [];
804
- }
805
- const delta = this.tracker.nextThinking(extractThinking(event));
829
+ const delta = this.tracker.nextThinking(text);
806
830
  return delta ? [this.chunkWith({ reasoning_content: delta })] : [];
807
831
  }
808
832
  if (isToolCall(event)) {
@@ -16110,6 +16134,7 @@ function extractCompletionFromStream(output) {
16110
16134
  let usage;
16111
16135
  let sawAssistantPartials = false;
16112
16136
  let sawThinkingPartials = false;
16137
+ const tracker = new MixedDeltaTracker;
16113
16138
  for (const line of lines) {
16114
16139
  const event = parseStreamJsonLine(line);
16115
16140
  if (!event) {
@@ -16121,8 +16146,8 @@ function extractCompletionFromStream(output) {
16121
16146
  continue;
16122
16147
  const isPartial = typeof event.timestamp_ms === "number";
16123
16148
  if (isPartial) {
16124
- assistantText += text;
16125
16149
  sawAssistantPartials = true;
16150
+ assistantText += tracker.nextText(text);
16126
16151
  } else if (!sawAssistantPartials) {
16127
16152
  assistantText = text;
16128
16153
  }
@@ -16132,8 +16157,8 @@ function extractCompletionFromStream(output) {
16132
16157
  if (thinking) {
16133
16158
  const isPartial = typeof event.timestamp_ms === "number";
16134
16159
  if (isPartial) {
16135
- reasoningText += thinking;
16136
16160
  sawThinkingPartials = true;
16161
+ reasoningText += tracker.nextThinking(thinking);
16137
16162
  } else if (!sawThinkingPartials) {
16138
16163
  reasoningText = thinking;
16139
16164
  }
@@ -16820,7 +16845,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16820
16845
  if (FORCE_TOOL_MODE) {
16821
16846
  cmd.push("--force");
16822
16847
  }
16823
- const child = spawn3(cmd[0], cmd.slice(1), {
16848
+ const child = spawn3(formatShellCommandForPlatform(cmd[0]), cmd.slice(1), {
16824
16849
  stdio: ["pipe", "pipe", "pipe"],
16825
16850
  shell: process.platform === "win32"
16826
16851
  });
@@ -16967,22 +16992,18 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16967
16992
  child.kill();
16968
16993
  } catch {}
16969
16994
  };
16970
- child.stdout.on("data", async (chunk) => {
16971
- if (streamTerminated || res.writableEnded) {
16972
- return;
16973
- }
16974
- if (!firstTokenReceived) {
16975
- perf.mark("first-token");
16976
- firstTokenReceived = true;
16977
- }
16978
- for (const line of lineBuffer.push(chunk)) {
16979
- if (streamTerminated || res.writableEnded) {
16995
+ const chunkQueue = [];
16996
+ let draining = false;
16997
+ let childClosed = false;
16998
+ let childCloseHandled = false;
16999
+ let childExitCode = null;
17000
+ const processLines = async (lines) => {
17001
+ for (const line of lines) {
17002
+ if (streamTerminated || res.writableEnded)
16980
17003
  break;
16981
- }
16982
17004
  const event = parseStreamJsonLine(line);
16983
- if (!event) {
17005
+ if (!event)
16984
17006
  continue;
16985
- }
16986
17007
  if (isResult(event)) {
16987
17008
  usage = extractOpenAiUsageFromResult(event) ?? usage;
16988
17009
  }
@@ -17031,148 +17052,100 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
17031
17052
  }
17032
17053
  break;
17033
17054
  }
17034
- if (result.intercepted) {
17055
+ if (result.intercepted)
17035
17056
  break;
17036
- }
17037
- if (result.skipConverter) {
17057
+ if (result.skipConverter)
17038
17058
  continue;
17039
- }
17040
17059
  }
17041
- if (streamTerminated || res.writableEnded) {
17060
+ if (streamTerminated || res.writableEnded)
17042
17061
  break;
17043
- }
17044
17062
  for (const sse of converter.handleEvent(event)) {
17045
17063
  res.write(sse);
17046
17064
  }
17047
17065
  }
17048
- });
17049
- child.on("close", async (code) => {
17050
- if (streamTerminated || res.writableEnded) {
17066
+ };
17067
+ const drainQueue = async () => {
17068
+ if (draining)
17051
17069
  return;
17052
- }
17053
- for (const line of lineBuffer.flush()) {
17054
- if (streamTerminated || res.writableEnded) {
17055
- break;
17056
- }
17057
- const event = parseStreamJsonLine(line);
17058
- if (!event) {
17059
- continue;
17060
- }
17061
- if (isResult(event)) {
17062
- usage = extractOpenAiUsageFromResult(event) ?? usage;
17063
- }
17064
- if (event.type === "tool_call") {
17065
- const result = await handleToolLoopEventWithFallback({
17066
- event,
17067
- boundary: boundaryContext.getBoundary(),
17068
- boundaryMode: boundaryContext.getBoundary().mode,
17069
- autoFallbackToLegacy: ENABLE_PROVIDER_BOUNDARY_AUTOFALLBACK,
17070
- toolLoopMode: TOOL_LOOP_MODE,
17071
- allowedToolNames,
17072
- toolSchemaMap,
17073
- toolLoopGuard,
17074
- toolMapper,
17075
- toolSessionId,
17076
- shouldEmitToolUpdates: SHOULD_EMIT_TOOL_UPDATES,
17077
- proxyExecuteToolCalls: PROXY_EXECUTE_TOOL_CALLS,
17078
- suppressConverterToolEvents: SUPPRESS_CONVERTER_TOOL_EVENTS,
17079
- toolRouter,
17080
- responseMeta: { id, created, model },
17081
- passThroughTracker,
17082
- onToolUpdate: (update) => {
17083
- res.write(formatToolUpdateEvent(update));
17084
- },
17085
- onToolResult: (toolResult) => {
17086
- res.write(`data: ${JSON.stringify(toolResult)}
17087
-
17088
- `);
17089
- },
17090
- onInterceptedToolCall: (toolCall) => {
17091
- emitToolCallAndTerminate(toolCall);
17092
- },
17093
- onFallbackToLegacy: (error) => {
17094
- boundaryContext.activateLegacyFallback("handleToolLoopEvent.close", error);
17095
- }
17096
- });
17097
- if (result.terminate) {
17098
- if (!result.terminate.silent) {
17099
- emitTerminalAssistantErrorAndTerminate(result.terminate.message);
17100
- } else {
17101
- streamTerminated = true;
17102
- try {
17103
- child.kill();
17104
- } catch {}
17105
- }
17106
- break;
17107
- }
17108
- if (result.intercepted) {
17070
+ draining = true;
17071
+ try {
17072
+ while (chunkQueue.length > 0) {
17073
+ if (streamTerminated || res.writableEnded)
17109
17074
  break;
17075
+ const chunk = chunkQueue.shift();
17076
+ if (!firstTokenReceived) {
17077
+ perf.mark("first-token");
17078
+ firstTokenReceived = true;
17110
17079
  }
17111
- if (result.skipConverter) {
17112
- continue;
17113
- }
17080
+ await processLines(lineBuffer.push(chunk));
17114
17081
  }
17115
- if (streamTerminated || res.writableEnded) {
17116
- break;
17117
- }
17118
- for (const sse of converter.handleEvent(event)) {
17119
- res.write(sse);
17120
- }
17121
- }
17122
- if (streamTerminated || res.writableEnded) {
17123
- return;
17124
- }
17125
- perf.mark("request:done");
17126
- perf.summarize();
17127
- const stderrText = Buffer.concat(stderrChunks).toString().trim();
17128
- log20.debug("cursor-agent completed (node stream)", {
17129
- code,
17130
- stderrChars: stderrText.length
17131
- });
17132
- if (code !== 0) {
17133
- const errSource = stderrText || `cursor-agent exited with code ${String(code ?? "unknown")} and no output`;
17134
- const parsed = parseAgentError(errSource);
17135
- const msg = formatErrorForUser(parsed);
17136
- const errChunk = createChatCompletionChunk(id, created, model, msg, true);
17137
- res.write(`data: ${JSON.stringify(errChunk)}
17082
+ if (childClosed && !childCloseHandled && !streamTerminated && !res.writableEnded) {
17083
+ childCloseHandled = true;
17084
+ await processLines(lineBuffer.flush());
17085
+ if (streamTerminated || res.writableEnded)
17086
+ return;
17087
+ perf.mark("request:done");
17088
+ perf.summarize();
17089
+ const stderrText = Buffer.concat(stderrChunks).toString().trim();
17090
+ log20.debug("cursor-agent completed (node stream)", {
17091
+ code: childExitCode,
17092
+ stderrChars: stderrText.length
17093
+ });
17094
+ if (childExitCode !== 0) {
17095
+ const errSource = stderrText || `cursor-agent exited with code ${String(childExitCode ?? "unknown")} and no output`;
17096
+ const parsed = parseAgentError(errSource);
17097
+ const msg = formatErrorForUser(parsed);
17098
+ const errChunk = createChatCompletionChunk(id, created, model, msg, true);
17099
+ res.write(`data: ${JSON.stringify(errChunk)}
17138
17100
 
17139
17101
  `);
17140
- res.write(formatSseDone());
17141
- streamTerminated = true;
17142
- res.end();
17143
- return;
17144
- }
17145
- const passThroughSummary = passThroughTracker.getSummary();
17146
- if (passThroughSummary.hasActivity) {
17147
- await toastService.showPassThroughSummary(passThroughSummary.tools);
17148
- }
17149
- if (passThroughSummary.errors.length > 0) {
17150
- await toastService.showErrorSummary(passThroughSummary.errors);
17151
- }
17152
- const doneChunk = {
17153
- id,
17154
- object: "chat.completion.chunk",
17155
- created,
17156
- model,
17157
- choices: [
17158
- {
17159
- index: 0,
17160
- delta: {},
17161
- finish_reason: "stop"
17102
+ res.write(formatSseDone());
17103
+ streamTerminated = true;
17104
+ res.end();
17105
+ return;
17162
17106
  }
17163
- ]
17164
- };
17165
- res.write(`data: ${JSON.stringify(doneChunk)}
17107
+ const passThroughSummary = passThroughTracker.getSummary();
17108
+ if (passThroughSummary.hasActivity) {
17109
+ await toastService.showPassThroughSummary(passThroughSummary.tools);
17110
+ }
17111
+ if (passThroughSummary.errors.length > 0) {
17112
+ await toastService.showErrorSummary(passThroughSummary.errors);
17113
+ }
17114
+ const doneChunk = {
17115
+ id,
17116
+ object: "chat.completion.chunk",
17117
+ created,
17118
+ model,
17119
+ choices: [{ index: 0, delta: {}, finish_reason: "stop" }]
17120
+ };
17121
+ res.write(`data: ${JSON.stringify(doneChunk)}
17166
17122
 
17167
17123
  `);
17168
- if (usage) {
17169
- const usageChunk = createChatCompletionUsageChunk(id, created, model, usage);
17170
- res.write(`data: ${JSON.stringify(usageChunk)}
17124
+ if (usage) {
17125
+ const usageChunk = createChatCompletionUsageChunk(id, created, model, usage);
17126
+ res.write(`data: ${JSON.stringify(usageChunk)}
17171
17127
 
17172
17128
  `);
17129
+ }
17130
+ res.write(formatSseDone());
17131
+ streamTerminated = true;
17132
+ res.end();
17133
+ }
17134
+ } finally {
17135
+ draining = false;
17136
+ if (!streamTerminated && !res.writableEnded && (chunkQueue.length > 0 || childClosed && !childCloseHandled)) {
17137
+ drainQueue();
17138
+ }
17173
17139
  }
17174
- res.write(formatSseDone());
17175
- res.end();
17140
+ };
17141
+ child.stdout.on("data", (chunk) => {
17142
+ chunkQueue.push(Buffer.from(chunk));
17143
+ drainQueue();
17144
+ });
17145
+ child.on("close", (code) => {
17146
+ childClosed = true;
17147
+ childExitCode = code;
17148
+ drainQueue();
17176
17149
  });
17177
17150
  }
17178
17151
  } catch (error) {
@@ -17727,7 +17700,7 @@ class SimpleCursorClient {
17727
17700
  args.push("--resume", resumeId);
17728
17701
  }
17729
17702
  this.log.debug("Executing prompt stream", { promptLength: prompt.length, mode, model });
17730
- const child = spawn3(this.config.cursorAgentPath, args, {
17703
+ const child = spawn3(formatShellCommandForPlatform(this.config.cursorAgentPath), args, {
17731
17704
  cwd,
17732
17705
  stdio: ["pipe", "pipe", "pipe"],
17733
17706
  shell: process.platform === "win32"
@@ -17814,7 +17787,7 @@ class SimpleCursorClient {
17814
17787
  }
17815
17788
  this.log.debug("Executing prompt", { promptLength: prompt.length, mode, model });
17816
17789
  return new Promise((resolve3, reject) => {
17817
- const child = spawn3(this.config.cursorAgentPath, args, {
17790
+ const child = spawn3(formatShellCommandForPlatform(this.config.cursorAgentPath), args, {
17818
17791
  cwd,
17819
17792
  stdio: ["pipe", "pipe", "pipe"],
17820
17793
  shell: process.platform === "win32"
@@ -18063,42 +18036,22 @@ function createProxyServer(config) {
18063
18036
 
18064
18037
  // src/streaming/ai-sdk-parts.ts
18065
18038
  class StreamToAiSdkParts {
18066
- tracker = new DeltaTracker;
18067
18039
  toolArgsById = new Map;
18068
18040
  startedToolIds = new Set;
18069
- sawAssistantPartials = false;
18070
- sawThinkingPartials = false;
18041
+ tracker = new MixedDeltaTracker;
18071
18042
  handleEvent(event) {
18072
18043
  if (isAssistantText(event)) {
18073
- const isPartial = typeof event.timestamp_ms === "number";
18074
- if (isPartial) {
18075
- const text = extractText(event);
18076
- if (text) {
18077
- this.sawAssistantPartials = true;
18078
- return [{ type: "text-delta", textDelta: text }];
18079
- }
18080
- return [];
18081
- }
18082
- if (this.sawAssistantPartials) {
18044
+ const text = extractText(event);
18045
+ if (!text)
18083
18046
  return [];
18084
- }
18085
- const delta = this.tracker.nextText(extractText(event));
18047
+ const delta = this.tracker.nextText(text);
18086
18048
  return delta ? [{ type: "text-delta", textDelta: delta }] : [];
18087
18049
  }
18088
18050
  if (isThinking(event)) {
18089
- const isPartial = typeof event.timestamp_ms === "number";
18090
- if (isPartial) {
18091
- const text = extractThinking(event);
18092
- if (text) {
18093
- this.sawThinkingPartials = true;
18094
- return [{ type: "text-delta", textDelta: text }];
18095
- }
18096
- return [];
18097
- }
18098
- if (this.sawThinkingPartials) {
18051
+ const text = extractThinking(event);
18052
+ if (!text)
18099
18053
  return [];
18100
- }
18101
- const delta = this.tracker.nextThinking(extractThinking(event));
18054
+ const delta = this.tracker.nextThinking(text);
18102
18055
  return delta ? [{ type: "text-delta", textDelta: delta }] : [];
18103
18056
  }
18104
18057
  if (isToolCall(event)) {