@rama_nigg/open-cursor 2.4.4 → 2.4.6

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/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)) {
@@ -978,27 +1002,6 @@ var init_perf = __esm(() => {
978
1002
  });
979
1003
 
980
1004
  // src/proxy/prompt-builder.ts
981
- import { appendFileSync as appendFileSync2, existsSync as existsSync3, mkdirSync as mkdirSync2 } from "node:fs";
982
- import { homedir as homedir3 } from "node:os";
983
- import { join as join4 } from "node:path";
984
- function ensureLogDir2() {
985
- try {
986
- if (!existsSync3(DEBUG_LOG_DIR)) {
987
- mkdirSync2(DEBUG_LOG_DIR, { recursive: true });
988
- }
989
- } catch {}
990
- }
991
- function debugLogToFile(message, data) {
992
- try {
993
- ensureLogDir2();
994
- const timestamp = new Date().toISOString();
995
- const logLine = `[${timestamp}] ${message}: ${JSON.stringify(data, null, 2)}
996
- `;
997
- appendFileSync2(DEBUG_LOG_FILE, logLine);
998
- } catch (err) {
999
- log5.debug(message, data);
1000
- }
1001
- }
1002
1005
  function buildPromptFromMessages(messages, tools, subagentNames = []) {
1003
1006
  const messageSummary = messages.map((m, i) => {
1004
1007
  const role = m?.role ?? "?";
@@ -1012,7 +1015,7 @@ function buildPromptFromMessages(messages, tools, subagentNames = []) {
1012
1015
  const assistantWithToolCalls = messages.filter((m) => m?.role === "assistant" && Array.isArray(m?.tool_calls) && m.tool_calls.length > 0);
1013
1016
  const assistantEmpty = messages.filter((m) => m?.role === "assistant" && (!m?.tool_calls || m.tool_calls.length === 0) && (!m?.content || m.content === "" || m.content === null));
1014
1017
  const toolResults = messages.filter((m) => m?.role === "tool");
1015
- debugLogToFile("buildPromptFromMessages", {
1018
+ log5.debug("buildPromptFromMessages", {
1016
1019
  totalMessages: messages.length,
1017
1020
  totalTools: tools.length,
1018
1021
  messageSummary,
@@ -1107,22 +1110,20 @@ ${toolDescs}`);
1107
1110
  const finalPrompt = lines.join(`
1108
1111
 
1109
1112
  `);
1110
- debugLogToFile("buildPromptFromMessages: final prompt", {
1113
+ log5.debug("buildPromptFromMessages: final prompt", {
1111
1114
  lineCount: lines.length,
1112
1115
  promptLength: finalPrompt.length,
1113
1116
  promptPreview: finalPrompt.slice(0, 500),
1114
1117
  hasToolResultFormat: finalPrompt.includes("TOOL_RESULT"),
1115
1118
  hasAssistantToolCallFormat: finalPrompt.includes("tool_call(id:"),
1116
- hasCompletionSignal: finalPrompt.includes("Based on the tool results")
1119
+ hasCompletionSignal: finalPrompt.includes("The above tool calls have been executed")
1117
1120
  });
1118
1121
  return finalPrompt;
1119
1122
  }
1120
- var log5, DEBUG_LOG_DIR, DEBUG_LOG_FILE;
1123
+ var log5;
1121
1124
  var init_prompt_builder = __esm(() => {
1122
1125
  init_logger();
1123
1126
  log5 = createLogger("proxy:prompt-builder");
1124
- DEBUG_LOG_DIR = join4(homedir3(), ".config", "opencode", "logs");
1125
- DEBUG_LOG_FILE = join4(DEBUG_LOG_DIR, "tool-loop-debug.log");
1126
1127
  });
1127
1128
 
1128
1129
  // src/proxy/tool-loop.ts
@@ -1803,9 +1804,9 @@ var init_model_discovery = __esm(() => {
1803
1804
  });
1804
1805
 
1805
1806
  // src/plugin-toggle.ts
1806
- import { existsSync as existsSync4, readFileSync } from "fs";
1807
- import { homedir as homedir4 } from "os";
1808
- import { join as join5, resolve } from "path";
1807
+ import { existsSync as existsSync3, readFileSync } from "fs";
1808
+ import { homedir as homedir3 } from "os";
1809
+ import { join as join4, resolve } from "path";
1809
1810
  function matchesPlugin(entry) {
1810
1811
  if (entry === CURSOR_PROVIDER_ID)
1811
1812
  return true;
@@ -1819,8 +1820,8 @@ function resolveOpenCodeConfigPath(env = process.env) {
1819
1820
  if (env.OPENCODE_CONFIG && env.OPENCODE_CONFIG.length > 0) {
1820
1821
  return resolve(env.OPENCODE_CONFIG);
1821
1822
  }
1822
- const configHome = env.XDG_CONFIG_HOME && env.XDG_CONFIG_HOME.length > 0 ? env.XDG_CONFIG_HOME : join5(homedir4(), ".config");
1823
- return join5(configHome, "opencode", "opencode.json");
1823
+ const configHome = env.XDG_CONFIG_HOME && env.XDG_CONFIG_HOME.length > 0 ? env.XDG_CONFIG_HOME : join4(homedir3(), ".config");
1824
+ return join4(configHome, "opencode", "opencode.json");
1824
1825
  }
1825
1826
  function isCursorPluginEnabledInConfig(config) {
1826
1827
  if (!config || typeof config !== "object") {
@@ -1839,7 +1840,7 @@ function isCursorPluginEnabledInConfig(config) {
1839
1840
  }
1840
1841
  function shouldEnableCursorPlugin(env = process.env) {
1841
1842
  const configPath = resolveOpenCodeConfigPath(env);
1842
- if (!existsSync4(configPath)) {
1843
+ if (!existsSync3(configPath)) {
1843
1844
  return {
1844
1845
  enabled: true,
1845
1846
  configPath,
@@ -11975,7 +11976,7 @@ function buildMcpToolDefinitions(tools) {
11975
11976
  function namespaceMcpTool(serverName, toolName) {
11976
11977
  const sanitizedServer = serverName.replace(/[^a-zA-Z0-9]/g, "_");
11977
11978
  const sanitizedTool = toolName.replace(/[^a-zA-Z0-9]/g, "_");
11978
- return `mcp__${sanitizedServer}__${sanitizedTool}`;
11979
+ return `${MCP_TOOL_PREFIX}${sanitizedServer}__${sanitizedTool}`;
11979
11980
  }
11980
11981
  function mcpSchemaToZod(inputSchema, z2) {
11981
11982
  if (!inputSchema || typeof inputSchema !== "object") {
@@ -12017,7 +12018,7 @@ function mcpSchemaToZod(inputSchema, z2) {
12017
12018
  }
12018
12019
  return shape;
12019
12020
  }
12020
- var log13;
12021
+ var log13, MCP_TOOL_PREFIX = "mcp__";
12021
12022
  var init_tool_bridge = __esm(() => {
12022
12023
  init_logger();
12023
12024
  log13 = createLogger("mcp:tool-bridge");
@@ -14022,9 +14023,6 @@ function resolveEditArguments(args) {
14022
14023
  newString = fallbackContent;
14023
14024
  }
14024
14025
  }
14025
- if (oldString === undefined && newString !== undefined) {
14026
- oldString = "";
14027
- }
14028
14026
  return {
14029
14027
  path: path2,
14030
14028
  old_string: oldString,
@@ -14431,7 +14429,10 @@ function applyToolSchemaCompat(toolCall, toolSchemaMap) {
14431
14429
  const toolSpecificArgs = normalizeToolSpecificArgs(toolCall.function.name, normalizedArgs);
14432
14430
  const schema = toolSchemaMap.get(toolCall.function.name);
14433
14431
  const sanitization = sanitizeArgumentsForSchema(toolSpecificArgs, schema);
14434
- const validation = validateToolArguments(toolCall.function.name, sanitization.args, schema, sanitization.unexpected);
14432
+ const validation = validateToolArguments(toolCall.function.name, sanitization.args, schema, sanitization.unexpected, {
14433
+ originalArgs: parsedArgs,
14434
+ writeSchema: toolSchemaMap.get("write")
14435
+ });
14435
14436
  const normalizedToolCall = {
14436
14437
  ...toolCall,
14437
14438
  function: {
@@ -14442,12 +14443,59 @@ function applyToolSchemaCompat(toolCall, toolSchemaMap) {
14442
14443
  return {
14443
14444
  toolCall: normalizedToolCall,
14444
14445
  normalizedArgs: sanitization.args,
14446
+ originalArgs: parsedArgs,
14445
14447
  originalArgKeys,
14446
14448
  normalizedArgKeys: Object.keys(sanitization.args),
14447
14449
  collisionKeys,
14448
14450
  validation
14449
14451
  };
14450
14452
  }
14453
+ function isFullFileShapedEditValidationFailure(toolName, args, validation, originalArgs, writeSchema) {
14454
+ if (toolName.toLowerCase() !== "edit" || validation.ok) {
14455
+ return false;
14456
+ }
14457
+ return buildEditFullFileHint(args, validation.missing, validation.typeErrors, {
14458
+ originalArgs,
14459
+ writeSchema
14460
+ }) !== null;
14461
+ }
14462
+ function buildWriteArguments(filePath, content, writeSchema) {
14463
+ if (!isRecord3(writeSchema)) {
14464
+ return { path: filePath, content };
14465
+ }
14466
+ const required = Array.isArray(writeSchema.required) ? writeSchema.required.filter((value) => typeof value === "string") : [];
14467
+ if (required.includes("filePath")) {
14468
+ return { filePath, content };
14469
+ }
14470
+ return { path: filePath, content };
14471
+ }
14472
+ function tryRerouteEditToWrite(toolCall, compat, allowedToolNames, toolSchemaMap) {
14473
+ if (toolCall.function.name.toLowerCase() !== "edit") {
14474
+ return null;
14475
+ }
14476
+ if (!allowedToolNames.has("write") || !toolSchemaMap.has("write")) {
14477
+ return null;
14478
+ }
14479
+ const writeSchema = toolSchemaMap.get("write");
14480
+ if (!isFullFileShapedEditValidationFailure(toolCall.function.name, compat.normalizedArgs, compat.validation, compat.originalArgs, writeSchema)) {
14481
+ return null;
14482
+ }
14483
+ const filePath = typeof compat.normalizedArgs.path === "string" && compat.normalizedArgs.path.length > 0 ? compat.normalizedArgs.path : typeof compat.normalizedArgs.filePath === "string" && compat.normalizedArgs.filePath.length > 0 ? compat.normalizedArgs.filePath : null;
14484
+ if (!filePath) {
14485
+ return null;
14486
+ }
14487
+ const content = typeof compat.normalizedArgs.new_string === "string" ? compat.normalizedArgs.new_string : typeof compat.normalizedArgs.newString === "string" ? compat.normalizedArgs.newString : typeof compat.normalizedArgs.content === "string" ? compat.normalizedArgs.content : null;
14488
+ if (content === null) {
14489
+ return null;
14490
+ }
14491
+ return {
14492
+ ...toolCall,
14493
+ function: {
14494
+ name: "write",
14495
+ arguments: JSON.stringify(buildWriteArguments(filePath, content, writeSchema))
14496
+ }
14497
+ };
14498
+ }
14451
14499
  function parseArguments(rawArguments) {
14452
14500
  try {
14453
14501
  const parsed = JSON.parse(rawArguments);
@@ -14630,7 +14678,7 @@ function sanitizeArgumentsForSchema(args, schema) {
14630
14678
  }
14631
14679
  return { args: sanitized, unexpected };
14632
14680
  }
14633
- function validateToolArguments(toolName, args, schema, unexpected) {
14681
+ function validateToolArguments(toolName, args, schema, unexpected, context = {}) {
14634
14682
  if (!isRecord3(schema)) {
14635
14683
  return {
14636
14684
  hasSchema: false,
@@ -14666,10 +14714,59 @@ function validateToolArguments(toolName, args, schema, unexpected) {
14666
14714
  missing,
14667
14715
  unexpected,
14668
14716
  typeErrors,
14669
- repairHint: ok ? undefined : buildRepairHint(toolName, missing, unexpected, typeErrors)
14717
+ repairHint: ok ? undefined : buildRepairHint(toolName, args, missing, unexpected, typeErrors, context)
14670
14718
  };
14671
14719
  }
14672
- function buildRepairHint(toolName, missing, unexpected, typeErrors) {
14720
+ function hadOldStringPropertyInPayload(args) {
14721
+ for (const key of Object.keys(args)) {
14722
+ const token = key.toLowerCase().replace(/[^a-z0-9]/g, "");
14723
+ if (token === "oldstring") {
14724
+ return true;
14725
+ }
14726
+ }
14727
+ return false;
14728
+ }
14729
+ function hasEditFilePath(args) {
14730
+ const pathValue = args.path ?? args.filePath;
14731
+ return typeof pathValue === "string" && pathValue.trim().length > 0;
14732
+ }
14733
+ function hasEditBody(args) {
14734
+ const body = args.new_string ?? args.newString ?? args.content;
14735
+ return typeof body === "string" && body.length > 0;
14736
+ }
14737
+ function writeToolExample(writeSchema) {
14738
+ if (!isRecord3(writeSchema)) {
14739
+ return "write with path and content";
14740
+ }
14741
+ const required = Array.isArray(writeSchema.required) ? writeSchema.required.filter((value) => typeof value === "string") : [];
14742
+ if (required.includes("filePath")) {
14743
+ return "write with filePath and content";
14744
+ }
14745
+ return "write with path and content";
14746
+ }
14747
+ function buildEditFullFileHint(args, missing, typeErrors, context) {
14748
+ if (typeErrors.length > 0) {
14749
+ return null;
14750
+ }
14751
+ const missingOldStringOnly = (missing.includes("old_string") || missing.includes("oldString")) && missing.every((key) => key === "old_string" || key === "oldString");
14752
+ if (!missingOldStringOnly) {
14753
+ return null;
14754
+ }
14755
+ const originalArgs = context.originalArgs ?? {};
14756
+ if (hadOldStringPropertyInPayload(originalArgs)) {
14757
+ return null;
14758
+ }
14759
+ if (!hasEditFilePath(args) || !hasEditBody(args)) {
14760
+ return null;
14761
+ }
14762
+ const example = writeToolExample(context.writeSchema);
14763
+ return `For a full file body, use ${example} instead of edit without old_string`;
14764
+ }
14765
+ function buildRepairHint(toolName, args, missing, unexpected, typeErrors, context = {}) {
14766
+ const fullFileHint = toolName.toLowerCase() === "edit" ? buildEditFullFileHint(args, missing, typeErrors, context) : null;
14767
+ if (fullFileHint) {
14768
+ return fullFileHint;
14769
+ }
14673
14770
  const hints = [];
14674
14771
  if (missing.length > 0) {
14675
14772
  hints.push(`missing required: ${missing.join(", ")}`);
@@ -14680,7 +14777,7 @@ function buildRepairHint(toolName, missing, unexpected, typeErrors) {
14680
14777
  if (typeErrors.length > 0) {
14681
14778
  hints.push(`fix type errors: ${typeErrors.join("; ")}`);
14682
14779
  }
14683
- if (toolName.toLowerCase() === "edit" && (missing.includes("old_string") || missing.includes("new_string"))) {
14780
+ if (toolName.toLowerCase() === "edit" && (missing.includes("old_string") || missing.includes("oldString") || missing.includes("new_string") || missing.includes("newString"))) {
14684
14781
  hints.push("edit requires path, old_string, and new_string");
14685
14782
  }
14686
14783
  return hints.join(" | ");
@@ -14867,6 +14964,14 @@ async function handleToolLoopEventLegacy(options) {
14867
14964
  }
14868
14965
  return { intercepted: false, skipConverter: true, terminate: validationTermination };
14869
14966
  }
14967
+ const reroutedWrite = tryRerouteEditToWrite(normalizedToolCall, compat, allowedToolNames, toolSchemaMap);
14968
+ if (reroutedWrite) {
14969
+ log18.debug("Rerouting malformed edit call to write (legacy)", {
14970
+ missing: compat.validation.missing
14971
+ });
14972
+ await onInterceptedToolCall(reroutedWrite);
14973
+ return { intercepted: true, skipConverter: true };
14974
+ }
14870
14975
  if (shouldEmitNonFatalSchemaValidationHint(normalizedToolCall, compat.validation)) {
14871
14976
  const hintChunk = createNonFatalSchemaValidationHintChunk(responseMeta, normalizedToolCall, compat.validation);
14872
14977
  log18.debug("Emitting non-fatal schema validation hint in legacy and skipping malformed tool execution", {
@@ -15018,6 +15123,18 @@ async function handleToolLoopEventV1(options) {
15018
15123
  terminate: createSchemaValidationTermination(normalizedToolCall, compat.validation)
15019
15124
  };
15020
15125
  }
15126
+ const reroutedWrite = tryRerouteEditToWrite(normalizedToolCall, compat, allowedToolNames, toolSchemaMap);
15127
+ if (reroutedWrite) {
15128
+ log18.debug("Rerouting malformed edit call to write", {
15129
+ missing: compat.validation.missing,
15130
+ typeErrors: compat.validation.typeErrors
15131
+ });
15132
+ await onInterceptedToolCall(reroutedWrite);
15133
+ return {
15134
+ intercepted: true,
15135
+ skipConverter: true
15136
+ };
15137
+ }
15021
15138
  if (schemaValidationFailureMode === "pass_through" && shouldEmitNonFatalSchemaValidationHint(normalizedToolCall, compat.validation)) {
15022
15139
  const hintChunk = createNonFatalSchemaValidationHintChunk(responseMeta, normalizedToolCall, compat.validation);
15023
15140
  log18.debug("Emitting non-fatal schema validation hint and skipping malformed tool execution", {
@@ -15228,8 +15345,9 @@ function shouldTerminateOnSchemaValidation(toolCall, validation) {
15228
15345
  }
15229
15346
  function createNonFatalSchemaValidationHintChunk(meta, toolCall, validation) {
15230
15347
  const termination = createSchemaValidationTermination(toolCall, validation);
15231
- const hint = termination.repairHint || "Use write for full-file replacement, or provide path, old_string, and new_string for edit.";
15232
- const content = `Skipped malformed tool call "${toolCall.function.name}": ${termination.message} ${hint}`.trim();
15348
+ const fallbackHint = "Use write for full-file replacement, or provide path, old_string, and new_string for edit.";
15349
+ const suffix = termination.repairHint ? "" : ` ${fallbackHint}`;
15350
+ const content = `Skipped malformed tool call "${toolCall.function.name}": ${termination.message}${suffix}`.trim();
15233
15351
  return {
15234
15352
  id: meta.id,
15235
15353
  object: "chat.completion.chunk",
@@ -15870,25 +15988,13 @@ __export(exports_plugin, {
15870
15988
  CursorPlugin: () => CursorPlugin
15871
15989
  });
15872
15990
  import { tool as tool2 } from "@opencode-ai/plugin";
15873
- import { appendFileSync as appendFileSync3, existsSync as existsSync5, realpathSync } from "fs";
15991
+ import { realpathSync } from "fs";
15874
15992
  import { mkdir } from "fs/promises";
15875
- import { homedir as homedir5 } from "os";
15876
- import { isAbsolute, join as join6, relative, resolve as resolve2 } from "path";
15877
- function ensureDebugLogDir() {
15878
- try {
15879
- if (!existsSync5(DEBUG_LOG_DIR2)) {
15880
- mkdir(DEBUG_LOG_DIR2, { recursive: true }).catch(() => {});
15881
- }
15882
- } catch {}
15883
- }
15884
- function debugLogToFile2(message, data) {
15885
- try {
15886
- ensureDebugLogDir();
15887
- const timestamp = new Date().toISOString();
15888
- const logLine = `[${timestamp}] ${message}: ${JSON.stringify(data, null, 2)}
15889
- `;
15890
- appendFileSync3(DEBUG_LOG_FILE2, logLine);
15891
- } catch {}
15993
+ import { homedir as homedir4 } from "os";
15994
+ import { isAbsolute, join as join5, relative, resolve as resolve2 } from "path";
15995
+ function getMcpToolDefinitionName(mcpToolDefs, index) {
15996
+ const name = mcpToolDefs[index]?.function?.name;
15997
+ return typeof name === "string" && name.length > 0 ? name : undefined;
15892
15998
  }
15893
15999
  function buildAvailableToolsSystemMessage(lastToolNames, lastToolMap, mcpToolDefs, mcpToolSummaries, subagentNames = []) {
15894
16000
  const parts = [];
@@ -15898,27 +16004,27 @@ function buildAvailableToolsSystemMessage(lastToolNames, lastToolMap, mcpToolDef
15898
16004
  parts.push(`Available OpenCode tools (use via tool calls): ${names}. Original skill ids mapped as: ${mapping}. Aliases include oc_skill_* and oc_superskill_* when applicable.`);
15899
16005
  }
15900
16006
  if (mcpToolSummaries && mcpToolSummaries.length > 0) {
16007
+ const summariesWithCallNames = mcpToolSummaries.map((summary, index) => ({
16008
+ ...summary,
16009
+ callName: summary.callName ?? getMcpToolDefinitionName(mcpToolDefs, index) ?? namespaceMcpTool(summary.serverName, summary.toolName)
16010
+ }));
15901
16011
  const servers = new Map;
15902
- for (const s of mcpToolSummaries) {
16012
+ for (const s of summariesWithCallNames) {
15903
16013
  const list = servers.get(s.serverName) ?? [];
15904
16014
  list.push(s);
15905
16015
  servers.set(s.serverName, list);
15906
16016
  }
15907
16017
  const lines = [
15908
- "MCP TOOLS — Use via Shell with the `mcptool` CLI.",
15909
- "Syntax: mcptool call <server> <tool> [json-args]",
16018
+ `MCP TOOLS — Use via direct tool calls (\`${MCP_TOOL_PREFIX}<server>__<tool>\`).`,
16019
+ "These tools are exposed as first-class tool calls (e.g. mcp__filesystem__read_file).",
15910
16020
  ""
15911
16021
  ];
15912
16022
  for (const [server2, tools] of servers) {
15913
16023
  lines.push(`Server: ${server2}`);
15914
16024
  for (const t of tools) {
15915
16025
  const paramHint = t.params?.length ? ` (params: ${t.params.join(", ")})` : "";
15916
- lines.push(` - ${t.toolName}${paramHint}${t.description ? " " + t.description : ""}`);
15917
- }
15918
- if (tools.length > 0) {
15919
- const ex = tools[0];
15920
- const exArgs = ex.params?.length ? ` '{"${ex.params[0]}":"..."}'` : "";
15921
- lines.push(` Example: mcptool call ${server2} ${ex.toolName}${exArgs}`);
16026
+ const sourceHint = t.callName === t.toolName ? "" : ` (server: ${t.serverName}; tool: ${t.toolName})`;
16027
+ lines.push(` - ${t.callName}${paramHint}${t.description ? " — " + t.description : ""}${sourceHint}`);
15922
16028
  }
15923
16029
  lines.push("");
15924
16030
  }
@@ -15933,8 +16039,8 @@ function buildAvailableToolsSystemMessage(lastToolNames, lastToolMap, mcpToolDef
15933
16039
  `) : null;
15934
16040
  }
15935
16041
  async function ensurePluginDirectory() {
15936
- const configHome = process.env.XDG_CONFIG_HOME ? resolve2(process.env.XDG_CONFIG_HOME) : join6(homedir5(), ".config");
15937
- const pluginDir = join6(configHome, "opencode", "plugin");
16042
+ const configHome = process.env.XDG_CONFIG_HOME ? resolve2(process.env.XDG_CONFIG_HOME) : join5(homedir4(), ".config");
16043
+ const pluginDir = join5(configHome, "opencode", "plugin");
15938
16044
  try {
15939
16045
  await mkdir(pluginDir, { recursive: true });
15940
16046
  log20.debug("Plugin directory ensured", { path: pluginDir });
@@ -15951,8 +16057,8 @@ function getGlobalKey() {
15951
16057
  return "__opencode_cursor_proxy_server__";
15952
16058
  }
15953
16059
  function getOpenCodeConfigPrefix() {
15954
- const configHome = process.env.XDG_CONFIG_HOME ? resolve2(process.env.XDG_CONFIG_HOME) : join6(homedir5(), ".config");
15955
- return join6(configHome, "opencode");
16060
+ const configHome = process.env.XDG_CONFIG_HOME ? resolve2(process.env.XDG_CONFIG_HOME) : join5(homedir4(), ".config");
16061
+ return join5(configHome, "opencode");
15956
16062
  }
15957
16063
  function canonicalizePathForCompare(pathValue) {
15958
16064
  const resolvedPath = resolve2(pathValue);
@@ -16029,7 +16135,7 @@ function resolveWorkspaceDirectory(worktree, directory) {
16029
16135
  if (isAcceptableWorkspace(cwd, configPrefix)) {
16030
16136
  return cwd;
16031
16137
  }
16032
- const home = resolveCandidate(homedir5());
16138
+ const home = resolveCandidate(homedir4());
16033
16139
  if (home && !isRootPath(home)) {
16034
16140
  return home;
16035
16141
  }
@@ -16110,6 +16216,7 @@ function extractCompletionFromStream(output) {
16110
16216
  let usage;
16111
16217
  let sawAssistantPartials = false;
16112
16218
  let sawThinkingPartials = false;
16219
+ const tracker = new MixedDeltaTracker;
16113
16220
  for (const line of lines) {
16114
16221
  const event = parseStreamJsonLine(line);
16115
16222
  if (!event) {
@@ -16121,8 +16228,8 @@ function extractCompletionFromStream(output) {
16121
16228
  continue;
16122
16229
  const isPartial = typeof event.timestamp_ms === "number";
16123
16230
  if (isPartial) {
16124
- assistantText += text;
16125
16231
  sawAssistantPartials = true;
16232
+ assistantText += tracker.nextText(text);
16126
16233
  } else if (!sawAssistantPartials) {
16127
16234
  assistantText = text;
16128
16235
  }
@@ -16132,8 +16239,8 @@ function extractCompletionFromStream(output) {
16132
16239
  if (thinking) {
16133
16240
  const isPartial = typeof event.timestamp_ms === "number";
16134
16241
  if (isPartial) {
16135
- reasoningText += thinking;
16136
16242
  sawThinkingPartials = true;
16243
+ reasoningText += tracker.nextThinking(thinking);
16137
16244
  } else if (!sawThinkingPartials) {
16138
16245
  reasoningText = thinking;
16139
16246
  }
@@ -16330,7 +16437,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16330
16437
  const messages = Array.isArray(body?.messages) ? body.messages : [];
16331
16438
  const stream = body?.stream === true;
16332
16439
  const tools = Array.isArray(body?.tools) ? body.tools : [];
16333
- debugLogToFile2("raw_request_body", {
16440
+ log20.debug("raw request body", {
16334
16441
  model: body?.model,
16335
16442
  cursorModel: body?.cursorModel,
16336
16443
  stream,
@@ -16820,7 +16927,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16820
16927
  if (FORCE_TOOL_MODE) {
16821
16928
  cmd.push("--force");
16822
16929
  }
16823
- const child = spawn3(cmd[0], cmd.slice(1), {
16930
+ const child = spawn3(formatShellCommandForPlatform(cmd[0]), cmd.slice(1), {
16824
16931
  stdio: ["pipe", "pipe", "pipe"],
16825
16932
  shell: process.platform === "win32"
16826
16933
  });
@@ -16967,22 +17074,18 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16967
17074
  child.kill();
16968
17075
  } catch {}
16969
17076
  };
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) {
17077
+ const chunkQueue = [];
17078
+ let draining = false;
17079
+ let childClosed = false;
17080
+ let childCloseHandled = false;
17081
+ let childExitCode = null;
17082
+ const processLines = async (lines) => {
17083
+ for (const line of lines) {
17084
+ if (streamTerminated || res.writableEnded)
16980
17085
  break;
16981
- }
16982
17086
  const event = parseStreamJsonLine(line);
16983
- if (!event) {
17087
+ if (!event)
16984
17088
  continue;
16985
- }
16986
17089
  if (isResult(event)) {
16987
17090
  usage = extractOpenAiUsageFromResult(event) ?? usage;
16988
17091
  }
@@ -17031,148 +17134,100 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
17031
17134
  }
17032
17135
  break;
17033
17136
  }
17034
- if (result.intercepted) {
17137
+ if (result.intercepted)
17035
17138
  break;
17036
- }
17037
- if (result.skipConverter) {
17139
+ if (result.skipConverter)
17038
17140
  continue;
17039
- }
17040
17141
  }
17041
- if (streamTerminated || res.writableEnded) {
17142
+ if (streamTerminated || res.writableEnded)
17042
17143
  break;
17043
- }
17044
17144
  for (const sse of converter.handleEvent(event)) {
17045
17145
  res.write(sse);
17046
17146
  }
17047
17147
  }
17048
- });
17049
- child.on("close", async (code) => {
17050
- if (streamTerminated || res.writableEnded) {
17148
+ };
17149
+ const drainQueue = async () => {
17150
+ if (draining)
17051
17151
  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) {
17152
+ draining = true;
17153
+ try {
17154
+ while (chunkQueue.length > 0) {
17155
+ if (streamTerminated || res.writableEnded)
17109
17156
  break;
17157
+ const chunk = chunkQueue.shift();
17158
+ if (!firstTokenReceived) {
17159
+ perf.mark("first-token");
17160
+ firstTokenReceived = true;
17110
17161
  }
17111
- if (result.skipConverter) {
17112
- continue;
17113
- }
17114
- }
17115
- if (streamTerminated || res.writableEnded) {
17116
- break;
17117
- }
17118
- for (const sse of converter.handleEvent(event)) {
17119
- res.write(sse);
17162
+ await processLines(lineBuffer.push(chunk));
17120
17163
  }
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)}
17164
+ if (childClosed && !childCloseHandled && !streamTerminated && !res.writableEnded) {
17165
+ childCloseHandled = true;
17166
+ await processLines(lineBuffer.flush());
17167
+ if (streamTerminated || res.writableEnded)
17168
+ return;
17169
+ perf.mark("request:done");
17170
+ perf.summarize();
17171
+ const stderrText = Buffer.concat(stderrChunks).toString().trim();
17172
+ log20.debug("cursor-agent completed (node stream)", {
17173
+ code: childExitCode,
17174
+ stderrChars: stderrText.length
17175
+ });
17176
+ if (childExitCode !== 0) {
17177
+ const errSource = stderrText || `cursor-agent exited with code ${String(childExitCode ?? "unknown")} and no output`;
17178
+ const parsed = parseAgentError(errSource);
17179
+ const msg = formatErrorForUser(parsed);
17180
+ const errChunk = createChatCompletionChunk(id, created, model, msg, true);
17181
+ res.write(`data: ${JSON.stringify(errChunk)}
17138
17182
 
17139
17183
  `);
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"
17184
+ res.write(formatSseDone());
17185
+ streamTerminated = true;
17186
+ res.end();
17187
+ return;
17162
17188
  }
17163
- ]
17164
- };
17165
- res.write(`data: ${JSON.stringify(doneChunk)}
17189
+ const passThroughSummary = passThroughTracker.getSummary();
17190
+ if (passThroughSummary.hasActivity) {
17191
+ await toastService.showPassThroughSummary(passThroughSummary.tools);
17192
+ }
17193
+ if (passThroughSummary.errors.length > 0) {
17194
+ await toastService.showErrorSummary(passThroughSummary.errors);
17195
+ }
17196
+ const doneChunk = {
17197
+ id,
17198
+ object: "chat.completion.chunk",
17199
+ created,
17200
+ model,
17201
+ choices: [{ index: 0, delta: {}, finish_reason: "stop" }]
17202
+ };
17203
+ res.write(`data: ${JSON.stringify(doneChunk)}
17166
17204
 
17167
17205
  `);
17168
- if (usage) {
17169
- const usageChunk = createChatCompletionUsageChunk(id, created, model, usage);
17170
- res.write(`data: ${JSON.stringify(usageChunk)}
17206
+ if (usage) {
17207
+ const usageChunk = createChatCompletionUsageChunk(id, created, model, usage);
17208
+ res.write(`data: ${JSON.stringify(usageChunk)}
17171
17209
 
17172
17210
  `);
17211
+ }
17212
+ res.write(formatSseDone());
17213
+ streamTerminated = true;
17214
+ res.end();
17215
+ }
17216
+ } finally {
17217
+ draining = false;
17218
+ if (!streamTerminated && !res.writableEnded && (chunkQueue.length > 0 || childClosed && !childCloseHandled)) {
17219
+ drainQueue();
17220
+ }
17173
17221
  }
17174
- res.write(formatSseDone());
17175
- res.end();
17222
+ };
17223
+ child.stdout.on("data", (chunk) => {
17224
+ chunkQueue.push(Buffer.from(chunk));
17225
+ drainQueue();
17226
+ });
17227
+ child.on("close", (code) => {
17228
+ childClosed = true;
17229
+ childExitCode = code;
17230
+ drainQueue();
17176
17231
  });
17177
17232
  }
17178
17233
  } catch (error) {
@@ -17373,7 +17428,7 @@ function buildToolHookEntries(registry, fallbackBaseDir) {
17373
17428
  }
17374
17429
  return entries;
17375
17430
  }
17376
- var log20, DEBUG_LOG_DIR2, DEBUG_LOG_FILE2, CURSOR_PROVIDER_ID2 = "cursor-acp", CURSOR_PROVIDER_PREFIX, CURSOR_PROXY_HOST = "127.0.0.1", CURSOR_PROXY_DEFAULT_PORT = 32124, CURSOR_PROXY_DEFAULT_BASE_URL, REUSE_EXISTING_PROXY, SESSION_WORKSPACE_CACHE_LIMIT = 200, FORCE_TOOL_MODE, EMIT_TOOL_UPDATES, FORWARD_TOOL_CALLS, TOOL_LOOP_MODE_RAW, TOOL_LOOP_MODE, TOOL_LOOP_MODE_VALID, PROVIDER_BOUNDARY_MODE_RAW, PROVIDER_BOUNDARY_MODE, PROVIDER_BOUNDARY_MODE_VALID, LEGACY_PROVIDER_BOUNDARY, PROVIDER_BOUNDARY, ENABLE_PROVIDER_BOUNDARY_AUTOFALLBACK, TOOL_LOOP_MAX_REPEAT_RAW, TOOL_LOOP_MAX_REPEAT, TOOL_LOOP_MAX_REPEAT_VALID, PROXY_EXECUTE_TOOL_CALLS, SUPPRESS_CONVERTER_TOOL_EVENTS, SHOULD_EMIT_TOOL_UPDATES, NATIVE_TOOL_HOOK_EXCLUSIONS, CursorPlugin = async ({ $, directory, worktree, client: client3, serverUrl }) => {
17431
+ var log20, CURSOR_PROVIDER_ID2 = "cursor-acp", CURSOR_PROVIDER_PREFIX, CURSOR_PROXY_HOST = "127.0.0.1", CURSOR_PROXY_DEFAULT_PORT = 32124, CURSOR_PROXY_DEFAULT_BASE_URL, REUSE_EXISTING_PROXY, SESSION_WORKSPACE_CACHE_LIMIT = 200, FORCE_TOOL_MODE, EMIT_TOOL_UPDATES, FORWARD_TOOL_CALLS, TOOL_LOOP_MODE_RAW, TOOL_LOOP_MODE, TOOL_LOOP_MODE_VALID, PROVIDER_BOUNDARY_MODE_RAW, PROVIDER_BOUNDARY_MODE, PROVIDER_BOUNDARY_MODE_VALID, LEGACY_PROVIDER_BOUNDARY, PROVIDER_BOUNDARY, ENABLE_PROVIDER_BOUNDARY_AUTOFALLBACK, TOOL_LOOP_MAX_REPEAT_RAW, TOOL_LOOP_MAX_REPEAT, TOOL_LOOP_MAX_REPEAT_VALID, PROXY_EXECUTE_TOOL_CALLS, SUPPRESS_CONVERTER_TOOL_EVENTS, SHOULD_EMIT_TOOL_UPDATES, NATIVE_TOOL_HOOK_EXCLUSIONS, CursorPlugin = async ({ $, directory, worktree, client: client3, serverUrl }) => {
17377
17432
  const workspaceDirectory = resolveWorkspaceDirectory(worktree, directory);
17378
17433
  log20.debug("Plugin initializing", {
17379
17434
  directory,
@@ -17429,6 +17484,7 @@ var log20, DEBUG_LOG_DIR2, DEBUG_LOG_FILE2, CURSOR_PROVIDER_ID2 = "cursor-acp",
17429
17484
  mcpToolSummaries = tools.map((t) => ({
17430
17485
  serverName: t.serverName,
17431
17486
  toolName: t.name,
17487
+ callName: namespaceMcpTool(t.serverName, t.name),
17432
17488
  description: t.description,
17433
17489
  params: t.inputSchema ? Object.keys(t.inputSchema.properties ?? {}) : undefined
17434
17490
  }));
@@ -17646,8 +17702,6 @@ var init_plugin = __esm(() => {
17646
17702
  init_tool_loop_guard();
17647
17703
  init_binary();
17648
17704
  log20 = createLogger("plugin");
17649
- DEBUG_LOG_DIR2 = join6(homedir5(), ".config", "opencode", "logs");
17650
- DEBUG_LOG_FILE2 = join6(DEBUG_LOG_DIR2, "tool-loop-debug.log");
17651
17705
  CURSOR_PROVIDER_PREFIX = `${CURSOR_PROVIDER_ID2}/`;
17652
17706
  CURSOR_PROXY_DEFAULT_BASE_URL = `http://${CURSOR_PROXY_HOST}:${CURSOR_PROXY_DEFAULT_PORT}/v1`;
17653
17707
  REUSE_EXISTING_PROXY = process.env.CURSOR_ACP_REUSE_EXISTING_PROXY !== "false";
@@ -17727,7 +17781,7 @@ class SimpleCursorClient {
17727
17781
  args.push("--resume", resumeId);
17728
17782
  }
17729
17783
  this.log.debug("Executing prompt stream", { promptLength: prompt.length, mode, model });
17730
- const child = spawn3(this.config.cursorAgentPath, args, {
17784
+ const child = spawn3(formatShellCommandForPlatform(this.config.cursorAgentPath), args, {
17731
17785
  cwd,
17732
17786
  stdio: ["pipe", "pipe", "pipe"],
17733
17787
  shell: process.platform === "win32"
@@ -17814,7 +17868,7 @@ class SimpleCursorClient {
17814
17868
  }
17815
17869
  this.log.debug("Executing prompt", { promptLength: prompt.length, mode, model });
17816
17870
  return new Promise((resolve3, reject) => {
17817
- const child = spawn3(this.config.cursorAgentPath, args, {
17871
+ const child = spawn3(formatShellCommandForPlatform(this.config.cursorAgentPath), args, {
17818
17872
  cwd,
17819
17873
  stdio: ["pipe", "pipe", "pipe"],
17820
17874
  shell: process.platform === "win32"
@@ -18063,42 +18117,22 @@ function createProxyServer(config) {
18063
18117
 
18064
18118
  // src/streaming/ai-sdk-parts.ts
18065
18119
  class StreamToAiSdkParts {
18066
- tracker = new DeltaTracker;
18067
18120
  toolArgsById = new Map;
18068
18121
  startedToolIds = new Set;
18069
- sawAssistantPartials = false;
18070
- sawThinkingPartials = false;
18122
+ tracker = new MixedDeltaTracker;
18071
18123
  handleEvent(event) {
18072
18124
  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) {
18125
+ const text = extractText(event);
18126
+ if (!text)
18083
18127
  return [];
18084
- }
18085
- const delta = this.tracker.nextText(extractText(event));
18128
+ const delta = this.tracker.nextText(text);
18086
18129
  return delta ? [{ type: "text-delta", textDelta: delta }] : [];
18087
18130
  }
18088
18131
  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) {
18132
+ const text = extractThinking(event);
18133
+ if (!text)
18099
18134
  return [];
18100
- }
18101
- const delta = this.tracker.nextThinking(extractThinking(event));
18135
+ const delta = this.tracker.nextThinking(text);
18102
18136
  return delta ? [{ type: "text-delta", textDelta: delta }] : [];
18103
18137
  }
18104
18138
  if (isToolCall(event)) {
@@ -18400,11 +18434,11 @@ init_auth();
18400
18434
  // src/commands/status.ts
18401
18435
  init_auth();
18402
18436
  init_logger();
18403
- import { existsSync as existsSync6 } from "fs";
18437
+ import { existsSync as existsSync4 } from "fs";
18404
18438
  var log22 = createLogger("status");
18405
18439
  function checkAuthStatus() {
18406
18440
  const authFilePath = getAuthFilePath();
18407
- const exists = existsSync6(authFilePath);
18441
+ const exists = existsSync4(authFilePath);
18408
18442
  log22.debug("Checking auth status", { path: authFilePath });
18409
18443
  if (exists) {
18410
18444
  return {