@rama_nigg/open-cursor 2.3.20 → 2.4.0

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.
@@ -71,6 +71,11 @@ function isCursorPluginEnabledInConfig(config) {
71
71
  return true;
72
72
  }
73
73
  const configObject = config;
74
+ if (configObject.provider && typeof configObject.provider === "object") {
75
+ if (CURSOR_PROVIDER_ID in configObject.provider) {
76
+ return true;
77
+ }
78
+ }
74
79
  if (Array.isArray(configObject.plugin)) {
75
80
  return configObject.plugin.some((entry) => matchesPlugin(entry));
76
81
  }
@@ -92,7 +97,7 @@ function shouldEnableCursorPlugin(env = process.env) {
92
97
  return {
93
98
  enabled,
94
99
  configPath,
95
- reason: enabled ? "enabled_in_plugin_array_or_legacy" : "disabled_in_plugin_array"
100
+ reason: enabled ? "enabled" : "disabled_in_plugin_array"
96
101
  };
97
102
  } catch {
98
103
  return {
@@ -480,11 +485,52 @@ function formatErrorForUser(error) {
480
485
  return output;
481
486
  }
482
487
 
488
+ // src/utils/binary.ts
489
+ import { existsSync as fsExistsSync } from "fs";
490
+ import * as pathModule from "path";
491
+ import { homedir as osHomedir } from "os";
492
+ function resolveCursorAgentBinary(deps = {}) {
493
+ const platform = deps.platform ?? process.platform;
494
+ const env = deps.env ?? process.env;
495
+ const checkExists = deps.existsSync ?? fsExistsSync;
496
+ const home = (deps.homedir ?? osHomedir)();
497
+ const envOverride = env.CURSOR_AGENT_EXECUTABLE;
498
+ if (envOverride && envOverride.length > 0) {
499
+ return envOverride;
500
+ }
501
+ if (platform === "win32") {
502
+ const pathJoin = pathModule.win32.join;
503
+ const localAppData = env.LOCALAPPDATA ?? pathJoin(home, "AppData", "Local");
504
+ const knownPath = pathJoin(localAppData, "cursor-agent", "cursor-agent.cmd");
505
+ if (checkExists(knownPath)) {
506
+ return knownPath;
507
+ }
508
+ log.warn("cursor-agent not found at known Windows path, falling back to PATH", { checkedPath: knownPath });
509
+ return "cursor-agent.cmd";
510
+ }
511
+ const knownPaths = [
512
+ pathModule.join(home, ".cursor-agent", "cursor-agent"),
513
+ "/usr/local/bin/cursor-agent"
514
+ ];
515
+ for (const p of knownPaths) {
516
+ if (checkExists(p)) {
517
+ return p;
518
+ }
519
+ }
520
+ log.warn("cursor-agent not found at known paths, falling back to PATH", { checkedPaths: knownPaths });
521
+ return "cursor-agent";
522
+ }
523
+ var log;
524
+ var init_binary = __esm(() => {
525
+ init_logger();
526
+ log = createLogger("binary");
527
+ });
528
+
483
529
  // src/auth.ts
484
530
  import { spawn } from "child_process";
485
531
  import { existsSync as existsSync3 } from "fs";
486
532
  import { homedir as homedir3, platform } from "os";
487
- import { join as join3 } from "path";
533
+ import { join as join4 } from "path";
488
534
  function getHomeDir() {
489
535
  const override = process.env.CURSOR_ACP_HOME_DIR;
490
536
  if (override && override.length > 0) {
@@ -500,18 +546,18 @@ async function pollForAuthFile(timeoutMs = AUTH_POLL_TIMEOUT, intervalMs = AUTH_
500
546
  const elapsed = Date.now() - startTime;
501
547
  for (const authPath of possiblePaths) {
502
548
  if (existsSync3(authPath)) {
503
- log.debug("Auth file detected", { path: authPath });
549
+ log2.debug("Auth file detected", { path: authPath });
504
550
  resolve2(true);
505
551
  return;
506
552
  }
507
553
  }
508
- log.debug("Polling for auth file", {
554
+ log2.debug("Polling for auth file", {
509
555
  checkedPaths: possiblePaths,
510
556
  elapsed: `${elapsed}ms`,
511
557
  timeout: `${timeoutMs}ms`
512
558
  });
513
559
  if (elapsed >= timeoutMs) {
514
- log.debug("Auth file polling timed out");
560
+ log2.debug("Auth file polling timed out");
515
561
  resolve2(false);
516
562
  return;
517
563
  }
@@ -522,9 +568,10 @@ async function pollForAuthFile(timeoutMs = AUTH_POLL_TIMEOUT, intervalMs = AUTH_
522
568
  }
523
569
  async function startCursorOAuth() {
524
570
  return new Promise((resolve2, reject) => {
525
- log.info("Starting cursor-cli login process");
526
- const proc = spawn("cursor-agent", ["login"], {
527
- stdio: ["pipe", "pipe", "pipe"]
571
+ log2.info("Starting cursor-cli login process");
572
+ const proc = spawn(resolveCursorAgentBinary(), ["login"], {
573
+ stdio: ["pipe", "pipe", "pipe"],
574
+ shell: process.platform === "win32"
528
575
  });
529
576
  let stdout = "";
530
577
  let stderr = "";
@@ -548,9 +595,9 @@ async function startCursorOAuth() {
548
595
  const url = extractUrl();
549
596
  if (url && !urlExtracted) {
550
597
  urlExtracted = true;
551
- log.debug("Captured stdout", { length: stdout.length });
552
- log.debug("Extracted URL", { url: url.substring(0, 50) + "..." });
553
- log.info("Got login URL, waiting for browser auth");
598
+ log2.debug("Captured stdout", { length: stdout.length });
599
+ log2.debug("Extracted URL", { url: url.substring(0, 50) + "..." });
600
+ log2.info("Got login URL, waiting for browser auth");
554
601
  resolve2({
555
602
  url,
556
603
  instructions: "Click 'Continue with Cursor' in your browser to authenticate",
@@ -564,26 +611,26 @@ async function startCursorOAuth() {
564
611
  }
565
612
  };
566
613
  proc.on("close", async (code) => {
567
- log.debug("Login process closed", { code });
614
+ log2.debug("Login process closed", { code });
568
615
  if (code === 0) {
569
- log.info("Process exited successfully, polling for auth file...");
616
+ log2.info("Process exited successfully, polling for auth file...");
570
617
  const isAuthenticated = await pollForAuthFile();
571
618
  if (isAuthenticated) {
572
- log.info("Authentication successful");
619
+ log2.info("Authentication successful");
573
620
  resolveOnce({
574
621
  type: "success",
575
622
  provider: "cursor-acp",
576
623
  key: "cursor-auth"
577
624
  });
578
625
  } else {
579
- log.warn("Auth file not found after polling");
626
+ log2.warn("Auth file not found after polling");
580
627
  resolveOnce({
581
628
  type: "failed",
582
629
  error: "Authentication was not completed. Please try again."
583
630
  });
584
631
  }
585
632
  } else {
586
- log.warn("Login process failed", { code });
633
+ log2.warn("Login process failed", { code });
587
634
  resolveOnce({
588
635
  type: "failed",
589
636
  error: stderr ? stripAnsi(stderr) : `Authentication failed with code ${code}`
@@ -591,7 +638,7 @@ async function startCursorOAuth() {
591
638
  }
592
639
  });
593
640
  setTimeout(() => {
594
- log.warn("Authentication timed out after 5 minutes");
641
+ log2.warn("Authentication timed out after 5 minutes");
595
642
  proc.kill();
596
643
  resolveOnce({
597
644
  type: "failed",
@@ -611,7 +658,7 @@ async function startCursorOAuth() {
611
658
  if (elapsed >= URL_EXTRACTION_TIMEOUT) {
612
659
  proc.kill();
613
660
  const errorMsg = stderr ? stripAnsi(stderr) : "No login URL received within timeout";
614
- log.error("Failed to extract login URL", { error: errorMsg, elapsed: `${elapsed}ms` });
661
+ log2.error("Failed to extract login URL", { error: errorMsg, elapsed: `${elapsed}ms` });
615
662
  reject(new Error(`Failed to get login URL: ${errorMsg}`));
616
663
  return;
617
664
  }
@@ -627,11 +674,11 @@ function verifyCursorAuth() {
627
674
  const possiblePaths = getPossibleAuthPaths();
628
675
  for (const authPath of possiblePaths) {
629
676
  if (existsSync3(authPath)) {
630
- log.debug("Auth file found", { path: authPath });
677
+ log2.debug("Auth file found", { path: authPath });
631
678
  return true;
632
679
  }
633
680
  }
634
- log.debug("No auth file found", { checkedPaths: possiblePaths });
681
+ log2.debug("No auth file found", { checkedPaths: possiblePaths });
635
682
  return false;
636
683
  }
637
684
  function getPossibleAuthPaths() {
@@ -641,23 +688,23 @@ function getPossibleAuthPaths() {
641
688
  const authFiles = ["cli-config.json", "auth.json"];
642
689
  if (isDarwin) {
643
690
  for (const file of authFiles) {
644
- paths.push(join3(home, ".cursor", file));
691
+ paths.push(join4(home, ".cursor", file));
645
692
  }
646
693
  for (const file of authFiles) {
647
- paths.push(join3(home, ".config", "cursor", file));
694
+ paths.push(join4(home, ".config", "cursor", file));
648
695
  }
649
696
  } else {
650
697
  for (const file of authFiles) {
651
- paths.push(join3(home, ".config", "cursor", file));
698
+ paths.push(join4(home, ".config", "cursor", file));
652
699
  }
653
700
  const xdgConfig = process.env.XDG_CONFIG_HOME;
654
- if (xdgConfig && xdgConfig !== join3(home, ".config")) {
701
+ if (xdgConfig && xdgConfig !== join4(home, ".config")) {
655
702
  for (const file of authFiles) {
656
- paths.push(join3(xdgConfig, "cursor", file));
703
+ paths.push(join4(xdgConfig, "cursor", file));
657
704
  }
658
705
  }
659
706
  for (const file of authFiles) {
660
- paths.push(join3(home, ".cursor", file));
707
+ paths.push(join4(home, ".cursor", file));
661
708
  }
662
709
  }
663
710
  return paths;
@@ -671,10 +718,11 @@ function getAuthFilePath() {
671
718
  }
672
719
  return possiblePaths[0];
673
720
  }
674
- var log, AUTH_POLL_INTERVAL = 2000, AUTH_POLL_TIMEOUT, URL_EXTRACTION_TIMEOUT = 1e4;
721
+ var log2, AUTH_POLL_INTERVAL = 2000, AUTH_POLL_TIMEOUT, URL_EXTRACTION_TIMEOUT = 1e4;
675
722
  var init_auth = __esm(() => {
676
723
  init_logger();
677
- log = createLogger("auth");
724
+ init_binary();
725
+ log2 = createLogger("auth");
678
726
  AUTH_POLL_TIMEOUT = 5 * 60 * 1000;
679
727
  });
680
728
 
@@ -721,7 +769,7 @@ var hasTextContent = (event) => event.message.content.some((content) => content.
721
769
  return true;
722
770
  }
723
771
  return event.type === "assistant" && hasThinkingContent(event);
724
- }, isToolCall = (event) => event.type === "tool_call", extractText = (event) => event.message.content.filter((content) => content.type === "text").map((content) => content.text).join(""), extractThinking = (event) => {
772
+ }, 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) => {
725
773
  if (event.type === "thinking") {
726
774
  return event.text ?? "";
727
775
  }
@@ -870,7 +918,7 @@ var createChunk = (id, created, model, delta) => ({
870
918
  var init_openai_sse = () => {};
871
919
 
872
920
  // src/streaming/parser.ts
873
- var log2, parseStreamJsonLine = (line) => {
921
+ var log3, parseStreamJsonLine = (line) => {
874
922
  const trimmed = line.trim();
875
923
  if (!trimmed) {
876
924
  return null;
@@ -882,15 +930,82 @@ var log2, parseStreamJsonLine = (line) => {
882
930
  }
883
931
  return parsed;
884
932
  } catch {
885
- log2.debug("Failed to parse NDJSON line", { line: trimmed.substring(0, 100) });
933
+ log3.debug("Failed to parse NDJSON line", { line: trimmed.substring(0, 100) });
886
934
  return null;
887
935
  }
888
936
  };
889
937
  var init_parser = __esm(() => {
890
938
  init_logger();
891
- log2 = createLogger("streaming:parser");
939
+ log3 = createLogger("streaming:parser");
892
940
  });
893
941
 
942
+ // src/usage.ts
943
+ function readTokenCount(value) {
944
+ if (typeof value !== "number" || !Number.isFinite(value) || value < 0) {
945
+ return 0;
946
+ }
947
+ return Math.floor(value);
948
+ }
949
+ function readOptionalCost(value) {
950
+ if (typeof value !== "number" || !Number.isFinite(value) || value < 0) {
951
+ return;
952
+ }
953
+ return value;
954
+ }
955
+ function normalizeCursorUsage(value) {
956
+ if (!value || typeof value !== "object") {
957
+ return;
958
+ }
959
+ const usage = value;
960
+ const metrics = {
961
+ inputTokens: readTokenCount(usage.inputTokens ?? usage.input_tokens ?? usage.prompt_tokens),
962
+ outputTokens: readTokenCount(usage.outputTokens ?? usage.output_tokens ?? usage.completion_tokens),
963
+ reasoningTokens: readTokenCount(usage.reasoningTokens ?? usage.reasoning_tokens),
964
+ cacheReadTokens: readTokenCount(usage.cacheReadTokens ?? usage.cache_read_tokens),
965
+ cacheWriteTokens: readTokenCount(usage.cacheWriteTokens ?? usage.cache_write_tokens)
966
+ };
967
+ const cost = readOptionalCost(usage.cost ?? usage.totalCost ?? usage.total_cost);
968
+ if (cost !== undefined) {
969
+ metrics.cost = cost;
970
+ }
971
+ const hasUsage = metrics.inputTokens > 0 || metrics.outputTokens > 0 || metrics.reasoningTokens > 0 || metrics.cacheReadTokens > 0 || metrics.cacheWriteTokens > 0 || cost !== undefined;
972
+ return hasUsage ? metrics : undefined;
973
+ }
974
+ function createOpenAiUsage(metrics) {
975
+ const promptTokens = metrics.inputTokens + metrics.cacheReadTokens + metrics.cacheWriteTokens;
976
+ const totalTokens = promptTokens + metrics.outputTokens + metrics.reasoningTokens;
977
+ const usage = {
978
+ prompt_tokens: promptTokens,
979
+ completion_tokens: metrics.outputTokens,
980
+ total_tokens: totalTokens,
981
+ prompt_tokens_details: {
982
+ cached_tokens: metrics.cacheReadTokens,
983
+ cache_write_tokens: metrics.cacheWriteTokens
984
+ },
985
+ completion_tokens_details: {
986
+ reasoning_tokens: metrics.reasoningTokens
987
+ }
988
+ };
989
+ if (metrics.cost !== undefined) {
990
+ usage.cost = metrics.cost;
991
+ }
992
+ return usage;
993
+ }
994
+ function extractOpenAiUsageFromResult(event) {
995
+ const metrics = normalizeCursorUsage(event.usage);
996
+ return metrics ? createOpenAiUsage(metrics) : undefined;
997
+ }
998
+ function createChatCompletionUsageChunk(id, created, model, usage) {
999
+ return {
1000
+ id,
1001
+ object: "chat.completion.chunk",
1002
+ created,
1003
+ model,
1004
+ choices: [],
1005
+ usage
1006
+ };
1007
+ }
1008
+
894
1009
  // src/utils/perf.ts
895
1010
  class RequestPerf {
896
1011
  markers = [];
@@ -911,7 +1026,7 @@ class RequestPerf {
911
1026
  phases[this.markers[i].name] = this.markers[i].ts - this.markers[i - 1].ts;
912
1027
  }
913
1028
  const total = this.markers[this.markers.length - 1].ts - start;
914
- log3.debug("Request timing", { requestId: this.requestId, total, phases });
1029
+ log4.debug("Request timing", { requestId: this.requestId, total, phases });
915
1030
  }
916
1031
  elapsed() {
917
1032
  return this.markers.length > 0 ? Date.now() - this.markers[0].ts : 0;
@@ -920,16 +1035,16 @@ class RequestPerf {
920
1035
  return this.markers;
921
1036
  }
922
1037
  }
923
- var log3;
1038
+ var log4;
924
1039
  var init_perf = __esm(() => {
925
1040
  init_logger();
926
- log3 = createLogger("perf");
1041
+ log4 = createLogger("perf");
927
1042
  });
928
1043
 
929
1044
  // src/proxy/prompt-builder.ts
930
1045
  import { appendFileSync as appendFileSync2, existsSync as existsSync4, mkdirSync as mkdirSync2 } from "node:fs";
931
1046
  import { homedir as homedir4 } from "node:os";
932
- import { join as join4 } from "node:path";
1047
+ import { join as join5 } from "node:path";
933
1048
  function ensureLogDir2() {
934
1049
  try {
935
1050
  if (!existsSync4(DEBUG_LOG_DIR)) {
@@ -945,7 +1060,7 @@ function debugLogToFile(message, data) {
945
1060
  `;
946
1061
  appendFileSync2(DEBUG_LOG_FILE, logLine);
947
1062
  } catch (err) {
948
- log4.debug(message, data);
1063
+ log5.debug(message, data);
949
1064
  }
950
1065
  }
951
1066
  function buildPromptFromMessages(messages, tools, subagentNames = []) {
@@ -1066,12 +1181,12 @@ ${toolDescs}`);
1066
1181
  });
1067
1182
  return finalPrompt;
1068
1183
  }
1069
- var log4, DEBUG_LOG_DIR, DEBUG_LOG_FILE;
1184
+ var log5, DEBUG_LOG_DIR, DEBUG_LOG_FILE;
1070
1185
  var init_prompt_builder = __esm(() => {
1071
1186
  init_logger();
1072
- log4 = createLogger("proxy:prompt-builder");
1073
- DEBUG_LOG_DIR = join4(homedir4(), ".config", "opencode", "logs");
1074
- DEBUG_LOG_FILE = join4(DEBUG_LOG_DIR, "tool-loop-debug.log");
1187
+ log5 = createLogger("proxy:prompt-builder");
1188
+ DEBUG_LOG_DIR = join5(homedir4(), ".config", "opencode", "logs");
1189
+ DEBUG_LOG_FILE = join5(DEBUG_LOG_DIR, "tool-loop-debug.log");
1075
1190
  });
1076
1191
 
1077
1192
  // src/proxy/tool-loop.ts
@@ -1099,7 +1214,7 @@ function extractOpenAiToolCall(event, allowedToolNames) {
1099
1214
  const resolvedName = resolveAllowedToolName(name, allowedToolNames);
1100
1215
  if (resolvedName) {
1101
1216
  if (args === undefined && event.subtype === "started") {
1102
- log5.debug("Tool call args extraction returned undefined", {
1217
+ log6.debug("Tool call args extraction returned undefined", {
1103
1218
  toolName: name,
1104
1219
  subtype: event.subtype ?? "none",
1105
1220
  payloadKeys: Object.entries(event.tool_call || {}).map(([k, v]) => `${k}:[${isRecord(v) ? Object.keys(v).join(",") : typeof v}]`),
@@ -1119,7 +1234,7 @@ function extractOpenAiToolCall(event, allowedToolNames) {
1119
1234
  }
1120
1235
  };
1121
1236
  }
1122
- log5.debug("Tool call not in allowlist; passing through to cursor-agent", {
1237
+ log6.debug("Tool call not in allowlist; passing through to cursor-agent", {
1123
1238
  name,
1124
1239
  normalized: normalizeAliasKey(name),
1125
1240
  allowedToolCount: allowedToolNames.size
@@ -1268,10 +1383,10 @@ function toOpenAiArguments(args) {
1268
1383
  function isRecord(value) {
1269
1384
  return typeof value === "object" && value !== null && !Array.isArray(value);
1270
1385
  }
1271
- var log5, TOOL_NAME_ALIASES;
1386
+ var log6, TOOL_NAME_ALIASES;
1272
1387
  var init_tool_loop = __esm(() => {
1273
1388
  init_logger();
1274
- log5 = createLogger("proxy:tool-loop");
1389
+ log6 = createLogger("proxy:tool-loop");
1275
1390
  TOOL_NAME_ALIASES = new Map([
1276
1391
  ["runcommand", "bash"],
1277
1392
  ["executecommand", "bash"],
@@ -1385,7 +1500,7 @@ class OpenCodeToolDiscovery {
1385
1500
  const mcpTools = await this.tryListMcpTools();
1386
1501
  tools = tools.concat(mcpTools);
1387
1502
  } catch (err) {
1388
- log6.debug("SDK tool.list failed, will try CLI", { error: String(err) });
1503
+ log7.debug("SDK tool.list failed, will try CLI", { error: String(err) });
1389
1504
  }
1390
1505
  }
1391
1506
  if (tools.length === 0 && this.executorPref !== "sdk") {
@@ -1397,10 +1512,10 @@ class OpenCodeToolDiscovery {
1397
1512
  if (parsed?.data?.tools?.length) {
1398
1513
  tools = parsed.data.tools.map((t) => this.normalize(t, "cli"));
1399
1514
  } else {
1400
- log6.debug("CLI tool list failed", { status: res.status, stderr: res.stderr });
1515
+ log7.debug("CLI tool list failed", { status: res.status, stderr: res.stderr });
1401
1516
  }
1402
1517
  } catch (err) {
1403
- log6.debug("CLI tool list error", { error: String(err) });
1518
+ log7.debug("CLI tool list error", { error: String(err) });
1404
1519
  }
1405
1520
  }
1406
1521
  const map = new Map;
@@ -1436,7 +1551,7 @@ class OpenCodeToolDiscovery {
1436
1551
  return [];
1437
1552
  return mcpList.data.tools.map((t) => this.normalize(t, "mcp"));
1438
1553
  } catch (err) {
1439
- log6.debug("MCP tool discovery skipped", { error: String(err) });
1554
+ log7.debug("MCP tool discovery skipped", { error: String(err) });
1440
1555
  return [];
1441
1556
  }
1442
1557
  }
@@ -1457,11 +1572,11 @@ class OpenCodeToolDiscovery {
1457
1572
  return null;
1458
1573
  }
1459
1574
  }
1460
- var log6;
1575
+ var log7;
1461
1576
  var init_discovery = __esm(() => {
1462
1577
  init_logger();
1463
1578
  init_strip_ansi();
1464
- log6 = createLogger("tools:discovery");
1579
+ log7 = createLogger("tools:discovery");
1465
1580
  });
1466
1581
 
1467
1582
  // src/tools/schema.ts
@@ -1518,10 +1633,10 @@ function describeTool(t) {
1518
1633
  const base = t.description || "OpenCode tool";
1519
1634
  return base.length > 400 ? base.slice(0, 400) : base;
1520
1635
  }
1521
- var log7;
1636
+ var log8;
1522
1637
  var init_schema = __esm(() => {
1523
1638
  init_logger();
1524
- log7 = createLogger("tools:schema");
1639
+ log8 = createLogger("tools:schema");
1525
1640
  });
1526
1641
 
1527
1642
  // src/tools/router.ts
@@ -1546,18 +1661,18 @@ class ToolRouter {
1546
1661
  }
1547
1662
  const tool = this.ctx.toolsByName.get(name);
1548
1663
  if (!tool) {
1549
- log8.warn("Unknown tool call", { name });
1664
+ log9.warn("Unknown tool call", { name });
1550
1665
  return this.buildResult(meta, callId, name, { status: "error", error: `Unknown tool ${name}` });
1551
1666
  }
1552
1667
  const args = this.extractArgs(event);
1553
- log8.debug("Executing tool", { name, toolId: tool.id });
1668
+ log9.debug("Executing tool", { name, toolId: tool.id });
1554
1669
  const t0 = Date.now();
1555
1670
  const result = await this.ctx.execute(tool.id, args);
1556
1671
  const elapsed = Date.now() - t0;
1557
1672
  if (result.status === "error") {
1558
- log8.warn("Tool execution returned error", { name, error: result.error, elapsed });
1673
+ log9.warn("Tool execution returned error", { name, error: result.error, elapsed });
1559
1674
  } else {
1560
- log8.debug("Tool execution completed", { name, toolId: tool.id, elapsed });
1675
+ log9.debug("Tool execution completed", { name, toolId: tool.id, elapsed });
1561
1676
  }
1562
1677
  return this.buildResult(meta, callId, name, result);
1563
1678
  }
@@ -1606,10 +1721,10 @@ class ToolRouter {
1606
1721
  };
1607
1722
  }
1608
1723
  }
1609
- var log8;
1724
+ var log9;
1610
1725
  var init_router = __esm(() => {
1611
1726
  init_logger();
1612
- log8 = createLogger("tools:router");
1727
+ log9 = createLogger("tools:router");
1613
1728
  });
1614
1729
 
1615
1730
  // src/tools/skills/loader.ts
@@ -1710,9 +1825,9 @@ function parseCursorModelsOutput(output) {
1710
1825
  return models;
1711
1826
  }
1712
1827
  function discoverModelsFromCursorAgent() {
1713
- const raw = execFileSync("cursor-agent", ["models"], {
1828
+ const raw = execFileSync(resolveCursorAgentBinary(), ["models"], {
1714
1829
  encoding: "utf8",
1715
- killSignal: "SIGTERM",
1830
+ ...process.platform !== "win32" && { killSignal: "SIGTERM" },
1716
1831
  stdio: ["ignore", "pipe", "pipe"],
1717
1832
  timeout: MODEL_DISCOVERY_TIMEOUT_MS
1718
1833
  });
@@ -1747,7 +1862,9 @@ function fallbackModels() {
1747
1862
  ];
1748
1863
  }
1749
1864
  var MODEL_DISCOVERY_TIMEOUT_MS = 5000;
1750
- var init_model_discovery = () => {};
1865
+ var init_model_discovery = __esm(() => {
1866
+ init_binary();
1867
+ });
1751
1868
 
1752
1869
  // src/models/sync.ts
1753
1870
  import {
@@ -1838,18 +1955,18 @@ async function autoRefreshModels(deps = {}) {
1838
1955
  resolvedDeps.log.debug("Model auto-refresh failed", { error: String(err) });
1839
1956
  }
1840
1957
  }
1841
- var log9, PROVIDER_ID = "cursor-acp", defaultDeps;
1958
+ var log10, PROVIDER_ID = "cursor-acp", defaultDeps;
1842
1959
  var init_sync = __esm(() => {
1843
1960
  init_model_discovery();
1844
1961
  init_plugin_toggle();
1845
1962
  init_logger();
1846
- log9 = createLogger("model-sync");
1963
+ log10 = createLogger("model-sync");
1847
1964
  defaultDeps = {
1848
1965
  defer: () => Promise.resolve(),
1849
1966
  discoverModels: discoverModelsFromCursorAgent,
1850
1967
  env: process.env,
1851
1968
  existsSync: nodeExistsSync,
1852
- log: log9,
1969
+ log: log10,
1853
1970
  readFileSync: nodeReadFileSync,
1854
1971
  writeFileSync: nodeWriteFileSync
1855
1972
  };
@@ -1910,7 +2027,7 @@ function readMcpConfigs(deps = {}) {
1910
2027
  timeout: typeof e.timeout === "number" ? e.timeout : undefined
1911
2028
  });
1912
2029
  } else {
1913
- log10.debug("Skipping unrecognised MCP config entry", { name, type: e.type });
2030
+ log11.debug("Skipping unrecognised MCP config entry", { name, type: e.type });
1914
2031
  }
1915
2032
  }
1916
2033
  return configs;
@@ -1954,11 +2071,11 @@ function readSubagentNames(deps = {}) {
1954
2071
  function isStringRecord(v) {
1955
2072
  return typeof v === "object" && v !== null && !Array.isArray(v);
1956
2073
  }
1957
- var log10;
2074
+ var log11;
1958
2075
  var init_config = __esm(() => {
1959
2076
  init_plugin_toggle();
1960
2077
  init_logger();
1961
- log10 = createLogger("mcp:config");
2078
+ log11 = createLogger("mcp:config");
1962
2079
  });
1963
2080
 
1964
2081
  // node_modules/@modelcontextprotocol/sdk/dist/esm/server/zod-compat.js
@@ -8095,11 +8212,11 @@ var require_core = __commonJS((exports) => {
8095
8212
  Ajv.ValidationError = validation_error_1.default;
8096
8213
  Ajv.MissingRefError = ref_error_1.default;
8097
8214
  exports.default = Ajv;
8098
- function checkOptions(checkOpts, options, msg, log11 = "error") {
8215
+ function checkOptions(checkOpts, options, msg, log12 = "error") {
8099
8216
  for (const key in checkOpts) {
8100
8217
  const opt = key;
8101
8218
  if (opt in options)
8102
- this.logger[log11](`${msg}: option ${key}. ${checkOpts[opt]}`);
8219
+ this.logger[log12](`${msg}: option ${key}. ${checkOpts[opt]}`);
8103
8220
  }
8104
8221
  }
8105
8222
  function getSchEnv(keyRef) {
@@ -11716,14 +11833,14 @@ class McpClientManager {
11716
11833
  }
11717
11834
  async connectServer(config) {
11718
11835
  if (this.connections.has(config.name)) {
11719
- log11.debug("Server already connected, skipping", { server: config.name });
11836
+ log12.debug("Server already connected, skipping", { server: config.name });
11720
11837
  return;
11721
11838
  }
11722
11839
  if (!this.deps) {
11723
11840
  try {
11724
11841
  this.deps = await loadDefaultDeps();
11725
11842
  } catch (err) {
11726
- log11.warn("Failed to load MCP SDK", { error: String(err) });
11843
+ log12.warn("Failed to load MCP SDK", { error: String(err) });
11727
11844
  return;
11728
11845
  }
11729
11846
  }
@@ -11734,7 +11851,7 @@ class McpClientManager {
11734
11851
  const transport = deps.createTransport(config);
11735
11852
  await client.connect(transport);
11736
11853
  } catch (err) {
11737
- log11.warn("MCP server connection failed", {
11854
+ log12.warn("MCP server connection failed", {
11738
11855
  server: config.name,
11739
11856
  error: String(err)
11740
11857
  });
@@ -11744,12 +11861,12 @@ class McpClientManager {
11744
11861
  try {
11745
11862
  const result = await client.listTools();
11746
11863
  tools = result?.tools ?? [];
11747
- log11.info("MCP server connected", {
11864
+ log12.info("MCP server connected", {
11748
11865
  server: config.name,
11749
11866
  tools: tools.length
11750
11867
  });
11751
11868
  } catch (err) {
11752
- log11.warn("MCP tool discovery failed", {
11869
+ log12.warn("MCP tool discovery failed", {
11753
11870
  server: config.name,
11754
11871
  error: String(err)
11755
11872
  });
@@ -11781,7 +11898,7 @@ class McpClientManager {
11781
11898
  }
11782
11899
  return typeof result === "string" ? result : JSON.stringify(result);
11783
11900
  } catch (err) {
11784
- log11.warn("MCP tool call failed", {
11901
+ log12.warn("MCP tool call failed", {
11785
11902
  server: serverName,
11786
11903
  tool: toolName,
11787
11904
  error: String(err?.message || err)
@@ -11793,9 +11910,9 @@ class McpClientManager {
11793
11910
  for (const [name, conn] of this.connections) {
11794
11911
  try {
11795
11912
  await conn.client.close();
11796
- log11.debug("MCP server disconnected", { server: name });
11913
+ log12.debug("MCP server disconnected", { server: name });
11797
11914
  } catch (err) {
11798
- log11.debug("MCP server disconnect failed", { server: name, error: String(err) });
11915
+ log12.debug("MCP server disconnect failed", { server: name, error: String(err) });
11799
11916
  }
11800
11917
  }
11801
11918
  this.connections.clear();
@@ -11804,10 +11921,10 @@ class McpClientManager {
11804
11921
  return Array.from(this.connections.keys());
11805
11922
  }
11806
11923
  }
11807
- var log11, defaultDeps2 = null;
11924
+ var log12, defaultDeps2 = null;
11808
11925
  var init_client_manager = __esm(() => {
11809
11926
  init_logger();
11810
- log11 = createLogger("mcp:client-manager");
11927
+ log12 = createLogger("mcp:client-manager");
11811
11928
  });
11812
11929
 
11813
11930
  // src/mcp/tool-bridge.ts
@@ -11818,7 +11935,7 @@ function buildMcpToolHookEntries(tools, manager) {
11818
11935
  for (const t of tools) {
11819
11936
  const hookName = namespaceMcpTool(t.serverName, t.name);
11820
11937
  if (entries[hookName]) {
11821
- log12.debug("Duplicate MCP tool name, skipping", { hookName });
11938
+ log13.debug("Duplicate MCP tool name, skipping", { hookName });
11822
11939
  continue;
11823
11940
  }
11824
11941
  const zodArgs = mcpSchemaToZod(t.inputSchema, z2);
@@ -11828,7 +11945,7 @@ function buildMcpToolHookEntries(tools, manager) {
11828
11945
  description: t.description || `MCP tool: ${t.name} (server: ${t.serverName})`,
11829
11946
  args: zodArgs,
11830
11947
  async execute(args) {
11831
- log12.debug("Executing MCP tool", { server: serverName, tool: toolName });
11948
+ log13.debug("Executing MCP tool", { server: serverName, tool: toolName });
11832
11949
  const result = await manager.callTool(serverName, toolName, args ?? {});
11833
11950
  if (result.startsWith("Error:")) {
11834
11951
  throw new Error(result);
@@ -11837,7 +11954,7 @@ function buildMcpToolHookEntries(tools, manager) {
11837
11954
  }
11838
11955
  });
11839
11956
  }
11840
- log12.debug("Built MCP tool hook entries", { count: Object.keys(entries).length });
11957
+ log13.debug("Built MCP tool hook entries", { count: Object.keys(entries).length });
11841
11958
  return entries;
11842
11959
  }
11843
11960
  function buildMcpToolDefinitions(tools) {
@@ -11884,7 +12001,7 @@ function mcpSchemaToZod(inputSchema, z2) {
11884
12001
  zodType = z2.array(z2.any());
11885
12002
  break;
11886
12003
  case "object":
11887
- zodType = z2.record(z2.any());
12004
+ zodType = z2.record(z2.string(), z2.any());
11888
12005
  break;
11889
12006
  default:
11890
12007
  zodType = z2.any();
@@ -11900,10 +12017,10 @@ function mcpSchemaToZod(inputSchema, z2) {
11900
12017
  }
11901
12018
  return shape;
11902
12019
  }
11903
- var log12;
12020
+ var log13;
11904
12021
  var init_tool_bridge = __esm(() => {
11905
12022
  init_logger();
11906
- log12 = createLogger("mcp:tool-bridge");
12023
+ log13 = createLogger("mcp:tool-bridge");
11907
12024
  });
11908
12025
 
11909
12026
  // node_modules/@opencode-ai/sdk/dist/gen/types.gen.js
@@ -13314,15 +13431,15 @@ class LocalExecutor {
13314
13431
  const out = await handler(args);
13315
13432
  return { status: "success", output: out };
13316
13433
  } catch (err) {
13317
- log13.warn("Local tool execution failed", { toolId, error: String(err?.message || err) });
13434
+ log14.warn("Local tool execution failed", { toolId, error: String(err?.message || err) });
13318
13435
  return { status: "error", error: String(err?.message || err) };
13319
13436
  }
13320
13437
  }
13321
13438
  }
13322
- var log13;
13439
+ var log14;
13323
13440
  var init_local = __esm(() => {
13324
13441
  init_logger();
13325
- log13 = createLogger("tools:executor:local");
13442
+ log14 = createLogger("tools:executor:local");
13326
13443
  });
13327
13444
 
13328
13445
  // src/tools/executors/sdk.ts
@@ -13349,7 +13466,7 @@ class SdkExecutor {
13349
13466
  const out = typeof res === "string" ? res : JSON.stringify(res);
13350
13467
  return { status: "success", output: out };
13351
13468
  } catch (err) {
13352
- log14.warn("SDK tool execution failed", { toolId, error: String(err?.message || err) });
13469
+ log15.warn("SDK tool execution failed", { toolId, error: String(err?.message || err) });
13353
13470
  return { status: "error", error: String(err?.message || err) };
13354
13471
  }
13355
13472
  }
@@ -13362,10 +13479,10 @@ class SdkExecutor {
13362
13479
  ]);
13363
13480
  }
13364
13481
  }
13365
- var log14;
13482
+ var log15;
13366
13483
  var init_sdk = __esm(() => {
13367
13484
  init_logger();
13368
- log14 = createLogger("tools:executor:sdk");
13485
+ log15 = createLogger("tools:executor:sdk");
13369
13486
  });
13370
13487
 
13371
13488
  // src/tools/executors/mcp.ts
@@ -13392,7 +13509,7 @@ class McpExecutor {
13392
13509
  const out = typeof res === "string" ? res : JSON.stringify(res);
13393
13510
  return { status: "success", output: out };
13394
13511
  } catch (err) {
13395
- log15.warn("MCP tool execution failed", { toolId, error: String(err?.message || err) });
13512
+ log16.warn("MCP tool execution failed", { toolId, error: String(err?.message || err) });
13396
13513
  return { status: "error", error: String(err?.message || err) };
13397
13514
  }
13398
13515
  }
@@ -13405,10 +13522,10 @@ class McpExecutor {
13405
13522
  ]);
13406
13523
  }
13407
13524
  }
13408
- var log15;
13525
+ var log16;
13409
13526
  var init_mcp = __esm(() => {
13410
13527
  init_logger();
13411
- log15 = createLogger("tools:executor:mcp");
13528
+ log16 = createLogger("tools:executor:mcp");
13412
13529
  });
13413
13530
 
13414
13531
  // src/tools/core/executor.ts
@@ -13418,17 +13535,17 @@ async function executeWithChain(executors, toolId, args) {
13418
13535
  try {
13419
13536
  return await ex.execute(toolId, args);
13420
13537
  } catch (err) {
13421
- log16.warn("Executor threw unexpected error", { toolId, error: String(err?.message || err) });
13538
+ log17.warn("Executor threw unexpected error", { toolId, error: String(err?.message || err) });
13422
13539
  return { status: "error", error: String(err?.message || err) };
13423
13540
  }
13424
13541
  }
13425
13542
  }
13426
13543
  return { status: "error", error: `No executor available for ${toolId}` };
13427
13544
  }
13428
- var log16;
13545
+ var log17;
13429
13546
  var init_executor = __esm(() => {
13430
13547
  init_logger();
13431
- log16 = createLogger("tools:executor:chain");
13548
+ log17 = createLogger("tools:executor:chain");
13432
13549
  });
13433
13550
 
13434
13551
  // src/tools/defaults.ts
@@ -13672,6 +13789,9 @@ ${output}`);
13672
13789
  const pattern = args.pattern;
13673
13790
  const path2 = args.path;
13674
13791
  const include = args.include;
13792
+ if (process.platform === "win32") {
13793
+ return nodeFallbackGrep(pattern, path2, include);
13794
+ }
13675
13795
  const grepArgs = ["-r", "-n"];
13676
13796
  if (include) {
13677
13797
  grepArgs.push(`--include=${include}`);
@@ -13764,6 +13884,9 @@ ${output}`);
13764
13884
  const path2 = resolvePathArg(args, "glob");
13765
13885
  const cwd = path2 || ".";
13766
13886
  const normalizedPattern = pattern.replace(/\\/g, "/");
13887
+ if (process.platform === "win32") {
13888
+ return nodeFallbackGlob(normalizedPattern, cwd);
13889
+ }
13767
13890
  const isPathPattern = normalizedPattern.includes("/");
13768
13891
  const findArgs = [cwd, "-type", "f"];
13769
13892
  if (isPathPattern) {
@@ -14040,6 +14163,146 @@ function coerceToString(value) {
14040
14163
  }
14041
14164
  return null;
14042
14165
  }
14166
+ async function nodeFallbackGrep(pattern, searchPath, include) {
14167
+ const fs2 = await import("fs/promises");
14168
+ const path2 = await import("path");
14169
+ let regex2;
14170
+ try {
14171
+ regex2 = new RegExp(pattern);
14172
+ } catch {
14173
+ return "Invalid regex pattern";
14174
+ }
14175
+ let includeRegex;
14176
+ if (include) {
14177
+ const incPattern = include.replace(/\./g, "\\.").replace(/\?/g, ".").replace(/\*/g, ".*");
14178
+ includeRegex = new RegExp(`^${incPattern}$`);
14179
+ }
14180
+ const results = [];
14181
+ async function walk(dir) {
14182
+ if (results.length >= 100)
14183
+ return;
14184
+ let entries;
14185
+ try {
14186
+ entries = await fs2.readdir(dir, { withFileTypes: true });
14187
+ } catch (err) {
14188
+ if (err?.code !== "ENOENT" && err?.code !== "EACCES") {
14189
+ fallbackLog.error("Unexpected error reading directory", { dir, code: err?.code, message: err?.message });
14190
+ }
14191
+ return;
14192
+ }
14193
+ for (const entry of entries) {
14194
+ if (results.length >= 100)
14195
+ return;
14196
+ const fullPath = path2.join(dir, entry.name);
14197
+ if (entry.isDirectory()) {
14198
+ if (!FALLBACK_SKIP_DIRS.has(entry.name)) {
14199
+ await walk(fullPath);
14200
+ }
14201
+ } else if (entry.isFile()) {
14202
+ if (includeRegex && !includeRegex.test(entry.name))
14203
+ continue;
14204
+ let content;
14205
+ try {
14206
+ content = await fs2.readFile(fullPath, "utf-8");
14207
+ } catch (err) {
14208
+ if (err?.code !== "ENOENT" && err?.code !== "EACCES") {
14209
+ fallbackLog.error("Unexpected error reading file", { path: fullPath, code: err?.code, message: err?.message });
14210
+ }
14211
+ continue;
14212
+ }
14213
+ const lines = content.split(`
14214
+ `);
14215
+ for (let i = 0;i < lines.length; i++) {
14216
+ if (regex2.test(lines[i])) {
14217
+ results.push(`${fullPath}:${i + 1}:${lines[i]}`);
14218
+ if (results.length >= 100)
14219
+ break;
14220
+ }
14221
+ }
14222
+ }
14223
+ }
14224
+ }
14225
+ let stat;
14226
+ try {
14227
+ stat = await fs2.stat(searchPath);
14228
+ } catch {
14229
+ return "Path not found";
14230
+ }
14231
+ if (stat.isFile()) {
14232
+ let content;
14233
+ try {
14234
+ content = await fs2.readFile(searchPath, "utf-8");
14235
+ } catch (err) {
14236
+ if (err?.code !== "ENOENT" && err?.code !== "EACCES") {
14237
+ fallbackLog.error("Unexpected error reading file", { path: searchPath, code: err?.code, message: err?.message });
14238
+ }
14239
+ return "Path not found";
14240
+ }
14241
+ const lines = content.split(`
14242
+ `);
14243
+ for (let i = 0;i < lines.length; i++) {
14244
+ if (regex2.test(lines[i])) {
14245
+ results.push(`${searchPath}:${i + 1}:${lines[i]}`);
14246
+ if (results.length >= 100)
14247
+ break;
14248
+ }
14249
+ }
14250
+ } else {
14251
+ await walk(searchPath);
14252
+ }
14253
+ return results.join(`
14254
+ `) || "No matches found";
14255
+ }
14256
+ async function nodeFallbackGlob(pattern, searchPath) {
14257
+ const fs2 = await import("fs/promises");
14258
+ const path2 = await import("path");
14259
+ const results = [];
14260
+ const isPathPattern = pattern.includes("/");
14261
+ let regexPattern = pattern.replace(/\./g, "\\.").replace(/\*\*/g, "\x00").replace(/\*/g, "[^/]*").replace(/\x00/g, ".*");
14262
+ let regex2;
14263
+ try {
14264
+ regex2 = isPathPattern ? new RegExp(`${regexPattern}$`) : new RegExp(`^${regexPattern}$`);
14265
+ } catch {
14266
+ return "No files found";
14267
+ }
14268
+ async function walk(dir) {
14269
+ if (results.length >= 50)
14270
+ return;
14271
+ let entries;
14272
+ try {
14273
+ entries = await fs2.readdir(dir, { withFileTypes: true });
14274
+ } catch (err) {
14275
+ if (err?.code !== "ENOENT" && err?.code !== "EACCES") {
14276
+ fallbackLog.error("Unexpected error reading directory", { dir, code: err?.code, message: err?.message });
14277
+ }
14278
+ return;
14279
+ }
14280
+ for (const entry of entries) {
14281
+ if (results.length >= 50)
14282
+ return;
14283
+ const fullPath = path2.join(dir, entry.name);
14284
+ if (entry.isDirectory()) {
14285
+ if (!FALLBACK_SKIP_DIRS.has(entry.name)) {
14286
+ await walk(fullPath);
14287
+ }
14288
+ } else if (entry.isFile()) {
14289
+ const matchTarget = isPathPattern ? fullPath.replace(/\\/g, "/") : entry.name;
14290
+ if (regex2.test(matchTarget)) {
14291
+ results.push(fullPath);
14292
+ }
14293
+ }
14294
+ }
14295
+ }
14296
+ await walk(searchPath);
14297
+ return results.join(`
14298
+ `) || "No files found";
14299
+ }
14300
+ var FALLBACK_SKIP_DIRS, fallbackLog;
14301
+ var init_defaults = __esm(() => {
14302
+ init_logger();
14303
+ FALLBACK_SKIP_DIRS = new Set(["node_modules", ".git", "dist", "build"]);
14304
+ fallbackLog = createLogger("tools:fallback");
14305
+ });
14043
14306
 
14044
14307
  // src/provider/boundary.ts
14045
14308
  function parseProviderBoundaryMode(value) {
@@ -14104,6 +14367,13 @@ function createSharedBoundary(providerId) {
14104
14367
  }
14105
14368
  return raw;
14106
14369
  },
14370
+ resolveRuntimeModel(model, cursorModel) {
14371
+ const rawCursorModel = typeof cursorModel === "string" ? cursorModel.trim() : "";
14372
+ if (rawCursorModel.length > 0) {
14373
+ return this.normalizeRuntimeModel(rawCursorModel);
14374
+ }
14375
+ return this.normalizeRuntimeModel(model);
14376
+ },
14107
14377
  applyChatParamDefaults(output, proxyBaseURL, defaultBaseURL, defaultApiKey) {
14108
14378
  output.options = output.options || {};
14109
14379
  output.options.baseURL = proxyBaseURL || defaultBaseURL;
@@ -14544,7 +14814,7 @@ async function handleToolLoopEventLegacy(options) {
14544
14814
  const extraction = toolLoopMode === "opencode" ? extractOpenAiToolCall(event, allowedToolNames) : { action: "skip", skipReason: "tool_loop_mode_not_opencode" };
14545
14815
  if (extraction.action === "passthrough") {
14546
14816
  passThroughTracker?.trackTool(extraction.passthroughName);
14547
- log17.debug("MCP tool passed through to cursor-agent (legacy)", {
14817
+ log18.debug("MCP tool passed through to cursor-agent (legacy)", {
14548
14818
  tool: extraction.passthroughName
14549
14819
  });
14550
14820
  return { intercepted: false, skipConverter: false };
@@ -14568,7 +14838,7 @@ async function handleToolLoopEventLegacy(options) {
14568
14838
  if (interceptedToolCall) {
14569
14839
  const compat = applyToolSchemaCompat(interceptedToolCall, toolSchemaMap);
14570
14840
  let normalizedToolCall = compat.toolCall;
14571
- log17.debug("Applied tool schema compatibility (legacy)", {
14841
+ log18.debug("Applied tool schema compatibility (legacy)", {
14572
14842
  tool: normalizedToolCall.function.name,
14573
14843
  originalArgKeys: compat.originalArgKeys,
14574
14844
  normalizedArgKeys: compat.normalizedArgKeys,
@@ -14580,7 +14850,7 @@ async function handleToolLoopEventLegacy(options) {
14580
14850
  if (validationTermination) {
14581
14851
  if (validationTermination.soft) {
14582
14852
  const hintChunk = createLoopGuardHintChunk(responseMeta, normalizedToolCall, validationTermination);
14583
- log17.debug("Soft-blocking schema validation loop guard in legacy (emitting hint)", {
14853
+ log18.debug("Soft-blocking schema validation loop guard in legacy (emitting hint)", {
14584
14854
  tool: normalizedToolCall.function.name,
14585
14855
  fingerprint: validationTermination.fingerprint
14586
14856
  });
@@ -14591,7 +14861,7 @@ async function handleToolLoopEventLegacy(options) {
14591
14861
  }
14592
14862
  const reroutedWrite = tryRerouteEditToWrite(normalizedToolCall, compat.normalizedArgs, allowedToolNames, toolSchemaMap);
14593
14863
  if (reroutedWrite) {
14594
- log17.debug("Rerouting malformed edit call to write (legacy)", {
14864
+ log18.debug("Rerouting malformed edit call to write (legacy)", {
14595
14865
  path: reroutedWrite.path,
14596
14866
  missing: compat.validation.missing,
14597
14867
  typeErrors: compat.validation.typeErrors
@@ -14599,7 +14869,7 @@ async function handleToolLoopEventLegacy(options) {
14599
14869
  normalizedToolCall = reroutedWrite.toolCall;
14600
14870
  } else if (shouldEmitNonFatalSchemaValidationHint(normalizedToolCall, compat.validation)) {
14601
14871
  const hintChunk = createNonFatalSchemaValidationHintChunk(responseMeta, normalizedToolCall, compat.validation);
14602
- log17.debug("Emitting non-fatal schema validation hint in legacy and skipping malformed tool execution", {
14872
+ log18.debug("Emitting non-fatal schema validation hint in legacy and skipping malformed tool execution", {
14603
14873
  tool: normalizedToolCall.function.name,
14604
14874
  missing: compat.validation.missing,
14605
14875
  typeErrors: compat.validation.typeErrors
@@ -14612,7 +14882,7 @@ async function handleToolLoopEventLegacy(options) {
14612
14882
  if (termination) {
14613
14883
  if (termination.soft) {
14614
14884
  const hintChunk = createLoopGuardHintChunk(responseMeta, normalizedToolCall, termination);
14615
- log17.debug("Soft-blocking tool loop guard in legacy (emitting hint)", {
14885
+ log18.debug("Soft-blocking tool loop guard in legacy (emitting hint)", {
14616
14886
  tool: normalizedToolCall.function.name,
14617
14887
  fingerprint: termination.fingerprint
14618
14888
  });
@@ -14670,7 +14940,7 @@ async function handleToolLoopEventV1(options) {
14670
14940
  }
14671
14941
  if (extraction.action === "passthrough") {
14672
14942
  passThroughTracker?.trackTool(extraction.passthroughName);
14673
- log17.debug("MCP tool passed through to cursor-agent (v1)", {
14943
+ log18.debug("MCP tool passed through to cursor-agent (v1)", {
14674
14944
  tool: extraction.passthroughName
14675
14945
  });
14676
14946
  return { intercepted: false, skipConverter: false };
@@ -14697,7 +14967,7 @@ async function handleToolLoopEventV1(options) {
14697
14967
  rawArgs: safeArgTypeSummary(event),
14698
14968
  normalizedArgs: compat.normalizedArgs
14699
14969
  } : undefined;
14700
- log17.debug("Applied tool schema compatibility", {
14970
+ log18.debug("Applied tool schema compatibility", {
14701
14971
  tool: normalizedToolCall.function.name,
14702
14972
  originalArgKeys: compat.originalArgKeys,
14703
14973
  normalizedArgKeys: compat.normalizedArgKeys,
@@ -14706,7 +14976,7 @@ async function handleToolLoopEventV1(options) {
14706
14976
  ...editDiag ? { editDiag } : {}
14707
14977
  });
14708
14978
  if (compat.validation.hasSchema && !compat.validation.ok) {
14709
- log17.debug("Tool schema compatibility validation failed", {
14979
+ log18.debug("Tool schema compatibility validation failed", {
14710
14980
  tool: normalizedToolCall.function.name,
14711
14981
  missing: compat.validation.missing,
14712
14982
  unexpected: compat.validation.unexpected,
@@ -14717,7 +14987,7 @@ async function handleToolLoopEventV1(options) {
14717
14987
  if (validationTermination) {
14718
14988
  if (validationTermination.soft) {
14719
14989
  const hintChunk = createLoopGuardHintChunk(responseMeta, normalizedToolCall, validationTermination);
14720
- log17.debug("Soft-blocking schema validation loop guard (emitting hint)", {
14990
+ log18.debug("Soft-blocking schema validation loop guard (emitting hint)", {
14721
14991
  tool: normalizedToolCall.function.name,
14722
14992
  fingerprint: validationTermination.fingerprint,
14723
14993
  repeatCount: validationTermination.repeatCount
@@ -14731,7 +15001,7 @@ async function handleToolLoopEventV1(options) {
14731
15001
  if (termination2) {
14732
15002
  if (termination2.soft) {
14733
15003
  const hintChunk = createLoopGuardHintChunk(responseMeta, normalizedToolCall, termination2);
14734
- log17.debug("Soft-blocking tool loop guard in validation path (emitting hint)", {
15004
+ log18.debug("Soft-blocking tool loop guard in validation path (emitting hint)", {
14735
15005
  tool: normalizedToolCall.function.name,
14736
15006
  fingerprint: termination2.fingerprint,
14737
15007
  repeatCount: termination2.repeatCount
@@ -14743,7 +15013,7 @@ async function handleToolLoopEventV1(options) {
14743
15013
  }
14744
15014
  const reroutedWrite = tryRerouteEditToWrite(normalizedToolCall, compat.normalizedArgs, allowedToolNames, toolSchemaMap);
14745
15015
  if (reroutedWrite) {
14746
- log17.debug("Rerouting malformed edit call to write", {
15016
+ log18.debug("Rerouting malformed edit call to write", {
14747
15017
  path: reroutedWrite.path,
14748
15018
  missing: compat.validation.missing,
14749
15019
  typeErrors: compat.validation.typeErrors
@@ -14763,7 +15033,7 @@ async function handleToolLoopEventV1(options) {
14763
15033
  }
14764
15034
  if (schemaValidationFailureMode === "pass_through" && shouldEmitNonFatalSchemaValidationHint(normalizedToolCall, compat.validation)) {
14765
15035
  const hintChunk = createNonFatalSchemaValidationHintChunk(responseMeta, normalizedToolCall, compat.validation);
14766
- log17.debug("Emitting non-fatal schema validation hint and skipping malformed tool execution", {
15036
+ log18.debug("Emitting non-fatal schema validation hint and skipping malformed tool execution", {
14767
15037
  tool: normalizedToolCall.function.name,
14768
15038
  missing: compat.validation.missing,
14769
15039
  typeErrors: compat.validation.typeErrors
@@ -14781,7 +15051,7 @@ async function handleToolLoopEventV1(options) {
14781
15051
  terminate: createSchemaValidationTermination(normalizedToolCall, compat.validation)
14782
15052
  };
14783
15053
  }
14784
- log17.debug("Forwarding schema-invalid tool call to OpenCode loop", {
15054
+ log18.debug("Forwarding schema-invalid tool call to OpenCode loop", {
14785
15055
  tool: normalizedToolCall.function.name,
14786
15056
  repairHint: compat.validation.repairHint
14787
15057
  });
@@ -14795,7 +15065,7 @@ async function handleToolLoopEventV1(options) {
14795
15065
  if (termination) {
14796
15066
  if (termination.soft) {
14797
15067
  const hintChunk = createLoopGuardHintChunk(responseMeta, normalizedToolCall, termination);
14798
- log17.debug("Soft-blocking tool loop guard (emitting hint)", {
15068
+ log18.debug("Soft-blocking tool loop guard (emitting hint)", {
14799
15069
  tool: normalizedToolCall.function.name,
14800
15070
  fingerprint: termination.fingerprint,
14801
15071
  repeatCount: termination.repeatCount
@@ -14854,7 +15124,7 @@ function evaluateToolLoopGuard(toolLoopGuard, toolCall) {
14854
15124
  if (!decision.triggered) {
14855
15125
  return null;
14856
15126
  }
14857
- log17.debug("Tool loop guard triggered", {
15127
+ log18.debug("Tool loop guard triggered", {
14858
15128
  tool: toolCall.function.name,
14859
15129
  fingerprint: decision.fingerprint,
14860
15130
  repeatCount: decision.repeatCount,
@@ -14916,7 +15186,7 @@ function evaluateSchemaValidationLoopGuard(toolLoopGuard, toolCall, validation)
14916
15186
  return null;
14917
15187
  }
14918
15188
  const isFirstTrigger = decision.repeatCount === decision.maxRepeat + 1;
14919
- log17.debug("Tool loop guard triggered on schema validation", {
15189
+ log18.debug("Tool loop guard triggered on schema validation", {
14920
15190
  tool: toolCall.function.name,
14921
15191
  fingerprint: decision.fingerprint,
14922
15192
  repeatCount: decision.repeatCount,
@@ -15096,12 +15366,12 @@ function tryRerouteEditToWrite(toolCall, normalizedArgs, allowedToolNames, toolS
15096
15366
  function isRecord4(value) {
15097
15367
  return typeof value === "object" && value !== null && !Array.isArray(value);
15098
15368
  }
15099
- var log17, ToolBoundaryExtractionError;
15369
+ var log18, ToolBoundaryExtractionError;
15100
15370
  var init_runtime_interception = __esm(() => {
15101
15371
  init_tool_loop();
15102
15372
  init_logger();
15103
15373
  init_tool_schema_compat();
15104
- log17 = createLogger("provider:runtime-interception");
15374
+ log18 = createLogger("provider:runtime-interception");
15105
15375
  ToolBoundaryExtractionError = class ToolBoundaryExtractionError extends Error {
15106
15376
  cause;
15107
15377
  constructor(message, cause) {
@@ -15143,7 +15413,7 @@ class ToastService {
15143
15413
  }
15144
15414
  async show(options) {
15145
15415
  if (!this.client?.tui?.showToast) {
15146
- log18.debug("Toast not available; client.tui.showToast missing", { message: options.message });
15416
+ log19.debug("Toast not available; client.tui.showToast missing", { message: options.message });
15147
15417
  return;
15148
15418
  }
15149
15419
  try {
@@ -15155,7 +15425,7 @@ class ToastService {
15155
15425
  }
15156
15426
  });
15157
15427
  } catch (error) {
15158
- log18.debug("Toast failed", { error, message: options.message });
15428
+ log19.debug("Toast failed", { error, message: options.message });
15159
15429
  }
15160
15430
  }
15161
15431
  async showPassThroughSummary(tools) {
@@ -15179,10 +15449,10 @@ class ToastService {
15179
15449
  });
15180
15450
  }
15181
15451
  }
15182
- var log18, toastService;
15452
+ var log19, toastService;
15183
15453
  var init_toast_service = __esm(() => {
15184
15454
  init_logger();
15185
- log18 = createLogger("services:toast");
15455
+ log19 = createLogger("services:toast");
15186
15456
  toastService = new ToastService;
15187
15457
  });
15188
15458
 
@@ -15631,9 +15901,12 @@ var init_tool_loop_guard = __esm(() => {
15631
15901
  var exports_plugin = {};
15632
15902
  __export(exports_plugin, {
15633
15903
  shouldProcessModel: () => shouldProcessModel,
15904
+ resolveWorkspaceDirectory: () => resolveWorkspaceDirectory,
15634
15905
  resolveChatParamTools: () => resolveChatParamTools,
15635
15906
  normalizeWorkspaceForCompare: () => normalizeWorkspaceForCompare,
15907
+ isRootPath: () => isRootPath,
15636
15908
  isReusableProxyHealthPayload: () => isReusableProxyHealthPayload,
15909
+ extractCompletionFromStream: () => extractCompletionFromStream,
15637
15910
  ensurePluginDirectory: () => ensurePluginDirectory,
15638
15911
  default: () => plugin_default,
15639
15912
  buildAvailableToolsSystemMessage: () => buildAvailableToolsSystemMessage,
@@ -15643,7 +15916,7 @@ import { tool as tool2 } from "@opencode-ai/plugin";
15643
15916
  import { appendFileSync as appendFileSync3, existsSync as existsSync5, realpathSync } from "fs";
15644
15917
  import { mkdir } from "fs/promises";
15645
15918
  import { homedir as homedir5 } from "os";
15646
- import { isAbsolute, join as join5, relative, resolve as resolve2 } from "path";
15919
+ import { isAbsolute, join as join6, relative, resolve as resolve2 } from "path";
15647
15920
  function ensureDebugLogDir() {
15648
15921
  try {
15649
15922
  if (!existsSync5(DEBUG_LOG_DIR2)) {
@@ -15703,13 +15976,13 @@ function buildAvailableToolsSystemMessage(lastToolNames, lastToolMap, mcpToolDef
15703
15976
  `) : null;
15704
15977
  }
15705
15978
  async function ensurePluginDirectory() {
15706
- const configHome = process.env.XDG_CONFIG_HOME ? resolve2(process.env.XDG_CONFIG_HOME) : join5(homedir5(), ".config");
15707
- const pluginDir = join5(configHome, "opencode", "plugin");
15979
+ const configHome = process.env.XDG_CONFIG_HOME ? resolve2(process.env.XDG_CONFIG_HOME) : join6(homedir5(), ".config");
15980
+ const pluginDir = join6(configHome, "opencode", "plugin");
15708
15981
  try {
15709
15982
  await mkdir(pluginDir, { recursive: true });
15710
- log19.debug("Plugin directory ensured", { path: pluginDir });
15983
+ log20.debug("Plugin directory ensured", { path: pluginDir });
15711
15984
  } catch (error) {
15712
- log19.warn("Failed to create plugin directory", { error: String(error) });
15985
+ log20.warn("Failed to create plugin directory", { error: String(error) });
15713
15986
  }
15714
15987
  }
15715
15988
  function shouldProcessModel(model) {
@@ -15721,8 +15994,8 @@ function getGlobalKey() {
15721
15994
  return "__opencode_cursor_proxy_server__";
15722
15995
  }
15723
15996
  function getOpenCodeConfigPrefix() {
15724
- const configHome = process.env.XDG_CONFIG_HOME ? resolve2(process.env.XDG_CONFIG_HOME) : join5(homedir5(), ".config");
15725
- return join5(configHome, "opencode");
15997
+ const configHome = process.env.XDG_CONFIG_HOME ? resolve2(process.env.XDG_CONFIG_HOME) : join6(homedir5(), ".config");
15998
+ return join6(configHome, "opencode");
15726
15999
  }
15727
16000
  function canonicalizePathForCompare(pathValue) {
15728
16001
  const resolvedPath = resolve2(pathValue);
@@ -15732,7 +16005,7 @@ function canonicalizePathForCompare(pathValue) {
15732
16005
  } catch {
15733
16006
  normalizedPath = resolvedPath;
15734
16007
  }
15735
- if (process.platform === "darwin") {
16008
+ if (process.platform === "darwin" || process.platform === "win32") {
15736
16009
  return normalizedPath.toLowerCase();
15737
16010
  }
15738
16011
  return normalizedPath;
@@ -15755,32 +16028,62 @@ function isNonConfigPath(pathValue) {
15755
16028
  }
15756
16029
  return !isWithinPath(getOpenCodeConfigPrefix(), pathValue);
15757
16030
  }
15758
- function resolveWorkspaceDirectory(worktree, directory) {
15759
- const envWorkspace = process.env.CURSOR_ACP_WORKSPACE?.trim();
15760
- if (envWorkspace) {
15761
- return resolve2(envWorkspace);
16031
+ function isRootPath(pathValue) {
16032
+ if (!pathValue) {
16033
+ return false;
16034
+ }
16035
+ const resolved = resolve2(pathValue);
16036
+ if (resolved === "/") {
16037
+ return true;
16038
+ }
16039
+ return /^[A-Za-z]:[\\/]?$/.test(resolved);
16040
+ }
16041
+ function isAcceptableWorkspace(pathValue, configPrefix) {
16042
+ if (!pathValue) {
16043
+ return false;
15762
16044
  }
15763
- const envProjectDir = process.env.OPENCODE_CURSOR_PROJECT_DIR?.trim();
15764
- if (envProjectDir) {
15765
- return resolve2(envProjectDir);
16045
+ if (isRootPath(pathValue)) {
16046
+ return false;
16047
+ }
16048
+ if (isWithinPath(configPrefix, pathValue)) {
16049
+ return false;
15766
16050
  }
16051
+ return true;
16052
+ }
16053
+ function resolveWorkspaceDirectory(worktree, directory) {
15767
16054
  const configPrefix = getOpenCodeConfigPrefix();
16055
+ const envWorkspace = resolveCandidate(process.env.CURSOR_ACP_WORKSPACE);
16056
+ if (envWorkspace && !isRootPath(envWorkspace)) {
16057
+ return envWorkspace;
16058
+ }
16059
+ const envProjectDir = resolveCandidate(process.env.OPENCODE_CURSOR_PROJECT_DIR);
16060
+ if (envProjectDir && !isRootPath(envProjectDir)) {
16061
+ return envProjectDir;
16062
+ }
15768
16063
  const worktreeCandidate = resolveCandidate(worktree);
15769
- if (worktreeCandidate && !isWithinPath(configPrefix, worktreeCandidate)) {
16064
+ if (isAcceptableWorkspace(worktreeCandidate, configPrefix)) {
15770
16065
  return worktreeCandidate;
15771
16066
  }
15772
16067
  const dirCandidate = resolveCandidate(directory);
15773
- if (dirCandidate && !isWithinPath(configPrefix, dirCandidate)) {
16068
+ if (isAcceptableWorkspace(dirCandidate, configPrefix)) {
15774
16069
  return dirCandidate;
15775
16070
  }
15776
16071
  const cwd = resolve2(process.cwd());
15777
- if (cwd && !isWithinPath(configPrefix, cwd)) {
16072
+ if (isAcceptableWorkspace(cwd, configPrefix)) {
15778
16073
  return cwd;
15779
16074
  }
15780
- return dirCandidate || cwd || configPrefix;
16075
+ const home = resolveCandidate(homedir5());
16076
+ if (home && !isRootPath(home)) {
16077
+ return home;
16078
+ }
16079
+ return configPrefix;
15781
16080
  }
15782
16081
  function normalizeWorkspaceForCompare(pathValue) {
15783
- return resolve2(pathValue);
16082
+ const resolved = resolve2(pathValue);
16083
+ if (process.platform === "darwin" || process.platform === "win32") {
16084
+ return resolved.toLowerCase();
16085
+ }
16086
+ return resolved;
15784
16087
  }
15785
16088
  function isReusableProxyHealthPayload(payload, workspaceDirectory) {
15786
16089
  if (!payload || payload.ok !== true) {
@@ -15801,7 +16104,7 @@ function parseToolLoopMode(value) {
15801
16104
  function resolveChatParamTools(mode, existingTools, refreshedTools) {
15802
16105
  return PROVIDER_BOUNDARY.resolveChatParamTools(mode, existingTools, refreshedTools);
15803
16106
  }
15804
- function createChatCompletionResponse(model, content, reasoningContent) {
16107
+ function createChatCompletionResponse(model, content, reasoningContent, usage) {
15805
16108
  const message = {
15806
16109
  role: "assistant",
15807
16110
  content
@@ -15809,7 +16112,7 @@ function createChatCompletionResponse(model, content, reasoningContent) {
15809
16112
  if (reasoningContent && reasoningContent.length > 0) {
15810
16113
  message.reasoning_content = reasoningContent;
15811
16114
  }
15812
- return {
16115
+ const response = {
15813
16116
  id: `cursor-acp-${Date.now()}`,
15814
16117
  object: "chat.completion",
15815
16118
  created: Math.floor(Date.now() / 1000),
@@ -15822,6 +16125,10 @@ function createChatCompletionResponse(model, content, reasoningContent) {
15822
16125
  }
15823
16126
  ]
15824
16127
  };
16128
+ if (usage) {
16129
+ response.usage = usage;
16130
+ }
16131
+ return response;
15825
16132
  }
15826
16133
  function createChatCompletionChunk(id, created, model, deltaContent, done = false) {
15827
16134
  return {
@@ -15843,7 +16150,9 @@ function extractCompletionFromStream(output) {
15843
16150
  `);
15844
16151
  let assistantText = "";
15845
16152
  let reasoningText = "";
16153
+ let usage;
15846
16154
  let sawAssistantPartials = false;
16155
+ let sawThinkingPartials = false;
15847
16156
  for (const line of lines) {
15848
16157
  const event = parseStreamJsonLine(line);
15849
16158
  if (!event) {
@@ -15864,11 +16173,20 @@ function extractCompletionFromStream(output) {
15864
16173
  if (isThinking(event)) {
15865
16174
  const thinking = extractThinking(event);
15866
16175
  if (thinking) {
15867
- reasoningText += thinking;
16176
+ const isPartial = typeof event.timestamp_ms === "number";
16177
+ if (isPartial) {
16178
+ reasoningText += thinking;
16179
+ sawThinkingPartials = true;
16180
+ } else if (!sawThinkingPartials) {
16181
+ reasoningText = thinking;
16182
+ }
15868
16183
  }
15869
16184
  }
16185
+ if (isResult(event)) {
16186
+ usage = extractOpenAiUsageFromResult(event) ?? usage;
16187
+ }
15870
16188
  }
15871
- return { assistantText, reasoningText };
16189
+ return { assistantText, reasoningText, usage };
15872
16190
  }
15873
16191
  function formatToolUpdateEvent(update) {
15874
16192
  return `event: tool_update
@@ -15897,9 +16215,9 @@ function createBoundaryRuntimeContext(scope) {
15897
16215
  error: toErrorMessage(error)
15898
16216
  };
15899
16217
  if (!fallbackActive) {
15900
- log19.warn("Provider boundary v1 failed; switching to legacy for this request", details);
16218
+ log20.warn("Provider boundary v1 failed; switching to legacy for this request", details);
15901
16219
  } else {
15902
- log19.debug("Provider boundary fallback already active", details);
16220
+ log20.debug("Provider boundary fallback already active", details);
15903
16221
  }
15904
16222
  fallbackActive = true;
15905
16223
  return true;
@@ -16012,7 +16330,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16012
16330
  if (url.pathname === "/v1/models" || url.pathname === "/models") {
16013
16331
  try {
16014
16332
  const bunAny2 = globalThis;
16015
- const proc = bunAny2.Bun.spawn(["cursor-agent", "models"], {
16333
+ const proc = bunAny2.Bun.spawn([resolveCursorAgentBinary(), "models"], {
16016
16334
  stdout: "pipe",
16017
16335
  stderr: "pipe"
16018
16336
  });
@@ -16037,7 +16355,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16037
16355
  headers: { "Content-Type": "application/json" }
16038
16356
  });
16039
16357
  } catch (err) {
16040
- log19.error("Failed to list models", { error: String(err) });
16358
+ log20.error("Failed to list models", { error: String(err) });
16041
16359
  return new Response(JSON.stringify({ error: "Failed to fetch models from cursor-agent" }), {
16042
16360
  status: 500,
16043
16361
  headers: { "Content-Type": "application/json" }
@@ -16050,13 +16368,14 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16050
16368
  headers: { "Content-Type": "application/json" }
16051
16369
  });
16052
16370
  }
16053
- log19.debug("Proxy request (bun)", { method: req.method, path: url.pathname });
16371
+ log20.debug("Proxy request (bun)", { method: req.method, path: url.pathname });
16054
16372
  const body = await req.json().catch(() => ({}));
16055
16373
  const messages = Array.isArray(body?.messages) ? body.messages : [];
16056
16374
  const stream = body?.stream === true;
16057
16375
  const tools = Array.isArray(body?.tools) ? body.tools : [];
16058
16376
  debugLogToFile2("raw_request_body", {
16059
16377
  model: body?.model,
16378
+ cursorModel: body?.cursorModel,
16060
16379
  stream,
16061
16380
  toolCount: tools.length,
16062
16381
  toolNames: tools.map((t) => t?.function?.name ?? t?.name ?? "unknown"),
@@ -16071,14 +16390,14 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16071
16390
  const boundaryContext = createBoundaryRuntimeContext("bun-handler");
16072
16391
  const subagentNames = readSubagentNames();
16073
16392
  const prompt = buildPromptFromMessages(messages, tools, subagentNames);
16074
- const model = boundaryContext.run("normalizeRuntimeModel", (boundary) => boundary.normalizeRuntimeModel(body?.model));
16393
+ const model = boundaryContext.run("resolveRuntimeModel", (boundary) => boundary.resolveRuntimeModel(body?.model, body?.cursorModel));
16075
16394
  const msgSummaryBun = messages.map((m, i) => {
16076
16395
  const role = m?.role ?? "?";
16077
16396
  const hasTc = Array.isArray(m?.tool_calls) ? m.tool_calls.length : 0;
16078
16397
  const clen = typeof m?.content === "string" ? m.content.length : Array.isArray(m?.content) ? `arr${m.content.length}` : typeof m?.content;
16079
16398
  return `${i}:${role}${hasTc ? `(tc:${hasTc})` : ""}(clen:${clen})`;
16080
16399
  });
16081
- log19.debug("Proxy chat request (bun)", {
16400
+ log20.debug("Proxy chat request (bun)", {
16082
16401
  stream,
16083
16402
  model,
16084
16403
  messages: messages.length,
@@ -16094,7 +16413,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16094
16413
  });
16095
16414
  }
16096
16415
  const cmd = [
16097
- "cursor-agent",
16416
+ resolveCursorAgentBinary(),
16098
16417
  "--print",
16099
16418
  "--output-format",
16100
16419
  "stream-json",
@@ -16124,7 +16443,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16124
16443
  const stdout = (stdoutText || "").trim();
16125
16444
  const stderr = (stderrText || "").trim();
16126
16445
  const exitCode = await child.exited;
16127
- log19.debug("cursor-agent completed (bun non-stream)", {
16446
+ log20.debug("cursor-agent completed (bun non-stream)", {
16128
16447
  exitCode,
16129
16448
  stdoutChars: stdout.length,
16130
16449
  stderrChars: stderr.length
@@ -16150,7 +16469,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16150
16469
  });
16151
16470
  }
16152
16471
  if (intercepted.toolCall) {
16153
- log19.debug("Intercepted OpenCode tool call (non-stream)", {
16472
+ log20.debug("Intercepted OpenCode tool call (non-stream)", {
16154
16473
  name: intercepted.toolCall.function.name,
16155
16474
  callId: intercepted.toolCall.id
16156
16475
  });
@@ -16164,7 +16483,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16164
16483
  const errSource = stderr || stdout || `cursor-agent exited with code ${String(exitCode ?? "unknown")} and no output`;
16165
16484
  const parsed = parseAgentError(errSource);
16166
16485
  const userError = formatErrorForUser(parsed);
16167
- log19.error("cursor-cli failed", {
16486
+ log20.error("cursor-cli failed", {
16168
16487
  type: parsed.type,
16169
16488
  message: parsed.message,
16170
16489
  code: exitCode
@@ -16176,7 +16495,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16176
16495
  });
16177
16496
  }
16178
16497
  const completion = extractCompletionFromStream(stdout);
16179
- const payload = createChatCompletionResponse(model, completion.assistantText || stdout || stderr, completion.reasoningText || undefined);
16498
+ const payload = createChatCompletionResponse(model, completion.assistantText || stdout || stderr, completion.reasoningText || undefined, completion.usage);
16180
16499
  return new Response(JSON.stringify(payload), {
16181
16500
  status: 200,
16182
16501
  headers: { "Content-Type": "application/json" }
@@ -16194,12 +16513,13 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16194
16513
  async start(controller) {
16195
16514
  let streamTerminated = false;
16196
16515
  let firstTokenReceived = false;
16516
+ let usage;
16197
16517
  try {
16198
16518
  const reader = child.stdout.getReader();
16199
16519
  const converter = new StreamToSseConverter(model, { id, created });
16200
16520
  const lineBuffer = new LineBuffer;
16201
16521
  const emitToolCallAndTerminate = (toolCall) => {
16202
- log19.debug("Intercepted OpenCode tool call (stream)", {
16522
+ log20.debug("Intercepted OpenCode tool call (stream)", {
16203
16523
  name: toolCall.function.name,
16204
16524
  callId: toolCall.id
16205
16525
  });
@@ -16248,6 +16568,9 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16248
16568
  if (!event) {
16249
16569
  continue;
16250
16570
  }
16571
+ if (isResult(event)) {
16572
+ usage = extractOpenAiUsageFromResult(event) ?? usage;
16573
+ }
16251
16574
  if (event.type === "tool_call") {
16252
16575
  perf.mark("tool-call");
16253
16576
  const result = await handleToolLoopEventWithFallback({
@@ -16316,6 +16639,9 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16316
16639
  if (!event) {
16317
16640
  continue;
16318
16641
  }
16642
+ if (isResult(event)) {
16643
+ usage = extractOpenAiUsageFromResult(event) ?? usage;
16644
+ }
16319
16645
  if (event.type === "tool_call") {
16320
16646
  const result = await handleToolLoopEventWithFallback({
16321
16647
  event,
@@ -16381,7 +16707,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16381
16707
  const errSource = (stderrText || "").trim() || `cursor-agent exited with code ${String(exitCode ?? "unknown")} and no output`;
16382
16708
  const parsed = parseAgentError(errSource);
16383
16709
  const msg = formatErrorForUser(parsed);
16384
- log19.error("cursor-cli streaming failed", {
16710
+ log20.error("cursor-cli streaming failed", {
16385
16711
  type: parsed.type,
16386
16712
  code: exitCode
16387
16713
  });
@@ -16392,7 +16718,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16392
16718
  controller.enqueue(encoder.encode(formatSseDone()));
16393
16719
  return;
16394
16720
  }
16395
- log19.debug("cursor-agent completed (bun stream)", {
16721
+ log20.debug("cursor-agent completed (bun stream)", {
16396
16722
  exitCode
16397
16723
  });
16398
16724
  const passThroughSummary = passThroughTracker.getSummary();
@@ -16406,6 +16732,12 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16406
16732
  controller.enqueue(encoder.encode(`data: ${JSON.stringify(doneChunk)}
16407
16733
 
16408
16734
  `));
16735
+ if (usage) {
16736
+ const usageChunk = createChatCompletionUsageChunk(id, created, model, usage);
16737
+ controller.enqueue(encoder.encode(`data: ${JSON.stringify(usageChunk)}
16738
+
16739
+ `));
16740
+ }
16409
16741
  controller.enqueue(encoder.encode(formatSseDone()));
16410
16742
  } finally {
16411
16743
  perf.mark("request:done");
@@ -16455,8 +16787,8 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16455
16787
  }
16456
16788
  if (url.pathname === "/v1/models" || url.pathname === "/models") {
16457
16789
  try {
16458
- const { execSync } = await import("child_process");
16459
- const output = execSync("cursor-agent models", { encoding: "utf-8", timeout: 30000 });
16790
+ const { execFileSync: execFileSync2 } = await import("child_process");
16791
+ const output = execFileSync2(resolveCursorAgentBinary(), ["models"], { encoding: "utf-8", timeout: 30000 });
16460
16792
  const clean = stripAnsi(output);
16461
16793
  const models = [];
16462
16794
  for (const line of clean.split(`
@@ -16474,7 +16806,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16474
16806
  res.writeHead(200, { "Content-Type": "application/json" });
16475
16807
  res.end(JSON.stringify({ object: "list", data: models }));
16476
16808
  } catch (err) {
16477
- log19.error("Failed to list models", { error: String(err) });
16809
+ log20.error("Failed to list models", { error: String(err) });
16478
16810
  res.writeHead(500, { "Content-Type": "application/json" });
16479
16811
  res.end(JSON.stringify({ error: "Failed to fetch models" }));
16480
16812
  }
@@ -16485,7 +16817,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16485
16817
  res.end(JSON.stringify({ error: `Unsupported path: ${url.pathname}` }));
16486
16818
  return;
16487
16819
  }
16488
- log19.debug("Proxy request (node)", { method: req.method, path: url.pathname });
16820
+ log20.debug("Proxy request (node)", { method: req.method, path: url.pathname });
16489
16821
  let body = "";
16490
16822
  for await (const chunk of req) {
16491
16823
  body += chunk;
@@ -16500,7 +16832,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16500
16832
  const boundaryContext = createBoundaryRuntimeContext("node-handler");
16501
16833
  const subagentNames = readSubagentNames();
16502
16834
  const prompt = buildPromptFromMessages(messages, tools, subagentNames);
16503
- const model = boundaryContext.run("normalizeRuntimeModel", (boundary) => boundary.normalizeRuntimeModel(bodyData?.model));
16835
+ const model = boundaryContext.run("resolveRuntimeModel", (boundary) => boundary.resolveRuntimeModel(bodyData?.model, bodyData?.cursorModel));
16504
16836
  const msgSummary = messages.map((m, i) => {
16505
16837
  const role = m?.role ?? "?";
16506
16838
  const hasTc = Array.isArray(m?.tool_calls) ? m.tool_calls.length : 0;
@@ -16509,7 +16841,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16509
16841
  const contentLen = typeof m?.content === "string" ? m.content.length : Array.isArray(m?.content) ? `arr${m.content.length}` : typeof m?.content;
16510
16842
  return `${i}:${role}${hasTc ? `(tc:${hasTc})` : ""}${role === "tool" ? `(tcid:${tcId},name:${tcName},clen:${contentLen})` : `(clen:${contentLen})`}`;
16511
16843
  });
16512
- log19.debug("Proxy chat request (node)", {
16844
+ log20.debug("Proxy chat request (node)", {
16513
16845
  stream,
16514
16846
  model,
16515
16847
  messages: messages.length,
@@ -16518,7 +16850,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16518
16850
  msgRoles: msgSummary.join(",")
16519
16851
  });
16520
16852
  const cmd = [
16521
- "cursor-agent",
16853
+ resolveCursorAgentBinary(),
16522
16854
  "--print",
16523
16855
  "--output-format",
16524
16856
  "stream-json",
@@ -16531,7 +16863,10 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16531
16863
  if (FORCE_TOOL_MODE) {
16532
16864
  cmd.push("--force");
16533
16865
  }
16534
- const child = spawn3(cmd[0], cmd.slice(1), { stdio: ["pipe", "pipe", "pipe"] });
16866
+ const child = spawn3(cmd[0], cmd.slice(1), {
16867
+ stdio: ["pipe", "pipe", "pipe"],
16868
+ shell: process.platform === "win32"
16869
+ });
16535
16870
  child.stdin.write(prompt);
16536
16871
  child.stdin.end();
16537
16872
  if (!stream) {
@@ -16540,14 +16875,14 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16540
16875
  let spawnErrorText = null;
16541
16876
  child.on("error", (error) => {
16542
16877
  spawnErrorText = String(error?.message || error);
16543
- log19.error("Failed to spawn cursor-agent", { error: spawnErrorText, model });
16878
+ log20.error("Failed to spawn cursor-agent", { error: spawnErrorText, model });
16544
16879
  });
16545
16880
  child.stdout.on("data", (chunk) => stdoutChunks.push(chunk));
16546
16881
  child.stderr.on("data", (chunk) => stderrChunks.push(chunk));
16547
16882
  child.on("close", async (code) => {
16548
16883
  const stdout = Buffer.concat(stdoutChunks).toString().trim();
16549
16884
  const stderr = Buffer.concat(stderrChunks).toString().trim();
16550
- log19.debug("cursor-agent completed (node non-stream)", {
16885
+ log20.debug("cursor-agent completed (node non-stream)", {
16551
16886
  code,
16552
16887
  stdoutChars: stdout.length,
16553
16888
  stderrChars: stderr.length,
@@ -16573,7 +16908,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16573
16908
  return;
16574
16909
  }
16575
16910
  if (intercepted.toolCall) {
16576
- log19.debug("Intercepted OpenCode tool call (non-stream)", {
16911
+ log20.debug("Intercepted OpenCode tool call (non-stream)", {
16577
16912
  name: intercepted.toolCall.function.name,
16578
16913
  callId: intercepted.toolCall.id
16579
16914
  });
@@ -16587,7 +16922,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16587
16922
  const errSource = stderr || stdout || spawnErrorText || `cursor-agent exited with code ${String(code ?? "unknown")} and no output`;
16588
16923
  const parsed = parseAgentError(errSource);
16589
16924
  const userError = formatErrorForUser(parsed);
16590
- log19.error("cursor-cli failed", {
16925
+ log20.error("cursor-cli failed", {
16591
16926
  type: parsed.type,
16592
16927
  message: parsed.message,
16593
16928
  code
@@ -16597,7 +16932,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16597
16932
  res.end(JSON.stringify(errorResponse));
16598
16933
  return;
16599
16934
  }
16600
- const response = createChatCompletionResponse(model, completion.assistantText || stdout || stderr, completion.reasoningText || undefined);
16935
+ const response = createChatCompletionResponse(model, completion.assistantText || stdout || stderr, completion.reasoningText || undefined, completion.usage);
16601
16936
  res.writeHead(200, { "Content-Type": "application/json" });
16602
16937
  res.end(JSON.stringify(response));
16603
16938
  });
@@ -16619,6 +16954,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16619
16954
  const stderrChunks = [];
16620
16955
  let streamTerminated = false;
16621
16956
  let firstTokenReceived = false;
16957
+ let usage;
16622
16958
  child.stderr.on("data", (chunk) => {
16623
16959
  stderrChunks.push(Buffer.from(chunk));
16624
16960
  });
@@ -16627,7 +16963,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16627
16963
  return;
16628
16964
  }
16629
16965
  const errSource = String(error?.message || error);
16630
- log19.error("Failed to spawn cursor-agent (stream)", { error: errSource, model });
16966
+ log20.error("Failed to spawn cursor-agent (stream)", { error: errSource, model });
16631
16967
  const parsed = parseAgentError(errSource);
16632
16968
  const msg = formatErrorForUser(parsed);
16633
16969
  const errChunk = createChatCompletionChunk(id, created, model, msg, true);
@@ -16642,7 +16978,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16642
16978
  if (streamTerminated || res.writableEnded) {
16643
16979
  return;
16644
16980
  }
16645
- log19.debug("Intercepted OpenCode tool call (stream)", {
16981
+ log20.debug("Intercepted OpenCode tool call (stream)", {
16646
16982
  name: toolCall.function.name,
16647
16983
  callId: toolCall.id
16648
16984
  });
@@ -16690,6 +17026,9 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16690
17026
  if (!event) {
16691
17027
  continue;
16692
17028
  }
17029
+ if (isResult(event)) {
17030
+ usage = extractOpenAiUsageFromResult(event) ?? usage;
17031
+ }
16693
17032
  if (event.type === "tool_call") {
16694
17033
  perf.mark("tool-call");
16695
17034
  const result = await handleToolLoopEventWithFallback({
@@ -16762,6 +17101,9 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16762
17101
  if (!event) {
16763
17102
  continue;
16764
17103
  }
17104
+ if (isResult(event)) {
17105
+ usage = extractOpenAiUsageFromResult(event) ?? usage;
17106
+ }
16765
17107
  if (event.type === "tool_call") {
16766
17108
  const result = await handleToolLoopEventWithFallback({
16767
17109
  event,
@@ -16826,7 +17168,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16826
17168
  perf.mark("request:done");
16827
17169
  perf.summarize();
16828
17170
  const stderrText = Buffer.concat(stderrChunks).toString().trim();
16829
- log19.debug("cursor-agent completed (node stream)", {
17171
+ log20.debug("cursor-agent completed (node stream)", {
16830
17172
  code,
16831
17173
  stderrChars: stderrText.length
16832
17174
  });
@@ -16866,6 +17208,12 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16866
17208
  res.write(`data: ${JSON.stringify(doneChunk)}
16867
17209
 
16868
17210
  `);
17211
+ if (usage) {
17212
+ const usageChunk = createChatCompletionUsageChunk(id, created, model, usage);
17213
+ res.write(`data: ${JSON.stringify(usageChunk)}
17214
+
17215
+ `);
17216
+ }
16869
17217
  res.write(formatSseDone());
16870
17218
  res.end();
16871
17219
  });
@@ -16943,7 +17291,7 @@ function jsonSchemaToZod(jsonSchema) {
16943
17291
  }
16944
17292
  break;
16945
17293
  case "object":
16946
- zodType = z2.record(z2.any());
17294
+ zodType = z2.record(z2.string(), z2.any());
16947
17295
  if (p.description) {
16948
17296
  zodType = zodType.describe(p.description);
16949
17297
  }
@@ -17054,7 +17402,7 @@ function buildToolHookEntries(registry, fallbackBaseDir) {
17054
17402
  const normalizedArgs = applyToolContextDefaults(toolName, args, context, fallbackBaseDir, sessionWorkspaceBySession);
17055
17403
  return await handler(normalizedArgs);
17056
17404
  } catch (error) {
17057
- log19.debug("Tool hook execution failed", { tool: toolName, error: String(error?.message || error) });
17405
+ log20.debug("Tool hook execution failed", { tool: toolName, error: String(error?.message || error) });
17058
17406
  throw error;
17059
17407
  }
17060
17408
  }
@@ -17066,9 +17414,9 @@ function buildToolHookEntries(registry, fallbackBaseDir) {
17066
17414
  }
17067
17415
  return entries;
17068
17416
  }
17069
- var log19, 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, CursorPlugin = async ({ $, directory, worktree, client: client3, serverUrl }) => {
17417
+ 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, CursorPlugin = async ({ $, directory, worktree, client: client3, serverUrl }) => {
17070
17418
  const workspaceDirectory = resolveWorkspaceDirectory(worktree, directory);
17071
- log19.debug("Plugin initializing", {
17419
+ log20.debug("Plugin initializing", {
17072
17420
  directory,
17073
17421
  worktree,
17074
17422
  workspaceDirectory,
@@ -17076,22 +17424,22 @@ var log19, DEBUG_LOG_DIR2, DEBUG_LOG_FILE2, CURSOR_PROVIDER_ID2 = "cursor-acp",
17076
17424
  serverUrl: serverUrl?.toString()
17077
17425
  });
17078
17426
  if (!TOOL_LOOP_MODE_VALID) {
17079
- log19.warn("Invalid CURSOR_ACP_TOOL_LOOP_MODE; defaulting to opencode", { value: TOOL_LOOP_MODE_RAW });
17427
+ log20.warn("Invalid CURSOR_ACP_TOOL_LOOP_MODE; defaulting to opencode", { value: TOOL_LOOP_MODE_RAW });
17080
17428
  }
17081
17429
  if (!PROVIDER_BOUNDARY_MODE_VALID) {
17082
- log19.warn("Invalid CURSOR_ACP_PROVIDER_BOUNDARY; defaulting to v1", {
17430
+ log20.warn("Invalid CURSOR_ACP_PROVIDER_BOUNDARY; defaulting to v1", {
17083
17431
  value: PROVIDER_BOUNDARY_MODE_RAW
17084
17432
  });
17085
17433
  }
17086
17434
  if (!TOOL_LOOP_MAX_REPEAT_VALID) {
17087
- log19.warn("Invalid CURSOR_ACP_TOOL_LOOP_MAX_REPEAT; defaulting to 3", {
17435
+ log20.warn("Invalid CURSOR_ACP_TOOL_LOOP_MAX_REPEAT; defaulting to 3", {
17088
17436
  value: TOOL_LOOP_MAX_REPEAT_RAW
17089
17437
  });
17090
17438
  }
17091
17439
  if (ENABLE_PROVIDER_BOUNDARY_AUTOFALLBACK && PROVIDER_BOUNDARY.mode !== "v1") {
17092
- log19.debug("Provider boundary auto-fallback is enabled but inactive unless mode=v1");
17440
+ log20.debug("Provider boundary auto-fallback is enabled but inactive unless mode=v1");
17093
17441
  }
17094
- log19.info("Tool loop mode configured", {
17442
+ log20.info("Tool loop mode configured", {
17095
17443
  mode: TOOL_LOOP_MODE,
17096
17444
  providerBoundary: PROVIDER_BOUNDARY.mode,
17097
17445
  proxyExecToolCalls: PROXY_EXECUTE_TOOL_CALLS,
@@ -17109,13 +17457,13 @@ var log19, DEBUG_LOG_DIR2, DEBUG_LOG_FILE2, CURSOR_PROVIDER_ID2 = "cursor-acp",
17109
17457
  try {
17110
17458
  const configs = readMcpConfigs();
17111
17459
  if (configs.length === 0) {
17112
- log19.debug("No MCP servers configured, skipping MCP bridge");
17460
+ log20.debug("No MCP servers configured, skipping MCP bridge");
17113
17461
  } else {
17114
- log19.debug("MCP bridge: connecting to servers", { count: configs.length });
17462
+ log20.debug("MCP bridge: connecting to servers", { count: configs.length });
17115
17463
  await Promise.allSettled(configs.map((c) => mcpManager.connectServer(c)));
17116
17464
  const tools = mcpManager.listTools();
17117
17465
  if (tools.length === 0) {
17118
- log19.debug("MCP bridge: no tools discovered");
17466
+ log20.debug("MCP bridge: no tools discovered");
17119
17467
  } else {
17120
17468
  mcpToolEntries = buildMcpToolHookEntries(tools, mcpManager);
17121
17469
  mcpToolDefs = buildMcpToolDefinitions(tools);
@@ -17125,23 +17473,23 @@ var log19, DEBUG_LOG_DIR2, DEBUG_LOG_FILE2, CURSOR_PROVIDER_ID2 = "cursor-acp",
17125
17473
  description: t.description,
17126
17474
  params: t.inputSchema ? Object.keys(t.inputSchema.properties ?? {}) : undefined
17127
17475
  }));
17128
- log19.info("MCP bridge: registered tools", {
17476
+ log20.info("MCP bridge: registered tools", {
17129
17477
  servers: mcpManager.connectedServers.length,
17130
17478
  tools: Object.keys(mcpToolEntries).length
17131
17479
  });
17132
17480
  }
17133
17481
  }
17134
17482
  } catch (err) {
17135
- log19.debug("MCP bridge init failed", { error: String(err) });
17483
+ log20.debug("MCP bridge init failed", { error: String(err) });
17136
17484
  }
17137
17485
  }
17138
17486
  toastService.setClient(client3);
17139
17487
  const toolsEnabled = process.env.CURSOR_ACP_ENABLE_OPENCODE_TOOLS !== "false";
17140
17488
  const legacyProxyToolPathsEnabled = toolsEnabled && TOOL_LOOP_MODE === "proxy-exec";
17141
17489
  if (toolsEnabled && TOOL_LOOP_MODE === "opencode") {
17142
- log19.debug("OpenCode mode active; skipping legacy SDK/MCP discovery and proxy-side tool execution");
17490
+ log20.debug("OpenCode mode active; skipping legacy SDK/MCP discovery and proxy-side tool execution");
17143
17491
  } else if (toolsEnabled && TOOL_LOOP_MODE === "off") {
17144
- log19.debug("Tool loop mode off; proxy-side tool execution disabled");
17492
+ log20.debug("Tool loop mode off; proxy-side tool execution disabled");
17145
17493
  }
17146
17494
  const serverClient = legacyProxyToolPathsEnabled ? createOpencodeClient({ baseUrl: serverUrl.toString(), directory: workspaceDirectory }) : null;
17147
17495
  const discovery = legacyProxyToolPathsEnabled ? new OpenCodeToolDiscovery(serverClient ?? client3) : null;
@@ -17193,7 +17541,7 @@ var log19, DEBUG_LOG_DIR2, DEBUG_LOG_FILE2, CURSOR_PROVIDER_ID2 = "cursor-acp",
17193
17541
  discoveredList = await discovery.listTools();
17194
17542
  discoveredList.forEach((t) => toolsByName.set(t.name, t));
17195
17543
  } catch (err) {
17196
- log19.debug("Tool discovery failed, using local tools only", { error: String(err) });
17544
+ log20.debug("Tool discovery failed, using local tools only", { error: String(err) });
17197
17545
  }
17198
17546
  }
17199
17547
  const allTools = [...localTools, ...discoveredList];
@@ -17223,11 +17571,11 @@ var log19, DEBUG_LOG_DIR2, DEBUG_LOG_FILE2, CURSOR_PROVIDER_ID2 = "cursor-acp",
17223
17571
  }
17224
17572
  lastToolNames = toolEntries.map((e) => e.function.name);
17225
17573
  lastToolMap = allTools.map((t) => ({ id: t.id, name: t.name }));
17226
- log19.debug("Tools refreshed", { local: localTools.length, discovered: discoveredList.length, total: toolEntries.length });
17574
+ log20.debug("Tools refreshed", { local: localTools.length, discovered: discoveredList.length, total: toolEntries.length });
17227
17575
  return toolEntries;
17228
17576
  }
17229
17577
  const proxyBaseURL = await ensureCursorProxyServer(workspaceDirectory, router);
17230
- log19.debug("Proxy server started", { baseURL: proxyBaseURL });
17578
+ log20.debug("Proxy server started", { baseURL: proxyBaseURL });
17231
17579
  const toolHookEntries = buildToolHookEntries(localRegistry, workspaceDirectory);
17232
17580
  return {
17233
17581
  tool: { ...toolHookEntries, ...mcpToolEntries },
@@ -17242,9 +17590,9 @@ var log19, DEBUG_LOG_DIR2, DEBUG_LOG_FILE2, CURSOR_PROVIDER_ID2 = "cursor-acp",
17242
17590
  type: "oauth",
17243
17591
  async authorize() {
17244
17592
  try {
17245
- log19.info("Starting OAuth flow");
17593
+ log20.info("Starting OAuth flow");
17246
17594
  const { url, instructions, callback } = await startCursorOAuth();
17247
- log19.debug("Got OAuth URL", { url: url.substring(0, 50) + "..." });
17595
+ log20.debug("Got OAuth URL", { url: url.substring(0, 50) + "..." });
17248
17596
  return {
17249
17597
  url,
17250
17598
  instructions,
@@ -17252,7 +17600,7 @@ var log19, DEBUG_LOG_DIR2, DEBUG_LOG_FILE2, CURSOR_PROVIDER_ID2 = "cursor-acp",
17252
17600
  callback
17253
17601
  };
17254
17602
  } catch (error) {
17255
- log19.error("OAuth error", { error });
17603
+ log20.error("OAuth error", { error });
17256
17604
  throw error;
17257
17605
  }
17258
17606
  }
@@ -17276,10 +17624,10 @@ var log19, DEBUG_LOG_DIR2, DEBUG_LOG_FILE2, CURSOR_PROVIDER_ID2 = "cursor-acp",
17276
17624
  output.options.tools = resolved.tools;
17277
17625
  } else if (resolved.action === "preserve") {
17278
17626
  const count = Array.isArray(existingTools) ? existingTools.length : 0;
17279
- log19.debug("Using OpenCode-provided tools from chat.params", { count });
17627
+ log20.debug("Using OpenCode-provided tools from chat.params", { count });
17280
17628
  }
17281
17629
  } catch (err) {
17282
- log19.debug("Failed to refresh tools", { error: String(err) });
17630
+ log20.debug("Failed to refresh tools", { error: String(err) });
17283
17631
  }
17284
17632
  }
17285
17633
  if (mcpToolDefs.length > 0) {
@@ -17290,7 +17638,7 @@ var log19, DEBUG_LOG_DIR2, DEBUG_LOG_FILE2, CURSOR_PROVIDER_ID2 = "cursor-acp",
17290
17638
  output.options.tools = mcpToolDefs;
17291
17639
  }
17292
17640
  const afterTools = Array.isArray(output.options.tools) ? output.options.tools : [];
17293
- log19.debug("Injected MCP tool definitions into chat.params", {
17641
+ log20.debug("Injected MCP tool definitions into chat.params", {
17294
17642
  injectedCount: mcpToolDefs.length,
17295
17643
  beforeCount: beforeTools.length,
17296
17644
  afterCount: afterTools.length,
@@ -17331,14 +17679,16 @@ var init_plugin = __esm(() => {
17331
17679
  init_sdk();
17332
17680
  init_mcp();
17333
17681
  init_executor();
17682
+ init_defaults();
17334
17683
  init_boundary();
17335
17684
  init_runtime_interception();
17336
17685
  init_toast_service();
17337
17686
  init_tool_schema_compat();
17338
17687
  init_tool_loop_guard();
17339
- log19 = createLogger("plugin");
17340
- DEBUG_LOG_DIR2 = join5(homedir5(), ".config", "opencode", "logs");
17341
- DEBUG_LOG_FILE2 = join5(DEBUG_LOG_DIR2, "tool-loop-debug.log");
17688
+ init_binary();
17689
+ log20 = createLogger("plugin");
17690
+ DEBUG_LOG_DIR2 = join6(homedir5(), ".config", "opencode", "logs");
17691
+ DEBUG_LOG_FILE2 = join6(DEBUG_LOG_DIR2, "tool-loop-debug.log");
17342
17692
  CURSOR_PROVIDER_PREFIX = `${CURSOR_PROVIDER_ID2}/`;
17343
17693
  CURSOR_PROXY_DEFAULT_BASE_URL = `http://${CURSOR_PROXY_HOST}:${CURSOR_PROXY_DEFAULT_PORT}/v1`;
17344
17694
  REUSE_EXISTING_PROXY = process.env.CURSOR_ACP_REUSE_EXISTING_PROXY !== "false";
@@ -17371,11 +17721,11 @@ var init_plugin = __esm(() => {
17371
17721
  // src/plugin-entry.ts
17372
17722
  init_plugin_toggle();
17373
17723
  init_logger();
17374
- var log20 = createLogger("plugin-entry");
17724
+ var log21 = createLogger("plugin-entry");
17375
17725
  var CursorPluginEntry = async (input) => {
17376
17726
  const state = shouldEnableCursorPlugin();
17377
17727
  if (!state.enabled) {
17378
- log20.info("Plugin disabled in OpenCode config; skipping initialization", {
17728
+ log21.info("Plugin disabled in OpenCode config; skipping initialization", {
17379
17729
  configPath: state.configPath,
17380
17730
  reason: state.reason
17381
17731
  });