@rama_nigg/open-cursor 2.3.20 → 2.4.1

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
@@ -13466,7 +13583,7 @@ function registerDefaultTools(registry) {
13466
13583
  const cwd = resolveWorkingDirectory(args);
13467
13584
  return new Promise((resolve2, reject) => {
13468
13585
  const proc = spawn3(command, {
13469
- shell: process.env.SHELL || "/bin/bash",
13586
+ shell: resolveShellOption(),
13470
13587
  cwd
13471
13588
  });
13472
13589
  const stdoutChunks = [];
@@ -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) {
@@ -13975,6 +14098,14 @@ function resolveTimeoutMs(value) {
13975
14098
  return 30000;
13976
14099
  return raw <= 600 ? raw * 1000 : raw;
13977
14100
  }
14101
+ function resolveShellOption(deps = {}) {
14102
+ const platform2 = deps.platform ?? process.platform;
14103
+ const env = deps.env ?? process.env;
14104
+ if (platform2 === "win32") {
14105
+ return env.ComSpec || env.COMSPEC || true;
14106
+ }
14107
+ return env.SHELL || "/bin/bash";
14108
+ }
13978
14109
  function resolveBoolean(value, defaultValue) {
13979
14110
  if (typeof value === "boolean") {
13980
14111
  return value;
@@ -14040,6 +14171,146 @@ function coerceToString(value) {
14040
14171
  }
14041
14172
  return null;
14042
14173
  }
14174
+ async function nodeFallbackGrep(pattern, searchPath, include) {
14175
+ const fs2 = await import("fs/promises");
14176
+ const path2 = await import("path");
14177
+ let regex2;
14178
+ try {
14179
+ regex2 = new RegExp(pattern);
14180
+ } catch {
14181
+ return "Invalid regex pattern";
14182
+ }
14183
+ let includeRegex;
14184
+ if (include) {
14185
+ const incPattern = include.replace(/\./g, "\\.").replace(/\?/g, ".").replace(/\*/g, ".*");
14186
+ includeRegex = new RegExp(`^${incPattern}$`);
14187
+ }
14188
+ const results = [];
14189
+ async function walk(dir) {
14190
+ if (results.length >= 100)
14191
+ return;
14192
+ let entries;
14193
+ try {
14194
+ entries = await fs2.readdir(dir, { withFileTypes: true });
14195
+ } catch (err) {
14196
+ if (err?.code !== "ENOENT" && err?.code !== "EACCES") {
14197
+ fallbackLog.error("Unexpected error reading directory", { dir, code: err?.code, message: err?.message });
14198
+ }
14199
+ return;
14200
+ }
14201
+ for (const entry of entries) {
14202
+ if (results.length >= 100)
14203
+ return;
14204
+ const fullPath = path2.join(dir, entry.name);
14205
+ if (entry.isDirectory()) {
14206
+ if (!FALLBACK_SKIP_DIRS.has(entry.name)) {
14207
+ await walk(fullPath);
14208
+ }
14209
+ } else if (entry.isFile()) {
14210
+ if (includeRegex && !includeRegex.test(entry.name))
14211
+ continue;
14212
+ let content;
14213
+ try {
14214
+ content = await fs2.readFile(fullPath, "utf-8");
14215
+ } catch (err) {
14216
+ if (err?.code !== "ENOENT" && err?.code !== "EACCES") {
14217
+ fallbackLog.error("Unexpected error reading file", { path: fullPath, code: err?.code, message: err?.message });
14218
+ }
14219
+ continue;
14220
+ }
14221
+ const lines = content.split(`
14222
+ `);
14223
+ for (let i = 0;i < lines.length; i++) {
14224
+ if (regex2.test(lines[i])) {
14225
+ results.push(`${fullPath}:${i + 1}:${lines[i]}`);
14226
+ if (results.length >= 100)
14227
+ break;
14228
+ }
14229
+ }
14230
+ }
14231
+ }
14232
+ }
14233
+ let stat;
14234
+ try {
14235
+ stat = await fs2.stat(searchPath);
14236
+ } catch {
14237
+ return "Path not found";
14238
+ }
14239
+ if (stat.isFile()) {
14240
+ let content;
14241
+ try {
14242
+ content = await fs2.readFile(searchPath, "utf-8");
14243
+ } catch (err) {
14244
+ if (err?.code !== "ENOENT" && err?.code !== "EACCES") {
14245
+ fallbackLog.error("Unexpected error reading file", { path: searchPath, code: err?.code, message: err?.message });
14246
+ }
14247
+ return "Path not found";
14248
+ }
14249
+ const lines = content.split(`
14250
+ `);
14251
+ for (let i = 0;i < lines.length; i++) {
14252
+ if (regex2.test(lines[i])) {
14253
+ results.push(`${searchPath}:${i + 1}:${lines[i]}`);
14254
+ if (results.length >= 100)
14255
+ break;
14256
+ }
14257
+ }
14258
+ } else {
14259
+ await walk(searchPath);
14260
+ }
14261
+ return results.join(`
14262
+ `) || "No matches found";
14263
+ }
14264
+ async function nodeFallbackGlob(pattern, searchPath) {
14265
+ const fs2 = await import("fs/promises");
14266
+ const path2 = await import("path");
14267
+ const results = [];
14268
+ const isPathPattern = pattern.includes("/");
14269
+ let regexPattern = pattern.replace(/\./g, "\\.").replace(/\*\*/g, "\x00").replace(/\*/g, "[^/]*").replace(/\x00/g, ".*");
14270
+ let regex2;
14271
+ try {
14272
+ regex2 = isPathPattern ? new RegExp(`${regexPattern}$`) : new RegExp(`^${regexPattern}$`);
14273
+ } catch {
14274
+ return "No files found";
14275
+ }
14276
+ async function walk(dir) {
14277
+ if (results.length >= 50)
14278
+ return;
14279
+ let entries;
14280
+ try {
14281
+ entries = await fs2.readdir(dir, { withFileTypes: true });
14282
+ } catch (err) {
14283
+ if (err?.code !== "ENOENT" && err?.code !== "EACCES") {
14284
+ fallbackLog.error("Unexpected error reading directory", { dir, code: err?.code, message: err?.message });
14285
+ }
14286
+ return;
14287
+ }
14288
+ for (const entry of entries) {
14289
+ if (results.length >= 50)
14290
+ return;
14291
+ const fullPath = path2.join(dir, entry.name);
14292
+ if (entry.isDirectory()) {
14293
+ if (!FALLBACK_SKIP_DIRS.has(entry.name)) {
14294
+ await walk(fullPath);
14295
+ }
14296
+ } else if (entry.isFile()) {
14297
+ const matchTarget = isPathPattern ? fullPath.replace(/\\/g, "/") : entry.name;
14298
+ if (regex2.test(matchTarget)) {
14299
+ results.push(fullPath);
14300
+ }
14301
+ }
14302
+ }
14303
+ }
14304
+ await walk(searchPath);
14305
+ return results.join(`
14306
+ `) || "No files found";
14307
+ }
14308
+ var FALLBACK_SKIP_DIRS, fallbackLog;
14309
+ var init_defaults = __esm(() => {
14310
+ init_logger();
14311
+ FALLBACK_SKIP_DIRS = new Set(["node_modules", ".git", "dist", "build"]);
14312
+ fallbackLog = createLogger("tools:fallback");
14313
+ });
14043
14314
 
14044
14315
  // src/provider/boundary.ts
14045
14316
  function parseProviderBoundaryMode(value) {
@@ -14104,6 +14375,13 @@ function createSharedBoundary(providerId) {
14104
14375
  }
14105
14376
  return raw;
14106
14377
  },
14378
+ resolveRuntimeModel(model, cursorModel) {
14379
+ const rawCursorModel = typeof cursorModel === "string" ? cursorModel.trim() : "";
14380
+ if (rawCursorModel.length > 0) {
14381
+ return this.normalizeRuntimeModel(rawCursorModel);
14382
+ }
14383
+ return this.normalizeRuntimeModel(model);
14384
+ },
14107
14385
  applyChatParamDefaults(output, proxyBaseURL, defaultBaseURL, defaultApiKey) {
14108
14386
  output.options = output.options || {};
14109
14387
  output.options.baseURL = proxyBaseURL || defaultBaseURL;
@@ -14544,7 +14822,7 @@ async function handleToolLoopEventLegacy(options) {
14544
14822
  const extraction = toolLoopMode === "opencode" ? extractOpenAiToolCall(event, allowedToolNames) : { action: "skip", skipReason: "tool_loop_mode_not_opencode" };
14545
14823
  if (extraction.action === "passthrough") {
14546
14824
  passThroughTracker?.trackTool(extraction.passthroughName);
14547
- log17.debug("MCP tool passed through to cursor-agent (legacy)", {
14825
+ log18.debug("MCP tool passed through to cursor-agent (legacy)", {
14548
14826
  tool: extraction.passthroughName
14549
14827
  });
14550
14828
  return { intercepted: false, skipConverter: false };
@@ -14568,7 +14846,7 @@ async function handleToolLoopEventLegacy(options) {
14568
14846
  if (interceptedToolCall) {
14569
14847
  const compat = applyToolSchemaCompat(interceptedToolCall, toolSchemaMap);
14570
14848
  let normalizedToolCall = compat.toolCall;
14571
- log17.debug("Applied tool schema compatibility (legacy)", {
14849
+ log18.debug("Applied tool schema compatibility (legacy)", {
14572
14850
  tool: normalizedToolCall.function.name,
14573
14851
  originalArgKeys: compat.originalArgKeys,
14574
14852
  normalizedArgKeys: compat.normalizedArgKeys,
@@ -14580,7 +14858,7 @@ async function handleToolLoopEventLegacy(options) {
14580
14858
  if (validationTermination) {
14581
14859
  if (validationTermination.soft) {
14582
14860
  const hintChunk = createLoopGuardHintChunk(responseMeta, normalizedToolCall, validationTermination);
14583
- log17.debug("Soft-blocking schema validation loop guard in legacy (emitting hint)", {
14861
+ log18.debug("Soft-blocking schema validation loop guard in legacy (emitting hint)", {
14584
14862
  tool: normalizedToolCall.function.name,
14585
14863
  fingerprint: validationTermination.fingerprint
14586
14864
  });
@@ -14591,7 +14869,7 @@ async function handleToolLoopEventLegacy(options) {
14591
14869
  }
14592
14870
  const reroutedWrite = tryRerouteEditToWrite(normalizedToolCall, compat.normalizedArgs, allowedToolNames, toolSchemaMap);
14593
14871
  if (reroutedWrite) {
14594
- log17.debug("Rerouting malformed edit call to write (legacy)", {
14872
+ log18.debug("Rerouting malformed edit call to write (legacy)", {
14595
14873
  path: reroutedWrite.path,
14596
14874
  missing: compat.validation.missing,
14597
14875
  typeErrors: compat.validation.typeErrors
@@ -14599,7 +14877,7 @@ async function handleToolLoopEventLegacy(options) {
14599
14877
  normalizedToolCall = reroutedWrite.toolCall;
14600
14878
  } else if (shouldEmitNonFatalSchemaValidationHint(normalizedToolCall, compat.validation)) {
14601
14879
  const hintChunk = createNonFatalSchemaValidationHintChunk(responseMeta, normalizedToolCall, compat.validation);
14602
- log17.debug("Emitting non-fatal schema validation hint in legacy and skipping malformed tool execution", {
14880
+ log18.debug("Emitting non-fatal schema validation hint in legacy and skipping malformed tool execution", {
14603
14881
  tool: normalizedToolCall.function.name,
14604
14882
  missing: compat.validation.missing,
14605
14883
  typeErrors: compat.validation.typeErrors
@@ -14612,7 +14890,7 @@ async function handleToolLoopEventLegacy(options) {
14612
14890
  if (termination) {
14613
14891
  if (termination.soft) {
14614
14892
  const hintChunk = createLoopGuardHintChunk(responseMeta, normalizedToolCall, termination);
14615
- log17.debug("Soft-blocking tool loop guard in legacy (emitting hint)", {
14893
+ log18.debug("Soft-blocking tool loop guard in legacy (emitting hint)", {
14616
14894
  tool: normalizedToolCall.function.name,
14617
14895
  fingerprint: termination.fingerprint
14618
14896
  });
@@ -14670,7 +14948,7 @@ async function handleToolLoopEventV1(options) {
14670
14948
  }
14671
14949
  if (extraction.action === "passthrough") {
14672
14950
  passThroughTracker?.trackTool(extraction.passthroughName);
14673
- log17.debug("MCP tool passed through to cursor-agent (v1)", {
14951
+ log18.debug("MCP tool passed through to cursor-agent (v1)", {
14674
14952
  tool: extraction.passthroughName
14675
14953
  });
14676
14954
  return { intercepted: false, skipConverter: false };
@@ -14697,7 +14975,7 @@ async function handleToolLoopEventV1(options) {
14697
14975
  rawArgs: safeArgTypeSummary(event),
14698
14976
  normalizedArgs: compat.normalizedArgs
14699
14977
  } : undefined;
14700
- log17.debug("Applied tool schema compatibility", {
14978
+ log18.debug("Applied tool schema compatibility", {
14701
14979
  tool: normalizedToolCall.function.name,
14702
14980
  originalArgKeys: compat.originalArgKeys,
14703
14981
  normalizedArgKeys: compat.normalizedArgKeys,
@@ -14706,7 +14984,7 @@ async function handleToolLoopEventV1(options) {
14706
14984
  ...editDiag ? { editDiag } : {}
14707
14985
  });
14708
14986
  if (compat.validation.hasSchema && !compat.validation.ok) {
14709
- log17.debug("Tool schema compatibility validation failed", {
14987
+ log18.debug("Tool schema compatibility validation failed", {
14710
14988
  tool: normalizedToolCall.function.name,
14711
14989
  missing: compat.validation.missing,
14712
14990
  unexpected: compat.validation.unexpected,
@@ -14717,7 +14995,7 @@ async function handleToolLoopEventV1(options) {
14717
14995
  if (validationTermination) {
14718
14996
  if (validationTermination.soft) {
14719
14997
  const hintChunk = createLoopGuardHintChunk(responseMeta, normalizedToolCall, validationTermination);
14720
- log17.debug("Soft-blocking schema validation loop guard (emitting hint)", {
14998
+ log18.debug("Soft-blocking schema validation loop guard (emitting hint)", {
14721
14999
  tool: normalizedToolCall.function.name,
14722
15000
  fingerprint: validationTermination.fingerprint,
14723
15001
  repeatCount: validationTermination.repeatCount
@@ -14731,7 +15009,7 @@ async function handleToolLoopEventV1(options) {
14731
15009
  if (termination2) {
14732
15010
  if (termination2.soft) {
14733
15011
  const hintChunk = createLoopGuardHintChunk(responseMeta, normalizedToolCall, termination2);
14734
- log17.debug("Soft-blocking tool loop guard in validation path (emitting hint)", {
15012
+ log18.debug("Soft-blocking tool loop guard in validation path (emitting hint)", {
14735
15013
  tool: normalizedToolCall.function.name,
14736
15014
  fingerprint: termination2.fingerprint,
14737
15015
  repeatCount: termination2.repeatCount
@@ -14743,7 +15021,7 @@ async function handleToolLoopEventV1(options) {
14743
15021
  }
14744
15022
  const reroutedWrite = tryRerouteEditToWrite(normalizedToolCall, compat.normalizedArgs, allowedToolNames, toolSchemaMap);
14745
15023
  if (reroutedWrite) {
14746
- log17.debug("Rerouting malformed edit call to write", {
15024
+ log18.debug("Rerouting malformed edit call to write", {
14747
15025
  path: reroutedWrite.path,
14748
15026
  missing: compat.validation.missing,
14749
15027
  typeErrors: compat.validation.typeErrors
@@ -14763,7 +15041,7 @@ async function handleToolLoopEventV1(options) {
14763
15041
  }
14764
15042
  if (schemaValidationFailureMode === "pass_through" && shouldEmitNonFatalSchemaValidationHint(normalizedToolCall, compat.validation)) {
14765
15043
  const hintChunk = createNonFatalSchemaValidationHintChunk(responseMeta, normalizedToolCall, compat.validation);
14766
- log17.debug("Emitting non-fatal schema validation hint and skipping malformed tool execution", {
15044
+ log18.debug("Emitting non-fatal schema validation hint and skipping malformed tool execution", {
14767
15045
  tool: normalizedToolCall.function.name,
14768
15046
  missing: compat.validation.missing,
14769
15047
  typeErrors: compat.validation.typeErrors
@@ -14781,7 +15059,7 @@ async function handleToolLoopEventV1(options) {
14781
15059
  terminate: createSchemaValidationTermination(normalizedToolCall, compat.validation)
14782
15060
  };
14783
15061
  }
14784
- log17.debug("Forwarding schema-invalid tool call to OpenCode loop", {
15062
+ log18.debug("Forwarding schema-invalid tool call to OpenCode loop", {
14785
15063
  tool: normalizedToolCall.function.name,
14786
15064
  repairHint: compat.validation.repairHint
14787
15065
  });
@@ -14795,7 +15073,7 @@ async function handleToolLoopEventV1(options) {
14795
15073
  if (termination) {
14796
15074
  if (termination.soft) {
14797
15075
  const hintChunk = createLoopGuardHintChunk(responseMeta, normalizedToolCall, termination);
14798
- log17.debug("Soft-blocking tool loop guard (emitting hint)", {
15076
+ log18.debug("Soft-blocking tool loop guard (emitting hint)", {
14799
15077
  tool: normalizedToolCall.function.name,
14800
15078
  fingerprint: termination.fingerprint,
14801
15079
  repeatCount: termination.repeatCount
@@ -14854,7 +15132,7 @@ function evaluateToolLoopGuard(toolLoopGuard, toolCall) {
14854
15132
  if (!decision.triggered) {
14855
15133
  return null;
14856
15134
  }
14857
- log17.debug("Tool loop guard triggered", {
15135
+ log18.debug("Tool loop guard triggered", {
14858
15136
  tool: toolCall.function.name,
14859
15137
  fingerprint: decision.fingerprint,
14860
15138
  repeatCount: decision.repeatCount,
@@ -14916,7 +15194,7 @@ function evaluateSchemaValidationLoopGuard(toolLoopGuard, toolCall, validation)
14916
15194
  return null;
14917
15195
  }
14918
15196
  const isFirstTrigger = decision.repeatCount === decision.maxRepeat + 1;
14919
- log17.debug("Tool loop guard triggered on schema validation", {
15197
+ log18.debug("Tool loop guard triggered on schema validation", {
14920
15198
  tool: toolCall.function.name,
14921
15199
  fingerprint: decision.fingerprint,
14922
15200
  repeatCount: decision.repeatCount,
@@ -15096,12 +15374,12 @@ function tryRerouteEditToWrite(toolCall, normalizedArgs, allowedToolNames, toolS
15096
15374
  function isRecord4(value) {
15097
15375
  return typeof value === "object" && value !== null && !Array.isArray(value);
15098
15376
  }
15099
- var log17, ToolBoundaryExtractionError;
15377
+ var log18, ToolBoundaryExtractionError;
15100
15378
  var init_runtime_interception = __esm(() => {
15101
15379
  init_tool_loop();
15102
15380
  init_logger();
15103
15381
  init_tool_schema_compat();
15104
- log17 = createLogger("provider:runtime-interception");
15382
+ log18 = createLogger("provider:runtime-interception");
15105
15383
  ToolBoundaryExtractionError = class ToolBoundaryExtractionError extends Error {
15106
15384
  cause;
15107
15385
  constructor(message, cause) {
@@ -15143,7 +15421,7 @@ class ToastService {
15143
15421
  }
15144
15422
  async show(options) {
15145
15423
  if (!this.client?.tui?.showToast) {
15146
- log18.debug("Toast not available; client.tui.showToast missing", { message: options.message });
15424
+ log19.debug("Toast not available; client.tui.showToast missing", { message: options.message });
15147
15425
  return;
15148
15426
  }
15149
15427
  try {
@@ -15155,7 +15433,7 @@ class ToastService {
15155
15433
  }
15156
15434
  });
15157
15435
  } catch (error) {
15158
- log18.debug("Toast failed", { error, message: options.message });
15436
+ log19.debug("Toast failed", { error, message: options.message });
15159
15437
  }
15160
15438
  }
15161
15439
  async showPassThroughSummary(tools) {
@@ -15179,10 +15457,10 @@ class ToastService {
15179
15457
  });
15180
15458
  }
15181
15459
  }
15182
- var log18, toastService;
15460
+ var log19, toastService;
15183
15461
  var init_toast_service = __esm(() => {
15184
15462
  init_logger();
15185
- log18 = createLogger("services:toast");
15463
+ log19 = createLogger("services:toast");
15186
15464
  toastService = new ToastService;
15187
15465
  });
15188
15466
 
@@ -15631,9 +15909,12 @@ var init_tool_loop_guard = __esm(() => {
15631
15909
  var exports_plugin = {};
15632
15910
  __export(exports_plugin, {
15633
15911
  shouldProcessModel: () => shouldProcessModel,
15912
+ resolveWorkspaceDirectory: () => resolveWorkspaceDirectory,
15634
15913
  resolveChatParamTools: () => resolveChatParamTools,
15635
15914
  normalizeWorkspaceForCompare: () => normalizeWorkspaceForCompare,
15915
+ isRootPath: () => isRootPath,
15636
15916
  isReusableProxyHealthPayload: () => isReusableProxyHealthPayload,
15917
+ extractCompletionFromStream: () => extractCompletionFromStream,
15637
15918
  ensurePluginDirectory: () => ensurePluginDirectory,
15638
15919
  default: () => plugin_default,
15639
15920
  buildAvailableToolsSystemMessage: () => buildAvailableToolsSystemMessage,
@@ -15643,7 +15924,7 @@ import { tool as tool2 } from "@opencode-ai/plugin";
15643
15924
  import { appendFileSync as appendFileSync3, existsSync as existsSync5, realpathSync } from "fs";
15644
15925
  import { mkdir } from "fs/promises";
15645
15926
  import { homedir as homedir5 } from "os";
15646
- import { isAbsolute, join as join5, relative, resolve as resolve2 } from "path";
15927
+ import { isAbsolute, join as join6, relative, resolve as resolve2 } from "path";
15647
15928
  function ensureDebugLogDir() {
15648
15929
  try {
15649
15930
  if (!existsSync5(DEBUG_LOG_DIR2)) {
@@ -15703,13 +15984,13 @@ function buildAvailableToolsSystemMessage(lastToolNames, lastToolMap, mcpToolDef
15703
15984
  `) : null;
15704
15985
  }
15705
15986
  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");
15987
+ const configHome = process.env.XDG_CONFIG_HOME ? resolve2(process.env.XDG_CONFIG_HOME) : join6(homedir5(), ".config");
15988
+ const pluginDir = join6(configHome, "opencode", "plugin");
15708
15989
  try {
15709
15990
  await mkdir(pluginDir, { recursive: true });
15710
- log19.debug("Plugin directory ensured", { path: pluginDir });
15991
+ log20.debug("Plugin directory ensured", { path: pluginDir });
15711
15992
  } catch (error) {
15712
- log19.warn("Failed to create plugin directory", { error: String(error) });
15993
+ log20.warn("Failed to create plugin directory", { error: String(error) });
15713
15994
  }
15714
15995
  }
15715
15996
  function shouldProcessModel(model) {
@@ -15721,8 +16002,8 @@ function getGlobalKey() {
15721
16002
  return "__opencode_cursor_proxy_server__";
15722
16003
  }
15723
16004
  function getOpenCodeConfigPrefix() {
15724
- const configHome = process.env.XDG_CONFIG_HOME ? resolve2(process.env.XDG_CONFIG_HOME) : join5(homedir5(), ".config");
15725
- return join5(configHome, "opencode");
16005
+ const configHome = process.env.XDG_CONFIG_HOME ? resolve2(process.env.XDG_CONFIG_HOME) : join6(homedir5(), ".config");
16006
+ return join6(configHome, "opencode");
15726
16007
  }
15727
16008
  function canonicalizePathForCompare(pathValue) {
15728
16009
  const resolvedPath = resolve2(pathValue);
@@ -15732,7 +16013,7 @@ function canonicalizePathForCompare(pathValue) {
15732
16013
  } catch {
15733
16014
  normalizedPath = resolvedPath;
15734
16015
  }
15735
- if (process.platform === "darwin") {
16016
+ if (process.platform === "darwin" || process.platform === "win32") {
15736
16017
  return normalizedPath.toLowerCase();
15737
16018
  }
15738
16019
  return normalizedPath;
@@ -15755,32 +16036,62 @@ function isNonConfigPath(pathValue) {
15755
16036
  }
15756
16037
  return !isWithinPath(getOpenCodeConfigPrefix(), pathValue);
15757
16038
  }
15758
- function resolveWorkspaceDirectory(worktree, directory) {
15759
- const envWorkspace = process.env.CURSOR_ACP_WORKSPACE?.trim();
15760
- if (envWorkspace) {
15761
- return resolve2(envWorkspace);
16039
+ function isRootPath(pathValue) {
16040
+ if (!pathValue) {
16041
+ return false;
15762
16042
  }
15763
- const envProjectDir = process.env.OPENCODE_CURSOR_PROJECT_DIR?.trim();
15764
- if (envProjectDir) {
15765
- return resolve2(envProjectDir);
16043
+ const resolved = resolve2(pathValue);
16044
+ if (resolved === "/") {
16045
+ return true;
15766
16046
  }
16047
+ return /^[A-Za-z]:[\\/]?$/.test(resolved);
16048
+ }
16049
+ function isAcceptableWorkspace(pathValue, configPrefix) {
16050
+ if (!pathValue) {
16051
+ return false;
16052
+ }
16053
+ if (isRootPath(pathValue)) {
16054
+ return false;
16055
+ }
16056
+ if (isWithinPath(configPrefix, pathValue)) {
16057
+ return false;
16058
+ }
16059
+ return true;
16060
+ }
16061
+ function resolveWorkspaceDirectory(worktree, directory) {
15767
16062
  const configPrefix = getOpenCodeConfigPrefix();
16063
+ const envWorkspace = resolveCandidate(process.env.CURSOR_ACP_WORKSPACE);
16064
+ if (envWorkspace && !isRootPath(envWorkspace)) {
16065
+ return envWorkspace;
16066
+ }
16067
+ const envProjectDir = resolveCandidate(process.env.OPENCODE_CURSOR_PROJECT_DIR);
16068
+ if (envProjectDir && !isRootPath(envProjectDir)) {
16069
+ return envProjectDir;
16070
+ }
15768
16071
  const worktreeCandidate = resolveCandidate(worktree);
15769
- if (worktreeCandidate && !isWithinPath(configPrefix, worktreeCandidate)) {
16072
+ if (isAcceptableWorkspace(worktreeCandidate, configPrefix)) {
15770
16073
  return worktreeCandidate;
15771
16074
  }
15772
16075
  const dirCandidate = resolveCandidate(directory);
15773
- if (dirCandidate && !isWithinPath(configPrefix, dirCandidate)) {
16076
+ if (isAcceptableWorkspace(dirCandidate, configPrefix)) {
15774
16077
  return dirCandidate;
15775
16078
  }
15776
16079
  const cwd = resolve2(process.cwd());
15777
- if (cwd && !isWithinPath(configPrefix, cwd)) {
16080
+ if (isAcceptableWorkspace(cwd, configPrefix)) {
15778
16081
  return cwd;
15779
16082
  }
15780
- return dirCandidate || cwd || configPrefix;
16083
+ const home = resolveCandidate(homedir5());
16084
+ if (home && !isRootPath(home)) {
16085
+ return home;
16086
+ }
16087
+ return configPrefix;
15781
16088
  }
15782
16089
  function normalizeWorkspaceForCompare(pathValue) {
15783
- return resolve2(pathValue);
16090
+ const resolved = resolve2(pathValue);
16091
+ if (process.platform === "darwin" || process.platform === "win32") {
16092
+ return resolved.toLowerCase();
16093
+ }
16094
+ return resolved;
15784
16095
  }
15785
16096
  function isReusableProxyHealthPayload(payload, workspaceDirectory) {
15786
16097
  if (!payload || payload.ok !== true) {
@@ -15801,7 +16112,7 @@ function parseToolLoopMode(value) {
15801
16112
  function resolveChatParamTools(mode, existingTools, refreshedTools) {
15802
16113
  return PROVIDER_BOUNDARY.resolveChatParamTools(mode, existingTools, refreshedTools);
15803
16114
  }
15804
- function createChatCompletionResponse(model, content, reasoningContent) {
16115
+ function createChatCompletionResponse(model, content, reasoningContent, usage) {
15805
16116
  const message = {
15806
16117
  role: "assistant",
15807
16118
  content
@@ -15809,7 +16120,7 @@ function createChatCompletionResponse(model, content, reasoningContent) {
15809
16120
  if (reasoningContent && reasoningContent.length > 0) {
15810
16121
  message.reasoning_content = reasoningContent;
15811
16122
  }
15812
- return {
16123
+ const response = {
15813
16124
  id: `cursor-acp-${Date.now()}`,
15814
16125
  object: "chat.completion",
15815
16126
  created: Math.floor(Date.now() / 1000),
@@ -15822,6 +16133,10 @@ function createChatCompletionResponse(model, content, reasoningContent) {
15822
16133
  }
15823
16134
  ]
15824
16135
  };
16136
+ if (usage) {
16137
+ response.usage = usage;
16138
+ }
16139
+ return response;
15825
16140
  }
15826
16141
  function createChatCompletionChunk(id, created, model, deltaContent, done = false) {
15827
16142
  return {
@@ -15843,7 +16158,9 @@ function extractCompletionFromStream(output) {
15843
16158
  `);
15844
16159
  let assistantText = "";
15845
16160
  let reasoningText = "";
16161
+ let usage;
15846
16162
  let sawAssistantPartials = false;
16163
+ let sawThinkingPartials = false;
15847
16164
  for (const line of lines) {
15848
16165
  const event = parseStreamJsonLine(line);
15849
16166
  if (!event) {
@@ -15864,11 +16181,20 @@ function extractCompletionFromStream(output) {
15864
16181
  if (isThinking(event)) {
15865
16182
  const thinking = extractThinking(event);
15866
16183
  if (thinking) {
15867
- reasoningText += thinking;
16184
+ const isPartial = typeof event.timestamp_ms === "number";
16185
+ if (isPartial) {
16186
+ reasoningText += thinking;
16187
+ sawThinkingPartials = true;
16188
+ } else if (!sawThinkingPartials) {
16189
+ reasoningText = thinking;
16190
+ }
15868
16191
  }
15869
16192
  }
16193
+ if (isResult(event)) {
16194
+ usage = extractOpenAiUsageFromResult(event) ?? usage;
16195
+ }
15870
16196
  }
15871
- return { assistantText, reasoningText };
16197
+ return { assistantText, reasoningText, usage };
15872
16198
  }
15873
16199
  function formatToolUpdateEvent(update) {
15874
16200
  return `event: tool_update
@@ -15897,9 +16223,9 @@ function createBoundaryRuntimeContext(scope) {
15897
16223
  error: toErrorMessage(error)
15898
16224
  };
15899
16225
  if (!fallbackActive) {
15900
- log19.warn("Provider boundary v1 failed; switching to legacy for this request", details);
16226
+ log20.warn("Provider boundary v1 failed; switching to legacy for this request", details);
15901
16227
  } else {
15902
- log19.debug("Provider boundary fallback already active", details);
16228
+ log20.debug("Provider boundary fallback already active", details);
15903
16229
  }
15904
16230
  fallbackActive = true;
15905
16231
  return true;
@@ -16012,7 +16338,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16012
16338
  if (url.pathname === "/v1/models" || url.pathname === "/models") {
16013
16339
  try {
16014
16340
  const bunAny2 = globalThis;
16015
- const proc = bunAny2.Bun.spawn(["cursor-agent", "models"], {
16341
+ const proc = bunAny2.Bun.spawn([resolveCursorAgentBinary(), "models"], {
16016
16342
  stdout: "pipe",
16017
16343
  stderr: "pipe"
16018
16344
  });
@@ -16037,7 +16363,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16037
16363
  headers: { "Content-Type": "application/json" }
16038
16364
  });
16039
16365
  } catch (err) {
16040
- log19.error("Failed to list models", { error: String(err) });
16366
+ log20.error("Failed to list models", { error: String(err) });
16041
16367
  return new Response(JSON.stringify({ error: "Failed to fetch models from cursor-agent" }), {
16042
16368
  status: 500,
16043
16369
  headers: { "Content-Type": "application/json" }
@@ -16050,13 +16376,14 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16050
16376
  headers: { "Content-Type": "application/json" }
16051
16377
  });
16052
16378
  }
16053
- log19.debug("Proxy request (bun)", { method: req.method, path: url.pathname });
16379
+ log20.debug("Proxy request (bun)", { method: req.method, path: url.pathname });
16054
16380
  const body = await req.json().catch(() => ({}));
16055
16381
  const messages = Array.isArray(body?.messages) ? body.messages : [];
16056
16382
  const stream = body?.stream === true;
16057
16383
  const tools = Array.isArray(body?.tools) ? body.tools : [];
16058
16384
  debugLogToFile2("raw_request_body", {
16059
16385
  model: body?.model,
16386
+ cursorModel: body?.cursorModel,
16060
16387
  stream,
16061
16388
  toolCount: tools.length,
16062
16389
  toolNames: tools.map((t) => t?.function?.name ?? t?.name ?? "unknown"),
@@ -16071,14 +16398,14 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16071
16398
  const boundaryContext = createBoundaryRuntimeContext("bun-handler");
16072
16399
  const subagentNames = readSubagentNames();
16073
16400
  const prompt = buildPromptFromMessages(messages, tools, subagentNames);
16074
- const model = boundaryContext.run("normalizeRuntimeModel", (boundary) => boundary.normalizeRuntimeModel(body?.model));
16401
+ const model = boundaryContext.run("resolveRuntimeModel", (boundary) => boundary.resolveRuntimeModel(body?.model, body?.cursorModel));
16075
16402
  const msgSummaryBun = messages.map((m, i) => {
16076
16403
  const role = m?.role ?? "?";
16077
16404
  const hasTc = Array.isArray(m?.tool_calls) ? m.tool_calls.length : 0;
16078
16405
  const clen = typeof m?.content === "string" ? m.content.length : Array.isArray(m?.content) ? `arr${m.content.length}` : typeof m?.content;
16079
16406
  return `${i}:${role}${hasTc ? `(tc:${hasTc})` : ""}(clen:${clen})`;
16080
16407
  });
16081
- log19.debug("Proxy chat request (bun)", {
16408
+ log20.debug("Proxy chat request (bun)", {
16082
16409
  stream,
16083
16410
  model,
16084
16411
  messages: messages.length,
@@ -16094,7 +16421,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16094
16421
  });
16095
16422
  }
16096
16423
  const cmd = [
16097
- "cursor-agent",
16424
+ resolveCursorAgentBinary(),
16098
16425
  "--print",
16099
16426
  "--output-format",
16100
16427
  "stream-json",
@@ -16124,7 +16451,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16124
16451
  const stdout = (stdoutText || "").trim();
16125
16452
  const stderr = (stderrText || "").trim();
16126
16453
  const exitCode = await child.exited;
16127
- log19.debug("cursor-agent completed (bun non-stream)", {
16454
+ log20.debug("cursor-agent completed (bun non-stream)", {
16128
16455
  exitCode,
16129
16456
  stdoutChars: stdout.length,
16130
16457
  stderrChars: stderr.length
@@ -16150,7 +16477,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16150
16477
  });
16151
16478
  }
16152
16479
  if (intercepted.toolCall) {
16153
- log19.debug("Intercepted OpenCode tool call (non-stream)", {
16480
+ log20.debug("Intercepted OpenCode tool call (non-stream)", {
16154
16481
  name: intercepted.toolCall.function.name,
16155
16482
  callId: intercepted.toolCall.id
16156
16483
  });
@@ -16164,7 +16491,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16164
16491
  const errSource = stderr || stdout || `cursor-agent exited with code ${String(exitCode ?? "unknown")} and no output`;
16165
16492
  const parsed = parseAgentError(errSource);
16166
16493
  const userError = formatErrorForUser(parsed);
16167
- log19.error("cursor-cli failed", {
16494
+ log20.error("cursor-cli failed", {
16168
16495
  type: parsed.type,
16169
16496
  message: parsed.message,
16170
16497
  code: exitCode
@@ -16176,7 +16503,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16176
16503
  });
16177
16504
  }
16178
16505
  const completion = extractCompletionFromStream(stdout);
16179
- const payload = createChatCompletionResponse(model, completion.assistantText || stdout || stderr, completion.reasoningText || undefined);
16506
+ const payload = createChatCompletionResponse(model, completion.assistantText || stdout || stderr, completion.reasoningText || undefined, completion.usage);
16180
16507
  return new Response(JSON.stringify(payload), {
16181
16508
  status: 200,
16182
16509
  headers: { "Content-Type": "application/json" }
@@ -16194,12 +16521,13 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16194
16521
  async start(controller) {
16195
16522
  let streamTerminated = false;
16196
16523
  let firstTokenReceived = false;
16524
+ let usage;
16197
16525
  try {
16198
16526
  const reader = child.stdout.getReader();
16199
16527
  const converter = new StreamToSseConverter(model, { id, created });
16200
16528
  const lineBuffer = new LineBuffer;
16201
16529
  const emitToolCallAndTerminate = (toolCall) => {
16202
- log19.debug("Intercepted OpenCode tool call (stream)", {
16530
+ log20.debug("Intercepted OpenCode tool call (stream)", {
16203
16531
  name: toolCall.function.name,
16204
16532
  callId: toolCall.id
16205
16533
  });
@@ -16248,6 +16576,9 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16248
16576
  if (!event) {
16249
16577
  continue;
16250
16578
  }
16579
+ if (isResult(event)) {
16580
+ usage = extractOpenAiUsageFromResult(event) ?? usage;
16581
+ }
16251
16582
  if (event.type === "tool_call") {
16252
16583
  perf.mark("tool-call");
16253
16584
  const result = await handleToolLoopEventWithFallback({
@@ -16316,6 +16647,9 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16316
16647
  if (!event) {
16317
16648
  continue;
16318
16649
  }
16650
+ if (isResult(event)) {
16651
+ usage = extractOpenAiUsageFromResult(event) ?? usage;
16652
+ }
16319
16653
  if (event.type === "tool_call") {
16320
16654
  const result = await handleToolLoopEventWithFallback({
16321
16655
  event,
@@ -16381,7 +16715,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16381
16715
  const errSource = (stderrText || "").trim() || `cursor-agent exited with code ${String(exitCode ?? "unknown")} and no output`;
16382
16716
  const parsed = parseAgentError(errSource);
16383
16717
  const msg = formatErrorForUser(parsed);
16384
- log19.error("cursor-cli streaming failed", {
16718
+ log20.error("cursor-cli streaming failed", {
16385
16719
  type: parsed.type,
16386
16720
  code: exitCode
16387
16721
  });
@@ -16392,7 +16726,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16392
16726
  controller.enqueue(encoder.encode(formatSseDone()));
16393
16727
  return;
16394
16728
  }
16395
- log19.debug("cursor-agent completed (bun stream)", {
16729
+ log20.debug("cursor-agent completed (bun stream)", {
16396
16730
  exitCode
16397
16731
  });
16398
16732
  const passThroughSummary = passThroughTracker.getSummary();
@@ -16406,6 +16740,12 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16406
16740
  controller.enqueue(encoder.encode(`data: ${JSON.stringify(doneChunk)}
16407
16741
 
16408
16742
  `));
16743
+ if (usage) {
16744
+ const usageChunk = createChatCompletionUsageChunk(id, created, model, usage);
16745
+ controller.enqueue(encoder.encode(`data: ${JSON.stringify(usageChunk)}
16746
+
16747
+ `));
16748
+ }
16409
16749
  controller.enqueue(encoder.encode(formatSseDone()));
16410
16750
  } finally {
16411
16751
  perf.mark("request:done");
@@ -16455,8 +16795,8 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16455
16795
  }
16456
16796
  if (url.pathname === "/v1/models" || url.pathname === "/models") {
16457
16797
  try {
16458
- const { execSync } = await import("child_process");
16459
- const output = execSync("cursor-agent models", { encoding: "utf-8", timeout: 30000 });
16798
+ const { execFileSync: execFileSync2 } = await import("child_process");
16799
+ const output = execFileSync2(resolveCursorAgentBinary(), ["models"], { encoding: "utf-8", timeout: 30000 });
16460
16800
  const clean = stripAnsi(output);
16461
16801
  const models = [];
16462
16802
  for (const line of clean.split(`
@@ -16474,7 +16814,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16474
16814
  res.writeHead(200, { "Content-Type": "application/json" });
16475
16815
  res.end(JSON.stringify({ object: "list", data: models }));
16476
16816
  } catch (err) {
16477
- log19.error("Failed to list models", { error: String(err) });
16817
+ log20.error("Failed to list models", { error: String(err) });
16478
16818
  res.writeHead(500, { "Content-Type": "application/json" });
16479
16819
  res.end(JSON.stringify({ error: "Failed to fetch models" }));
16480
16820
  }
@@ -16485,7 +16825,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16485
16825
  res.end(JSON.stringify({ error: `Unsupported path: ${url.pathname}` }));
16486
16826
  return;
16487
16827
  }
16488
- log19.debug("Proxy request (node)", { method: req.method, path: url.pathname });
16828
+ log20.debug("Proxy request (node)", { method: req.method, path: url.pathname });
16489
16829
  let body = "";
16490
16830
  for await (const chunk of req) {
16491
16831
  body += chunk;
@@ -16500,7 +16840,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16500
16840
  const boundaryContext = createBoundaryRuntimeContext("node-handler");
16501
16841
  const subagentNames = readSubagentNames();
16502
16842
  const prompt = buildPromptFromMessages(messages, tools, subagentNames);
16503
- const model = boundaryContext.run("normalizeRuntimeModel", (boundary) => boundary.normalizeRuntimeModel(bodyData?.model));
16843
+ const model = boundaryContext.run("resolveRuntimeModel", (boundary) => boundary.resolveRuntimeModel(bodyData?.model, bodyData?.cursorModel));
16504
16844
  const msgSummary = messages.map((m, i) => {
16505
16845
  const role = m?.role ?? "?";
16506
16846
  const hasTc = Array.isArray(m?.tool_calls) ? m.tool_calls.length : 0;
@@ -16509,7 +16849,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16509
16849
  const contentLen = typeof m?.content === "string" ? m.content.length : Array.isArray(m?.content) ? `arr${m.content.length}` : typeof m?.content;
16510
16850
  return `${i}:${role}${hasTc ? `(tc:${hasTc})` : ""}${role === "tool" ? `(tcid:${tcId},name:${tcName},clen:${contentLen})` : `(clen:${contentLen})`}`;
16511
16851
  });
16512
- log19.debug("Proxy chat request (node)", {
16852
+ log20.debug("Proxy chat request (node)", {
16513
16853
  stream,
16514
16854
  model,
16515
16855
  messages: messages.length,
@@ -16518,7 +16858,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16518
16858
  msgRoles: msgSummary.join(",")
16519
16859
  });
16520
16860
  const cmd = [
16521
- "cursor-agent",
16861
+ resolveCursorAgentBinary(),
16522
16862
  "--print",
16523
16863
  "--output-format",
16524
16864
  "stream-json",
@@ -16531,7 +16871,10 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16531
16871
  if (FORCE_TOOL_MODE) {
16532
16872
  cmd.push("--force");
16533
16873
  }
16534
- const child = spawn3(cmd[0], cmd.slice(1), { stdio: ["pipe", "pipe", "pipe"] });
16874
+ const child = spawn3(cmd[0], cmd.slice(1), {
16875
+ stdio: ["pipe", "pipe", "pipe"],
16876
+ shell: process.platform === "win32"
16877
+ });
16535
16878
  child.stdin.write(prompt);
16536
16879
  child.stdin.end();
16537
16880
  if (!stream) {
@@ -16540,14 +16883,14 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16540
16883
  let spawnErrorText = null;
16541
16884
  child.on("error", (error) => {
16542
16885
  spawnErrorText = String(error?.message || error);
16543
- log19.error("Failed to spawn cursor-agent", { error: spawnErrorText, model });
16886
+ log20.error("Failed to spawn cursor-agent", { error: spawnErrorText, model });
16544
16887
  });
16545
16888
  child.stdout.on("data", (chunk) => stdoutChunks.push(chunk));
16546
16889
  child.stderr.on("data", (chunk) => stderrChunks.push(chunk));
16547
16890
  child.on("close", async (code) => {
16548
16891
  const stdout = Buffer.concat(stdoutChunks).toString().trim();
16549
16892
  const stderr = Buffer.concat(stderrChunks).toString().trim();
16550
- log19.debug("cursor-agent completed (node non-stream)", {
16893
+ log20.debug("cursor-agent completed (node non-stream)", {
16551
16894
  code,
16552
16895
  stdoutChars: stdout.length,
16553
16896
  stderrChars: stderr.length,
@@ -16573,7 +16916,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16573
16916
  return;
16574
16917
  }
16575
16918
  if (intercepted.toolCall) {
16576
- log19.debug("Intercepted OpenCode tool call (non-stream)", {
16919
+ log20.debug("Intercepted OpenCode tool call (non-stream)", {
16577
16920
  name: intercepted.toolCall.function.name,
16578
16921
  callId: intercepted.toolCall.id
16579
16922
  });
@@ -16587,7 +16930,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16587
16930
  const errSource = stderr || stdout || spawnErrorText || `cursor-agent exited with code ${String(code ?? "unknown")} and no output`;
16588
16931
  const parsed = parseAgentError(errSource);
16589
16932
  const userError = formatErrorForUser(parsed);
16590
- log19.error("cursor-cli failed", {
16933
+ log20.error("cursor-cli failed", {
16591
16934
  type: parsed.type,
16592
16935
  message: parsed.message,
16593
16936
  code
@@ -16597,7 +16940,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16597
16940
  res.end(JSON.stringify(errorResponse));
16598
16941
  return;
16599
16942
  }
16600
- const response = createChatCompletionResponse(model, completion.assistantText || stdout || stderr, completion.reasoningText || undefined);
16943
+ const response = createChatCompletionResponse(model, completion.assistantText || stdout || stderr, completion.reasoningText || undefined, completion.usage);
16601
16944
  res.writeHead(200, { "Content-Type": "application/json" });
16602
16945
  res.end(JSON.stringify(response));
16603
16946
  });
@@ -16619,6 +16962,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16619
16962
  const stderrChunks = [];
16620
16963
  let streamTerminated = false;
16621
16964
  let firstTokenReceived = false;
16965
+ let usage;
16622
16966
  child.stderr.on("data", (chunk) => {
16623
16967
  stderrChunks.push(Buffer.from(chunk));
16624
16968
  });
@@ -16627,7 +16971,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16627
16971
  return;
16628
16972
  }
16629
16973
  const errSource = String(error?.message || error);
16630
- log19.error("Failed to spawn cursor-agent (stream)", { error: errSource, model });
16974
+ log20.error("Failed to spawn cursor-agent (stream)", { error: errSource, model });
16631
16975
  const parsed = parseAgentError(errSource);
16632
16976
  const msg = formatErrorForUser(parsed);
16633
16977
  const errChunk = createChatCompletionChunk(id, created, model, msg, true);
@@ -16642,7 +16986,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16642
16986
  if (streamTerminated || res.writableEnded) {
16643
16987
  return;
16644
16988
  }
16645
- log19.debug("Intercepted OpenCode tool call (stream)", {
16989
+ log20.debug("Intercepted OpenCode tool call (stream)", {
16646
16990
  name: toolCall.function.name,
16647
16991
  callId: toolCall.id
16648
16992
  });
@@ -16690,6 +17034,9 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16690
17034
  if (!event) {
16691
17035
  continue;
16692
17036
  }
17037
+ if (isResult(event)) {
17038
+ usage = extractOpenAiUsageFromResult(event) ?? usage;
17039
+ }
16693
17040
  if (event.type === "tool_call") {
16694
17041
  perf.mark("tool-call");
16695
17042
  const result = await handleToolLoopEventWithFallback({
@@ -16762,6 +17109,9 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16762
17109
  if (!event) {
16763
17110
  continue;
16764
17111
  }
17112
+ if (isResult(event)) {
17113
+ usage = extractOpenAiUsageFromResult(event) ?? usage;
17114
+ }
16765
17115
  if (event.type === "tool_call") {
16766
17116
  const result = await handleToolLoopEventWithFallback({
16767
17117
  event,
@@ -16826,7 +17176,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16826
17176
  perf.mark("request:done");
16827
17177
  perf.summarize();
16828
17178
  const stderrText = Buffer.concat(stderrChunks).toString().trim();
16829
- log19.debug("cursor-agent completed (node stream)", {
17179
+ log20.debug("cursor-agent completed (node stream)", {
16830
17180
  code,
16831
17181
  stderrChars: stderrText.length
16832
17182
  });
@@ -16866,6 +17216,12 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
16866
17216
  res.write(`data: ${JSON.stringify(doneChunk)}
16867
17217
 
16868
17218
  `);
17219
+ if (usage) {
17220
+ const usageChunk = createChatCompletionUsageChunk(id, created, model, usage);
17221
+ res.write(`data: ${JSON.stringify(usageChunk)}
17222
+
17223
+ `);
17224
+ }
16869
17225
  res.write(formatSseDone());
16870
17226
  res.end();
16871
17227
  });
@@ -16943,7 +17299,7 @@ function jsonSchemaToZod(jsonSchema) {
16943
17299
  }
16944
17300
  break;
16945
17301
  case "object":
16946
- zodType = z2.record(z2.any());
17302
+ zodType = z2.record(z2.string(), z2.any());
16947
17303
  if (p.description) {
16948
17304
  zodType = zodType.describe(p.description);
16949
17305
  }
@@ -17054,7 +17410,7 @@ function buildToolHookEntries(registry, fallbackBaseDir) {
17054
17410
  const normalizedArgs = applyToolContextDefaults(toolName, args, context, fallbackBaseDir, sessionWorkspaceBySession);
17055
17411
  return await handler(normalizedArgs);
17056
17412
  } catch (error) {
17057
- log19.debug("Tool hook execution failed", { tool: toolName, error: String(error?.message || error) });
17413
+ log20.debug("Tool hook execution failed", { tool: toolName, error: String(error?.message || error) });
17058
17414
  throw error;
17059
17415
  }
17060
17416
  }
@@ -17066,9 +17422,9 @@ function buildToolHookEntries(registry, fallbackBaseDir) {
17066
17422
  }
17067
17423
  return entries;
17068
17424
  }
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 }) => {
17425
+ 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
17426
  const workspaceDirectory = resolveWorkspaceDirectory(worktree, directory);
17071
- log19.debug("Plugin initializing", {
17427
+ log20.debug("Plugin initializing", {
17072
17428
  directory,
17073
17429
  worktree,
17074
17430
  workspaceDirectory,
@@ -17076,22 +17432,22 @@ var log19, DEBUG_LOG_DIR2, DEBUG_LOG_FILE2, CURSOR_PROVIDER_ID2 = "cursor-acp",
17076
17432
  serverUrl: serverUrl?.toString()
17077
17433
  });
17078
17434
  if (!TOOL_LOOP_MODE_VALID) {
17079
- log19.warn("Invalid CURSOR_ACP_TOOL_LOOP_MODE; defaulting to opencode", { value: TOOL_LOOP_MODE_RAW });
17435
+ log20.warn("Invalid CURSOR_ACP_TOOL_LOOP_MODE; defaulting to opencode", { value: TOOL_LOOP_MODE_RAW });
17080
17436
  }
17081
17437
  if (!PROVIDER_BOUNDARY_MODE_VALID) {
17082
- log19.warn("Invalid CURSOR_ACP_PROVIDER_BOUNDARY; defaulting to v1", {
17438
+ log20.warn("Invalid CURSOR_ACP_PROVIDER_BOUNDARY; defaulting to v1", {
17083
17439
  value: PROVIDER_BOUNDARY_MODE_RAW
17084
17440
  });
17085
17441
  }
17086
17442
  if (!TOOL_LOOP_MAX_REPEAT_VALID) {
17087
- log19.warn("Invalid CURSOR_ACP_TOOL_LOOP_MAX_REPEAT; defaulting to 3", {
17443
+ log20.warn("Invalid CURSOR_ACP_TOOL_LOOP_MAX_REPEAT; defaulting to 3", {
17088
17444
  value: TOOL_LOOP_MAX_REPEAT_RAW
17089
17445
  });
17090
17446
  }
17091
17447
  if (ENABLE_PROVIDER_BOUNDARY_AUTOFALLBACK && PROVIDER_BOUNDARY.mode !== "v1") {
17092
- log19.debug("Provider boundary auto-fallback is enabled but inactive unless mode=v1");
17448
+ log20.debug("Provider boundary auto-fallback is enabled but inactive unless mode=v1");
17093
17449
  }
17094
- log19.info("Tool loop mode configured", {
17450
+ log20.info("Tool loop mode configured", {
17095
17451
  mode: TOOL_LOOP_MODE,
17096
17452
  providerBoundary: PROVIDER_BOUNDARY.mode,
17097
17453
  proxyExecToolCalls: PROXY_EXECUTE_TOOL_CALLS,
@@ -17109,13 +17465,13 @@ var log19, DEBUG_LOG_DIR2, DEBUG_LOG_FILE2, CURSOR_PROVIDER_ID2 = "cursor-acp",
17109
17465
  try {
17110
17466
  const configs = readMcpConfigs();
17111
17467
  if (configs.length === 0) {
17112
- log19.debug("No MCP servers configured, skipping MCP bridge");
17468
+ log20.debug("No MCP servers configured, skipping MCP bridge");
17113
17469
  } else {
17114
- log19.debug("MCP bridge: connecting to servers", { count: configs.length });
17470
+ log20.debug("MCP bridge: connecting to servers", { count: configs.length });
17115
17471
  await Promise.allSettled(configs.map((c) => mcpManager.connectServer(c)));
17116
17472
  const tools = mcpManager.listTools();
17117
17473
  if (tools.length === 0) {
17118
- log19.debug("MCP bridge: no tools discovered");
17474
+ log20.debug("MCP bridge: no tools discovered");
17119
17475
  } else {
17120
17476
  mcpToolEntries = buildMcpToolHookEntries(tools, mcpManager);
17121
17477
  mcpToolDefs = buildMcpToolDefinitions(tools);
@@ -17125,23 +17481,23 @@ var log19, DEBUG_LOG_DIR2, DEBUG_LOG_FILE2, CURSOR_PROVIDER_ID2 = "cursor-acp",
17125
17481
  description: t.description,
17126
17482
  params: t.inputSchema ? Object.keys(t.inputSchema.properties ?? {}) : undefined
17127
17483
  }));
17128
- log19.info("MCP bridge: registered tools", {
17484
+ log20.info("MCP bridge: registered tools", {
17129
17485
  servers: mcpManager.connectedServers.length,
17130
17486
  tools: Object.keys(mcpToolEntries).length
17131
17487
  });
17132
17488
  }
17133
17489
  }
17134
17490
  } catch (err) {
17135
- log19.debug("MCP bridge init failed", { error: String(err) });
17491
+ log20.debug("MCP bridge init failed", { error: String(err) });
17136
17492
  }
17137
17493
  }
17138
17494
  toastService.setClient(client3);
17139
17495
  const toolsEnabled = process.env.CURSOR_ACP_ENABLE_OPENCODE_TOOLS !== "false";
17140
17496
  const legacyProxyToolPathsEnabled = toolsEnabled && TOOL_LOOP_MODE === "proxy-exec";
17141
17497
  if (toolsEnabled && TOOL_LOOP_MODE === "opencode") {
17142
- log19.debug("OpenCode mode active; skipping legacy SDK/MCP discovery and proxy-side tool execution");
17498
+ log20.debug("OpenCode mode active; skipping legacy SDK/MCP discovery and proxy-side tool execution");
17143
17499
  } else if (toolsEnabled && TOOL_LOOP_MODE === "off") {
17144
- log19.debug("Tool loop mode off; proxy-side tool execution disabled");
17500
+ log20.debug("Tool loop mode off; proxy-side tool execution disabled");
17145
17501
  }
17146
17502
  const serverClient = legacyProxyToolPathsEnabled ? createOpencodeClient({ baseUrl: serverUrl.toString(), directory: workspaceDirectory }) : null;
17147
17503
  const discovery = legacyProxyToolPathsEnabled ? new OpenCodeToolDiscovery(serverClient ?? client3) : null;
@@ -17193,7 +17549,7 @@ var log19, DEBUG_LOG_DIR2, DEBUG_LOG_FILE2, CURSOR_PROVIDER_ID2 = "cursor-acp",
17193
17549
  discoveredList = await discovery.listTools();
17194
17550
  discoveredList.forEach((t) => toolsByName.set(t.name, t));
17195
17551
  } catch (err) {
17196
- log19.debug("Tool discovery failed, using local tools only", { error: String(err) });
17552
+ log20.debug("Tool discovery failed, using local tools only", { error: String(err) });
17197
17553
  }
17198
17554
  }
17199
17555
  const allTools = [...localTools, ...discoveredList];
@@ -17223,11 +17579,11 @@ var log19, DEBUG_LOG_DIR2, DEBUG_LOG_FILE2, CURSOR_PROVIDER_ID2 = "cursor-acp",
17223
17579
  }
17224
17580
  lastToolNames = toolEntries.map((e) => e.function.name);
17225
17581
  lastToolMap = allTools.map((t) => ({ id: t.id, name: t.name }));
17226
- log19.debug("Tools refreshed", { local: localTools.length, discovered: discoveredList.length, total: toolEntries.length });
17582
+ log20.debug("Tools refreshed", { local: localTools.length, discovered: discoveredList.length, total: toolEntries.length });
17227
17583
  return toolEntries;
17228
17584
  }
17229
17585
  const proxyBaseURL = await ensureCursorProxyServer(workspaceDirectory, router);
17230
- log19.debug("Proxy server started", { baseURL: proxyBaseURL });
17586
+ log20.debug("Proxy server started", { baseURL: proxyBaseURL });
17231
17587
  const toolHookEntries = buildToolHookEntries(localRegistry, workspaceDirectory);
17232
17588
  return {
17233
17589
  tool: { ...toolHookEntries, ...mcpToolEntries },
@@ -17242,9 +17598,9 @@ var log19, DEBUG_LOG_DIR2, DEBUG_LOG_FILE2, CURSOR_PROVIDER_ID2 = "cursor-acp",
17242
17598
  type: "oauth",
17243
17599
  async authorize() {
17244
17600
  try {
17245
- log19.info("Starting OAuth flow");
17601
+ log20.info("Starting OAuth flow");
17246
17602
  const { url, instructions, callback } = await startCursorOAuth();
17247
- log19.debug("Got OAuth URL", { url: url.substring(0, 50) + "..." });
17603
+ log20.debug("Got OAuth URL", { url: url.substring(0, 50) + "..." });
17248
17604
  return {
17249
17605
  url,
17250
17606
  instructions,
@@ -17252,7 +17608,7 @@ var log19, DEBUG_LOG_DIR2, DEBUG_LOG_FILE2, CURSOR_PROVIDER_ID2 = "cursor-acp",
17252
17608
  callback
17253
17609
  };
17254
17610
  } catch (error) {
17255
- log19.error("OAuth error", { error });
17611
+ log20.error("OAuth error", { error });
17256
17612
  throw error;
17257
17613
  }
17258
17614
  }
@@ -17276,10 +17632,10 @@ var log19, DEBUG_LOG_DIR2, DEBUG_LOG_FILE2, CURSOR_PROVIDER_ID2 = "cursor-acp",
17276
17632
  output.options.tools = resolved.tools;
17277
17633
  } else if (resolved.action === "preserve") {
17278
17634
  const count = Array.isArray(existingTools) ? existingTools.length : 0;
17279
- log19.debug("Using OpenCode-provided tools from chat.params", { count });
17635
+ log20.debug("Using OpenCode-provided tools from chat.params", { count });
17280
17636
  }
17281
17637
  } catch (err) {
17282
- log19.debug("Failed to refresh tools", { error: String(err) });
17638
+ log20.debug("Failed to refresh tools", { error: String(err) });
17283
17639
  }
17284
17640
  }
17285
17641
  if (mcpToolDefs.length > 0) {
@@ -17290,7 +17646,7 @@ var log19, DEBUG_LOG_DIR2, DEBUG_LOG_FILE2, CURSOR_PROVIDER_ID2 = "cursor-acp",
17290
17646
  output.options.tools = mcpToolDefs;
17291
17647
  }
17292
17648
  const afterTools = Array.isArray(output.options.tools) ? output.options.tools : [];
17293
- log19.debug("Injected MCP tool definitions into chat.params", {
17649
+ log20.debug("Injected MCP tool definitions into chat.params", {
17294
17650
  injectedCount: mcpToolDefs.length,
17295
17651
  beforeCount: beforeTools.length,
17296
17652
  afterCount: afterTools.length,
@@ -17331,14 +17687,16 @@ var init_plugin = __esm(() => {
17331
17687
  init_sdk();
17332
17688
  init_mcp();
17333
17689
  init_executor();
17690
+ init_defaults();
17334
17691
  init_boundary();
17335
17692
  init_runtime_interception();
17336
17693
  init_toast_service();
17337
17694
  init_tool_schema_compat();
17338
17695
  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");
17696
+ init_binary();
17697
+ log20 = createLogger("plugin");
17698
+ DEBUG_LOG_DIR2 = join6(homedir5(), ".config", "opencode", "logs");
17699
+ DEBUG_LOG_FILE2 = join6(DEBUG_LOG_DIR2, "tool-loop-debug.log");
17342
17700
  CURSOR_PROVIDER_PREFIX = `${CURSOR_PROVIDER_ID2}/`;
17343
17701
  CURSOR_PROXY_DEFAULT_BASE_URL = `http://${CURSOR_PROXY_HOST}:${CURSOR_PROXY_DEFAULT_PORT}/v1`;
17344
17702
  REUSE_EXISTING_PROXY = process.env.CURSOR_ACP_REUSE_EXISTING_PROXY !== "false";
@@ -17371,11 +17729,11 @@ var init_plugin = __esm(() => {
17371
17729
  // src/plugin-entry.ts
17372
17730
  init_plugin_toggle();
17373
17731
  init_logger();
17374
- var log20 = createLogger("plugin-entry");
17732
+ var log21 = createLogger("plugin-entry");
17375
17733
  var CursorPluginEntry = async (input) => {
17376
17734
  const state = shouldEnableCursorPlugin();
17377
17735
  if (!state.enabled) {
17378
- log20.info("Plugin disabled in OpenCode config; skipping initialization", {
17736
+ log21.info("Plugin disabled in OpenCode config; skipping initialization", {
17379
17737
  configPath: state.configPath,
17380
17738
  reason: state.reason
17381
17739
  });