@rama_nigg/open-cursor 2.1.7 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,5 +1,20 @@
1
1
  import { createRequire } from "node:module";
2
+ var __create = Object.create;
3
+ var __getProtoOf = Object.getPrototypeOf;
2
4
  var __defProp = Object.defineProperty;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __toESM = (mod, isNodeMode, target) => {
8
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
9
+ const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
10
+ for (let key of __getOwnPropNames(mod))
11
+ if (!__hasOwnProp.call(to, key))
12
+ __defProp(to, key, {
13
+ get: () => mod[key],
14
+ enumerable: true
15
+ });
16
+ return to;
17
+ };
3
18
  var __export = (target, all) => {
4
19
  for (var name in all)
5
20
  __defProp(target, name, {
@@ -12833,6 +12848,9 @@ ${result.output || "(no output)"}`
12833
12848
  }
12834
12849
 
12835
12850
  // src/utils/logger.ts
12851
+ import * as fs from "node:fs";
12852
+ import * as path from "node:path";
12853
+ import * as os from "node:os";
12836
12854
  function getConfiguredLevel() {
12837
12855
  const env = process.env.CURSOR_ACP_LOG_LEVEL?.toLowerCase();
12838
12856
  if (env && env in LEVEL_PRIORITY) {
@@ -12863,32 +12881,90 @@ function formatMessage(level, component, message, data) {
12863
12881
  }
12864
12882
  return formatted;
12865
12883
  }
12884
+ function isConsoleEnabled() {
12885
+ const consoleEnv = process.env.CURSOR_ACP_LOG_CONSOLE;
12886
+ return consoleEnv === "1" || consoleEnv === "true";
12887
+ }
12888
+ function ensureLogDir() {
12889
+ if (logDirEnsured)
12890
+ return;
12891
+ try {
12892
+ if (!fs.existsSync(LOG_DIR)) {
12893
+ fs.mkdirSync(LOG_DIR, { recursive: true });
12894
+ }
12895
+ logDirEnsured = true;
12896
+ } catch {
12897
+ logFileError = true;
12898
+ }
12899
+ }
12900
+ function rotateIfNeeded() {
12901
+ try {
12902
+ const stats = fs.statSync(LOG_FILE);
12903
+ if (stats.size >= MAX_LOG_SIZE) {
12904
+ const backupFile = LOG_FILE + ".1";
12905
+ fs.renameSync(LOG_FILE, backupFile);
12906
+ }
12907
+ } catch {}
12908
+ }
12909
+ function writeToFile(message) {
12910
+ if (logFileError)
12911
+ return;
12912
+ ensureLogDir();
12913
+ if (logFileError)
12914
+ return;
12915
+ try {
12916
+ rotateIfNeeded();
12917
+ const timestamp = new Date().toISOString();
12918
+ fs.appendFileSync(LOG_FILE, `${timestamp} ${message}
12919
+ `);
12920
+ } catch {
12921
+ if (!logFileError) {
12922
+ logFileError = true;
12923
+ console.error(`[cursor-acp] Failed to write logs. Using: ${LOG_FILE}`);
12924
+ }
12925
+ }
12926
+ }
12866
12927
  function createLogger(component) {
12867
12928
  return {
12868
12929
  debug: (message, data) => {
12869
- if (shouldLog("debug")) {
12870
- console.error(formatMessage("debug", component, message, data));
12871
- }
12930
+ if (!shouldLog("debug"))
12931
+ return;
12932
+ const formatted = formatMessage("debug", component, message, data);
12933
+ writeToFile(formatted);
12934
+ if (isConsoleEnabled())
12935
+ console.error(formatted);
12872
12936
  },
12873
12937
  info: (message, data) => {
12874
- if (shouldLog("info")) {
12875
- console.error(formatMessage("info", component, message, data));
12876
- }
12938
+ if (!shouldLog("info"))
12939
+ return;
12940
+ const formatted = formatMessage("info", component, message, data);
12941
+ writeToFile(formatted);
12942
+ if (isConsoleEnabled())
12943
+ console.error(formatted);
12877
12944
  },
12878
12945
  warn: (message, data) => {
12879
- if (shouldLog("warn")) {
12880
- console.error(formatMessage("warn", component, message, data));
12881
- }
12946
+ if (!shouldLog("warn"))
12947
+ return;
12948
+ const formatted = formatMessage("warn", component, message, data);
12949
+ writeToFile(formatted);
12950
+ if (isConsoleEnabled())
12951
+ console.error(formatted);
12882
12952
  },
12883
12953
  error: (message, data) => {
12884
- if (shouldLog("error")) {
12885
- console.error(formatMessage("error", component, message, data));
12886
- }
12954
+ if (!shouldLog("error"))
12955
+ return;
12956
+ const formatted = formatMessage("error", component, message, data);
12957
+ writeToFile(formatted);
12958
+ if (isConsoleEnabled())
12959
+ console.error(formatted);
12887
12960
  }
12888
12961
  };
12889
12962
  }
12890
- var LEVEL_PRIORITY;
12963
+ var LOG_DIR, LOG_FILE, MAX_LOG_SIZE, LEVEL_PRIORITY, logDirEnsured = false, logFileError = false;
12891
12964
  var init_logger = __esm(() => {
12965
+ LOG_DIR = path.join(os.homedir(), ".opencode-cursor");
12966
+ LOG_FILE = path.join(LOG_DIR, "plugin.log");
12967
+ MAX_LOG_SIZE = 5 * 1024 * 1024;
12892
12968
  LEVEL_PRIORITY = {
12893
12969
  debug: 0,
12894
12970
  info: 1,
@@ -12989,15 +13065,15 @@ function formatErrorForUser(error45) {
12989
13065
 
12990
13066
  // src/auth.ts
12991
13067
  import { spawn } from "child_process";
12992
- import { existsSync } from "fs";
12993
- import { homedir, platform } from "os";
12994
- import { join } from "path";
13068
+ import { existsSync as existsSync2 } from "fs";
13069
+ import { homedir as homedir2, platform } from "os";
13070
+ import { join as join2 } from "path";
12995
13071
  function getHomeDir() {
12996
13072
  const override = process.env.CURSOR_ACP_HOME_DIR;
12997
13073
  if (override && override.length > 0) {
12998
13074
  return override;
12999
13075
  }
13000
- return homedir();
13076
+ return homedir2();
13001
13077
  }
13002
13078
  async function pollForAuthFile(timeoutMs = AUTH_POLL_TIMEOUT, intervalMs = AUTH_POLL_INTERVAL) {
13003
13079
  const startTime = Date.now();
@@ -13006,7 +13082,7 @@ async function pollForAuthFile(timeoutMs = AUTH_POLL_TIMEOUT, intervalMs = AUTH_
13006
13082
  const check2 = () => {
13007
13083
  const elapsed = Date.now() - startTime;
13008
13084
  for (const authPath of possiblePaths) {
13009
- if (existsSync(authPath)) {
13085
+ if (existsSync2(authPath)) {
13010
13086
  log.debug("Auth file detected", { path: authPath });
13011
13087
  resolve(true);
13012
13088
  return;
@@ -13133,7 +13209,7 @@ async function startCursorOAuth() {
13133
13209
  function verifyCursorAuth() {
13134
13210
  const possiblePaths = getPossibleAuthPaths();
13135
13211
  for (const authPath of possiblePaths) {
13136
- if (existsSync(authPath)) {
13212
+ if (existsSync2(authPath)) {
13137
13213
  log.debug("Auth file found", { path: authPath });
13138
13214
  return true;
13139
13215
  }
@@ -13148,23 +13224,23 @@ function getPossibleAuthPaths() {
13148
13224
  const authFiles = ["cli-config.json", "auth.json"];
13149
13225
  if (isDarwin) {
13150
13226
  for (const file2 of authFiles) {
13151
- paths.push(join(home, ".cursor", file2));
13227
+ paths.push(join2(home, ".cursor", file2));
13152
13228
  }
13153
13229
  for (const file2 of authFiles) {
13154
- paths.push(join(home, ".config", "cursor", file2));
13230
+ paths.push(join2(home, ".config", "cursor", file2));
13155
13231
  }
13156
13232
  } else {
13157
13233
  for (const file2 of authFiles) {
13158
- paths.push(join(home, ".config", "cursor", file2));
13234
+ paths.push(join2(home, ".config", "cursor", file2));
13159
13235
  }
13160
13236
  const xdgConfig = process.env.XDG_CONFIG_HOME;
13161
- if (xdgConfig && xdgConfig !== join(home, ".config")) {
13237
+ if (xdgConfig && xdgConfig !== join2(home, ".config")) {
13162
13238
  for (const file2 of authFiles) {
13163
- paths.push(join(xdgConfig, "cursor", file2));
13239
+ paths.push(join2(xdgConfig, "cursor", file2));
13164
13240
  }
13165
13241
  }
13166
13242
  for (const file2 of authFiles) {
13167
- paths.push(join(home, ".cursor", file2));
13243
+ paths.push(join2(home, ".cursor", file2));
13168
13244
  }
13169
13245
  }
13170
13246
  return paths;
@@ -13172,7 +13248,7 @@ function getPossibleAuthPaths() {
13172
13248
  function getAuthFilePath() {
13173
13249
  const possiblePaths = getPossibleAuthPaths();
13174
13250
  for (const authPath of possiblePaths) {
13175
- if (existsSync(authPath)) {
13251
+ if (existsSync2(authPath)) {
13176
13252
  return authPath;
13177
13253
  }
13178
13254
  }
@@ -13400,7 +13476,68 @@ var init_perf = __esm(() => {
13400
13476
  });
13401
13477
 
13402
13478
  // src/proxy/prompt-builder.ts
13479
+ import { appendFileSync as appendFileSync2, existsSync as existsSync3, mkdirSync as mkdirSync2 } from "node:fs";
13480
+ import { homedir as homedir3 } from "node:os";
13481
+ import { join as join3 } from "node:path";
13482
+ function ensureLogDir2() {
13483
+ try {
13484
+ if (!existsSync3(DEBUG_LOG_DIR)) {
13485
+ mkdirSync2(DEBUG_LOG_DIR, { recursive: true });
13486
+ }
13487
+ } catch {}
13488
+ }
13489
+ function debugLogToFile(message, data) {
13490
+ try {
13491
+ ensureLogDir2();
13492
+ const timestamp = new Date().toISOString();
13493
+ const logLine = `[${timestamp}] ${message}: ${JSON.stringify(data, null, 2)}
13494
+ `;
13495
+ appendFileSync2(DEBUG_LOG_FILE, logLine);
13496
+ } catch (err) {
13497
+ log4.debug(message, data);
13498
+ }
13499
+ }
13403
13500
  function buildPromptFromMessages(messages, tools) {
13501
+ const messageSummary = messages.map((m, i) => {
13502
+ const role = m?.role ?? "?";
13503
+ const hasToolCalls = Array.isArray(m?.tool_calls) ? m.tool_calls.length : 0;
13504
+ const tcNames = hasToolCalls > 0 ? m.tool_calls.map((tc) => tc?.function?.name).join(",") : "";
13505
+ const contentType = typeof m?.content;
13506
+ const contentLen = typeof m?.content === "string" ? m.content.length : Array.isArray(m?.content) ? `arr:${m.content.length}` : "null";
13507
+ const toolCallId = m?.tool_call_id ?? null;
13508
+ return { i, role, hasToolCalls, tcNames, contentType, contentLen, toolCallId };
13509
+ });
13510
+ const assistantWithToolCalls = messages.filter((m) => m?.role === "assistant" && Array.isArray(m?.tool_calls) && m.tool_calls.length > 0);
13511
+ const assistantEmpty = messages.filter((m) => m?.role === "assistant" && (!m?.tool_calls || m.tool_calls.length === 0) && (!m?.content || m.content === "" || m.content === null));
13512
+ const toolResults = messages.filter((m) => m?.role === "tool");
13513
+ debugLogToFile("buildPromptFromMessages", {
13514
+ totalMessages: messages.length,
13515
+ totalTools: tools.length,
13516
+ messageSummary,
13517
+ stats: {
13518
+ assistantWithToolCalls: assistantWithToolCalls.length,
13519
+ assistantEmpty: assistantEmpty.length,
13520
+ toolResults: toolResults.length
13521
+ },
13522
+ assistantDetails: assistantWithToolCalls.length > 0 ? assistantWithToolCalls.map((m, i) => ({
13523
+ index: i,
13524
+ toolCallCount: Array.isArray(m?.tool_calls) ? m.tool_calls.length : 0,
13525
+ toolCallIds: Array.isArray(m?.tool_calls) ? m.tool_calls.map((tc) => tc?.id).join(",") : "",
13526
+ toolCallNames: Array.isArray(m?.tool_calls) ? m.tool_calls.map((tc) => tc?.function?.name).join(",") : "",
13527
+ contentType: typeof m?.content,
13528
+ contentPreview: typeof m?.content === "string" ? m.content.slice(0, 50) : typeof m?.content
13529
+ })) : [],
13530
+ emptyAssistantDetails: assistantEmpty.length > 0 ? assistantEmpty.map((m, i) => ({
13531
+ index: i,
13532
+ contentType: typeof m?.content,
13533
+ contentPreview: typeof m?.content === "string" ? m.content.slice(0, 50) : typeof m?.content
13534
+ })) : [],
13535
+ toolResultDetails: toolResults.length > 0 ? toolResults.map((m, i) => ({
13536
+ index: i,
13537
+ toolCallId: m?.tool_call_id,
13538
+ contentPreview: typeof m?.content === "string" ? m.content.slice(0, 100) : typeof m?.content
13539
+ })) : []
13540
+ });
13404
13541
  const lines = [];
13405
13542
  if (tools.length > 0) {
13406
13543
  const toolDescs = tools.map((t) => {
@@ -13414,6 +13551,7 @@ function buildPromptFromMessages(messages, tools) {
13414
13551
  }).join(`
13415
13552
  `);
13416
13553
  lines.push(`SYSTEM: You have access to the following tools. When you need to use one, respond with a tool_call in the standard OpenAI format.
13554
+ ` + `Tool guidance: prefer write/edit for file changes; use bash mainly to run commands/tests.
13417
13555
 
13418
13556
  Available tools:
13419
13557
  ${toolDescs}`);
@@ -13453,10 +13591,30 @@ ${toolDescs}`);
13453
13591
  }
13454
13592
  }
13455
13593
  }
13456
- return lines.join(`
13594
+ const hasToolResults = messages.some((m) => m?.role === "tool");
13595
+ if (hasToolResults) {
13596
+ lines.push("The above tool calls have been executed. Continue your response based on these results.");
13597
+ }
13598
+ const finalPrompt = lines.join(`
13457
13599
 
13458
13600
  `);
13459
- }
13601
+ debugLogToFile("buildPromptFromMessages: final prompt", {
13602
+ lineCount: lines.length,
13603
+ promptLength: finalPrompt.length,
13604
+ promptPreview: finalPrompt.slice(0, 500),
13605
+ hasToolResultFormat: finalPrompt.includes("TOOL_RESULT"),
13606
+ hasAssistantToolCallFormat: finalPrompt.includes("tool_call(id:"),
13607
+ hasCompletionSignal: finalPrompt.includes("Based on the tool results")
13608
+ });
13609
+ return finalPrompt;
13610
+ }
13611
+ var log4, DEBUG_LOG_DIR, DEBUG_LOG_FILE;
13612
+ var init_prompt_builder = __esm(() => {
13613
+ init_logger();
13614
+ log4 = createLogger("proxy:prompt-builder");
13615
+ DEBUG_LOG_DIR = join3(homedir3(), ".config", "opencode", "logs");
13616
+ DEBUG_LOG_FILE = join3(DEBUG_LOG_DIR, "tool-loop-debug.log");
13617
+ });
13460
13618
 
13461
13619
  // src/proxy/tool-loop.ts
13462
13620
  function extractAllowedToolNames(tools) {
@@ -13482,7 +13640,7 @@ function extractOpenAiToolCall(event, allowedToolNames) {
13482
13640
  }
13483
13641
  const resolvedName = resolveAllowedToolName(name, allowedToolNames);
13484
13642
  if (!resolvedName) {
13485
- log4.debug("Tool call name not allowed; skipping interception", {
13643
+ log5.debug("Tool call name not allowed; skipping interception", {
13486
13644
  name,
13487
13645
  normalized: normalizeAliasKey(name),
13488
13646
  allowedToolCount: allowedToolNames.size,
@@ -13491,7 +13649,7 @@ function extractOpenAiToolCall(event, allowedToolNames) {
13491
13649
  return null;
13492
13650
  }
13493
13651
  if (args === undefined && event.subtype === "started") {
13494
- log4.debug("Tool call args extraction returned undefined", {
13652
+ log5.debug("Tool call args extraction returned undefined", {
13495
13653
  toolName: name,
13496
13654
  subtype: event.subtype ?? "none",
13497
13655
  payloadKeys: Object.entries(event.tool_call || {}).map(([k, v]) => `${k}:[${isRecord(v) ? Object.keys(v).join(",") : typeof v}]`),
@@ -13647,10 +13805,10 @@ function toOpenAiArguments(args) {
13647
13805
  function isRecord(value) {
13648
13806
  return typeof value === "object" && value !== null && !Array.isArray(value);
13649
13807
  }
13650
- var log4, TOOL_NAME_ALIASES;
13808
+ var log5, TOOL_NAME_ALIASES;
13651
13809
  var init_tool_loop = __esm(() => {
13652
13810
  init_logger();
13653
- log4 = createLogger("proxy:tool-loop");
13811
+ log5 = createLogger("proxy:tool-loop");
13654
13812
  TOOL_NAME_ALIASES = new Map([
13655
13813
  ["runcommand", "bash"],
13656
13814
  ["executecommand", "bash"],
@@ -13764,7 +13922,7 @@ class OpenCodeToolDiscovery {
13764
13922
  const mcpTools = await this.tryListMcpTools();
13765
13923
  tools = tools.concat(mcpTools);
13766
13924
  } catch (err) {
13767
- log5.debug("SDK tool.list failed, will try CLI", { error: String(err) });
13925
+ log6.debug("SDK tool.list failed, will try CLI", { error: String(err) });
13768
13926
  }
13769
13927
  }
13770
13928
  if (tools.length === 0 && this.executorPref !== "sdk") {
@@ -13776,10 +13934,10 @@ class OpenCodeToolDiscovery {
13776
13934
  if (parsed?.data?.tools?.length) {
13777
13935
  tools = parsed.data.tools.map((t) => this.normalize(t, "cli"));
13778
13936
  } else {
13779
- log5.debug("CLI tool list failed", { status: res.status, stderr: res.stderr });
13937
+ log6.debug("CLI tool list failed", { status: res.status, stderr: res.stderr });
13780
13938
  }
13781
13939
  } catch (err) {
13782
- log5.debug("CLI tool list error", { error: String(err) });
13940
+ log6.debug("CLI tool list error", { error: String(err) });
13783
13941
  }
13784
13942
  }
13785
13943
  const map2 = new Map;
@@ -13815,7 +13973,7 @@ class OpenCodeToolDiscovery {
13815
13973
  return [];
13816
13974
  return mcpList.data.tools.map((t) => this.normalize(t, "mcp"));
13817
13975
  } catch (err) {
13818
- log5.debug("MCP tool discovery skipped", { error: String(err) });
13976
+ log6.debug("MCP tool discovery skipped", { error: String(err) });
13819
13977
  return [];
13820
13978
  }
13821
13979
  }
@@ -13836,11 +13994,11 @@ class OpenCodeToolDiscovery {
13836
13994
  return null;
13837
13995
  }
13838
13996
  }
13839
- var log5;
13997
+ var log6;
13840
13998
  var init_discovery = __esm(() => {
13841
13999
  init_logger();
13842
14000
  init_strip_ansi();
13843
- log5 = createLogger("tools:discovery");
14001
+ log6 = createLogger("tools:discovery");
13844
14002
  });
13845
14003
 
13846
14004
  // src/tools/schema.ts
@@ -13897,10 +14055,10 @@ function describeTool(t) {
13897
14055
  const base = t.description || "OpenCode tool";
13898
14056
  return base.length > 400 ? base.slice(0, 400) : base;
13899
14057
  }
13900
- var log6;
14058
+ var log7;
13901
14059
  var init_schema = __esm(() => {
13902
14060
  init_logger();
13903
- log6 = createLogger("tools:schema");
14061
+ log7 = createLogger("tools:schema");
13904
14062
  });
13905
14063
 
13906
14064
  // src/tools/router.ts
@@ -13925,18 +14083,18 @@ class ToolRouter {
13925
14083
  }
13926
14084
  const tool3 = this.ctx.toolsByName.get(name);
13927
14085
  if (!tool3) {
13928
- log7.warn("Unknown tool call", { name });
14086
+ log8.warn("Unknown tool call", { name });
13929
14087
  return this.buildResult(meta, callId, name, { status: "error", error: `Unknown tool ${name}` });
13930
14088
  }
13931
14089
  const args = this.extractArgs(event);
13932
- log7.debug("Executing tool", { name, toolId: tool3.id });
14090
+ log8.debug("Executing tool", { name, toolId: tool3.id });
13933
14091
  const t0 = Date.now();
13934
14092
  const result = await this.ctx.execute(tool3.id, args);
13935
14093
  const elapsed = Date.now() - t0;
13936
14094
  if (result.status === "error") {
13937
- log7.warn("Tool execution returned error", { name, error: result.error, elapsed });
14095
+ log8.warn("Tool execution returned error", { name, error: result.error, elapsed });
13938
14096
  } else {
13939
- log7.debug("Tool execution completed", { name, toolId: tool3.id, elapsed });
14097
+ log8.debug("Tool execution completed", { name, toolId: tool3.id, elapsed });
13940
14098
  }
13941
14099
  return this.buildResult(meta, callId, name, result);
13942
14100
  }
@@ -13985,10 +14143,10 @@ class ToolRouter {
13985
14143
  };
13986
14144
  }
13987
14145
  }
13988
- var log7;
14146
+ var log8;
13989
14147
  var init_router = __esm(() => {
13990
14148
  init_logger();
13991
- log7 = createLogger("tools:router");
14149
+ log8 = createLogger("tools:router");
13992
14150
  });
13993
14151
 
13994
14152
  // src/tools/skills/loader.ts
@@ -14300,7 +14458,7 @@ var separatorArrayExplode = (style) => {
14300
14458
  };
14301
14459
 
14302
14460
  // node_modules/@opencode-ai/sdk/dist/gen/core/utils.gen.js
14303
- var PATH_PARAM_RE, defaultPathSerializer = ({ path, url: _url2 }) => {
14461
+ var PATH_PARAM_RE, defaultPathSerializer = ({ path: path2, url: _url2 }) => {
14304
14462
  let url2 = _url2;
14305
14463
  const matches = _url2.match(PATH_PARAM_RE);
14306
14464
  if (matches) {
@@ -14319,7 +14477,7 @@ var PATH_PARAM_RE, defaultPathSerializer = ({ path, url: _url2 }) => {
14319
14477
  name = name.substring(1);
14320
14478
  style = "matrix";
14321
14479
  }
14322
- const value = path[name];
14480
+ const value = path2[name];
14323
14481
  if (value === undefined || value === null) {
14324
14482
  continue;
14325
14483
  }
@@ -14349,11 +14507,11 @@ var PATH_PARAM_RE, defaultPathSerializer = ({ path, url: _url2 }) => {
14349
14507
  }
14350
14508
  }
14351
14509
  return url2;
14352
- }, getUrl = ({ baseUrl, path, query, querySerializer, url: _url2 }) => {
14510
+ }, getUrl = ({ baseUrl, path: path2, query, querySerializer, url: _url2 }) => {
14353
14511
  const pathUrl = _url2.startsWith("/") ? _url2 : `/${_url2}`;
14354
14512
  let url2 = (baseUrl ?? "") + pathUrl;
14355
- if (path) {
14356
- url2 = defaultPathSerializer({ path, url: url2 });
14513
+ if (path2) {
14514
+ url2 = defaultPathSerializer({ path: path2, url: url2 });
14357
14515
  }
14358
14516
  let search = query ? querySerializer(query) : "";
14359
14517
  if (search.startsWith("?")) {
@@ -15474,15 +15632,15 @@ class LocalExecutor {
15474
15632
  const out = await handler(args);
15475
15633
  return { status: "success", output: out };
15476
15634
  } catch (err) {
15477
- log8.warn("Local tool execution failed", { toolId, error: String(err?.message || err) });
15635
+ log9.warn("Local tool execution failed", { toolId, error: String(err?.message || err) });
15478
15636
  return { status: "error", error: String(err?.message || err) };
15479
15637
  }
15480
15638
  }
15481
15639
  }
15482
- var log8;
15640
+ var log9;
15483
15641
  var init_local = __esm(() => {
15484
15642
  init_logger();
15485
- log8 = createLogger("tools:executor:local");
15643
+ log9 = createLogger("tools:executor:local");
15486
15644
  });
15487
15645
 
15488
15646
  // src/tools/executors/sdk.ts
@@ -15509,7 +15667,7 @@ class SdkExecutor {
15509
15667
  const out = typeof res === "string" ? res : JSON.stringify(res);
15510
15668
  return { status: "success", output: out };
15511
15669
  } catch (err) {
15512
- log9.warn("SDK tool execution failed", { toolId, error: String(err?.message || err) });
15670
+ log10.warn("SDK tool execution failed", { toolId, error: String(err?.message || err) });
15513
15671
  return { status: "error", error: String(err?.message || err) };
15514
15672
  }
15515
15673
  }
@@ -15522,10 +15680,10 @@ class SdkExecutor {
15522
15680
  ]);
15523
15681
  }
15524
15682
  }
15525
- var log9;
15683
+ var log10;
15526
15684
  var init_sdk = __esm(() => {
15527
15685
  init_logger();
15528
- log9 = createLogger("tools:executor:sdk");
15686
+ log10 = createLogger("tools:executor:sdk");
15529
15687
  });
15530
15688
 
15531
15689
  // src/tools/executors/mcp.ts
@@ -15552,7 +15710,7 @@ class McpExecutor {
15552
15710
  const out = typeof res === "string" ? res : JSON.stringify(res);
15553
15711
  return { status: "success", output: out };
15554
15712
  } catch (err) {
15555
- log10.warn("MCP tool execution failed", { toolId, error: String(err?.message || err) });
15713
+ log11.warn("MCP tool execution failed", { toolId, error: String(err?.message || err) });
15556
15714
  return { status: "error", error: String(err?.message || err) };
15557
15715
  }
15558
15716
  }
@@ -15565,10 +15723,10 @@ class McpExecutor {
15565
15723
  ]);
15566
15724
  }
15567
15725
  }
15568
- var log10;
15726
+ var log11;
15569
15727
  var init_mcp = __esm(() => {
15570
15728
  init_logger();
15571
- log10 = createLogger("tools:executor:mcp");
15729
+ log11 = createLogger("tools:executor:mcp");
15572
15730
  });
15573
15731
 
15574
15732
  // src/tools/core/executor.ts
@@ -15578,17 +15736,17 @@ async function executeWithChain(executors, toolId, args) {
15578
15736
  try {
15579
15737
  return await ex.execute(toolId, args);
15580
15738
  } catch (err) {
15581
- log11.warn("Executor threw unexpected error", { toolId, error: String(err?.message || err) });
15739
+ log12.warn("Executor threw unexpected error", { toolId, error: String(err?.message || err) });
15582
15740
  return { status: "error", error: String(err?.message || err) };
15583
15741
  }
15584
15742
  }
15585
15743
  }
15586
15744
  return { status: "error", error: `No executor available for ${toolId}` };
15587
15745
  }
15588
- var log11;
15746
+ var log12;
15589
15747
  var init_executor = __esm(() => {
15590
15748
  init_logger();
15591
- log11 = createLogger("tools:executor:chain");
15749
+ log12 = createLogger("tools:executor:chain");
15592
15750
  });
15593
15751
 
15594
15752
  // src/tools/defaults.ts
@@ -15596,7 +15754,7 @@ function registerDefaultTools(registry2) {
15596
15754
  registry2.register({
15597
15755
  id: "bash",
15598
15756
  name: "bash",
15599
- description: "Execute a shell command in a safe environment",
15757
+ description: "Execute a shell command. Use this to run programs/tests; prefer write/edit for creating or modifying files.",
15600
15758
  parameters: {
15601
15759
  type: "object",
15602
15760
  properties: {
@@ -15660,12 +15818,12 @@ function registerDefaultTools(registry2) {
15660
15818
  },
15661
15819
  source: "local"
15662
15820
  }, async (args) => {
15663
- const fs = await import("fs");
15821
+ const fs2 = await import("fs");
15664
15822
  try {
15665
- const path = args.path;
15823
+ const path2 = args.path;
15666
15824
  const offset = args.offset;
15667
15825
  const limit = args.limit;
15668
- let content = fs.readFileSync(path, "utf-8");
15826
+ let content = fs2.readFileSync(path2, "utf-8");
15669
15827
  if (offset !== undefined || limit !== undefined) {
15670
15828
  const lines = content.split(`
15671
15829
  `);
@@ -15682,7 +15840,7 @@ function registerDefaultTools(registry2) {
15682
15840
  registry2.register({
15683
15841
  id: "write",
15684
15842
  name: "write",
15685
- description: "Write content to a file (creates or overwrites)",
15843
+ description: "Write content to a file (creates or overwrites). Prefer this over using bash redirection/heredocs for file creation.",
15686
15844
  parameters: {
15687
15845
  type: "object",
15688
15846
  properties: {
@@ -15699,16 +15857,16 @@ function registerDefaultTools(registry2) {
15699
15857
  },
15700
15858
  source: "local"
15701
15859
  }, async (args) => {
15702
- const fs = await import("fs");
15703
- const path = await import("path");
15860
+ const fs2 = await import("fs");
15861
+ const path2 = await import("path");
15704
15862
  try {
15705
15863
  const filePath = args.path;
15706
15864
  const content = args.content;
15707
- const dir = path.dirname(filePath);
15708
- if (!fs.existsSync(dir)) {
15709
- fs.mkdirSync(dir, { recursive: true });
15865
+ const dir = path2.dirname(filePath);
15866
+ if (!fs2.existsSync(dir)) {
15867
+ fs2.mkdirSync(dir, { recursive: true });
15710
15868
  }
15711
- fs.writeFileSync(filePath, content, "utf-8");
15869
+ fs2.writeFileSync(filePath, content, "utf-8");
15712
15870
  return `File written successfully: ${filePath}`;
15713
15871
  } catch (error45) {
15714
15872
  throw error45;
@@ -15717,7 +15875,7 @@ function registerDefaultTools(registry2) {
15717
15875
  registry2.register({
15718
15876
  id: "edit",
15719
15877
  name: "edit",
15720
- description: "Edit a file by replacing old text with new text",
15878
+ description: "Edit a file by replacing old text with new text. Use for targeted replacements; use write to overwrite an entire file.",
15721
15879
  parameters: {
15722
15880
  type: "object",
15723
15881
  properties: {
@@ -15738,8 +15896,8 @@ function registerDefaultTools(registry2) {
15738
15896
  },
15739
15897
  source: "local"
15740
15898
  }, async (args) => {
15741
- const fs = await import("fs");
15742
- const path = await import("path");
15899
+ const fs2 = await import("fs");
15900
+ const path2 = await import("path");
15743
15901
  try {
15744
15902
  const resolvedArgs = resolveEditArguments(args);
15745
15903
  const filePath = resolvedArgs.path;
@@ -15756,27 +15914,27 @@ function registerDefaultTools(registry2) {
15756
15914
  }
15757
15915
  let content = "";
15758
15916
  try {
15759
- content = fs.readFileSync(filePath, "utf-8");
15917
+ content = fs2.readFileSync(filePath, "utf-8");
15760
15918
  } catch (error45) {
15761
15919
  if (error45?.code === "ENOENT") {
15762
- const dir = path.dirname(filePath);
15763
- if (!fs.existsSync(dir)) {
15764
- fs.mkdirSync(dir, { recursive: true });
15920
+ const dir = path2.dirname(filePath);
15921
+ if (!fs2.existsSync(dir)) {
15922
+ fs2.mkdirSync(dir, { recursive: true });
15765
15923
  }
15766
- fs.writeFileSync(filePath, newString, "utf-8");
15924
+ fs2.writeFileSync(filePath, newString, "utf-8");
15767
15925
  return `File did not exist. Created and wrote content: ${filePath}`;
15768
15926
  }
15769
15927
  throw error45;
15770
15928
  }
15771
15929
  if (!oldString) {
15772
- fs.writeFileSync(filePath, newString, "utf-8");
15930
+ fs2.writeFileSync(filePath, newString, "utf-8");
15773
15931
  return `File edited successfully: ${filePath}`;
15774
15932
  }
15775
15933
  if (!content.includes(oldString)) {
15776
15934
  return `Error: Could not find the text to replace in ${filePath}`;
15777
15935
  }
15778
15936
  content = content.replaceAll(oldString, newString);
15779
- fs.writeFileSync(filePath, content, "utf-8");
15937
+ fs2.writeFileSync(filePath, content, "utf-8");
15780
15938
  return `File edited successfully: ${filePath}`;
15781
15939
  } catch (error45) {
15782
15940
  throw error45;
@@ -15810,13 +15968,13 @@ function registerDefaultTools(registry2) {
15810
15968
  const { promisify } = await import("util");
15811
15969
  const execFileAsync = promisify(execFile);
15812
15970
  const pattern = args.pattern;
15813
- const path = args.path;
15971
+ const path2 = args.path;
15814
15972
  const include = args.include;
15815
15973
  const grepArgs = ["-r", "-n"];
15816
15974
  if (include) {
15817
15975
  grepArgs.push(`--include=${include}`);
15818
15976
  }
15819
- grepArgs.push(pattern, path);
15977
+ grepArgs.push(pattern, path2);
15820
15978
  const runGrep = async (extraArgs = []) => {
15821
15979
  return execFileAsync("grep", [...extraArgs, ...grepArgs], { timeout: 30000 });
15822
15980
  };
@@ -15859,11 +16017,11 @@ function registerDefaultTools(registry2) {
15859
16017
  },
15860
16018
  source: "local"
15861
16019
  }, async (args) => {
15862
- const fs = await import("fs");
15863
- const path = await import("path");
16020
+ const fs2 = await import("fs");
16021
+ const path2 = await import("path");
15864
16022
  try {
15865
16023
  const dirPath = args.path;
15866
- const entries = fs.readdirSync(dirPath, { withFileTypes: true });
16024
+ const entries = fs2.readdirSync(dirPath, { withFileTypes: true });
15867
16025
  const result = entries.map((entry) => {
15868
16026
  const type = entry.isDirectory() ? "d" : entry.isSymbolicLink() ? "l" : entry.isFile() ? "f" : "?";
15869
16027
  return `[${type}] ${entry.name}`;
@@ -15901,8 +16059,8 @@ function registerDefaultTools(registry2) {
15901
16059
  if (!pattern) {
15902
16060
  throw new Error("glob: missing required argument 'pattern'");
15903
16061
  }
15904
- const path = resolvePathArg(args, "glob");
15905
- const cwd = path || ".";
16062
+ const path2 = resolvePathArg(args, "glob");
16063
+ const cwd = path2 || ".";
15906
16064
  const normalizedPattern = pattern.replace(/\\/g, "/");
15907
16065
  const isPathPattern = normalizedPattern.includes("/");
15908
16066
  const findArgs = [cwd, "-type", "f"];
@@ -16030,7 +16188,7 @@ function registerDefaultTools(registry2) {
16030
16188
  });
16031
16189
  }
16032
16190
  function resolveEditArguments(args) {
16033
- const path = typeof args.path === "string" ? args.path : "";
16191
+ const path2 = typeof args.path === "string" ? args.path : "";
16034
16192
  let oldString = typeof args.old_string === "string" ? args.old_string : undefined;
16035
16193
  let newString = typeof args.new_string === "string" ? args.new_string : undefined;
16036
16194
  if (newString === undefined) {
@@ -16043,7 +16201,7 @@ function resolveEditArguments(args) {
16043
16201
  oldString = "";
16044
16202
  }
16045
16203
  return {
16046
- path,
16204
+ path: path2,
16047
16205
  old_string: oldString,
16048
16206
  new_string: newString
16049
16207
  };
@@ -16386,6 +16544,23 @@ function normalizeToolSpecificArgs(toolName, args) {
16386
16544
  todos
16387
16545
  };
16388
16546
  }
16547
+ if (normalizedToolName === "write") {
16548
+ const normalized = { ...args };
16549
+ if (normalized.content === undefined && normalized.new_string !== undefined) {
16550
+ const coerced = coerceToString2(normalized.new_string);
16551
+ if (coerced !== null) {
16552
+ normalized.content = coerced;
16553
+ }
16554
+ delete normalized.new_string;
16555
+ }
16556
+ if (normalized.content !== undefined && typeof normalized.content !== "string") {
16557
+ const coerced = coerceToString2(normalized.content);
16558
+ if (coerced !== null) {
16559
+ normalized.content = coerced;
16560
+ }
16561
+ }
16562
+ return normalized;
16563
+ }
16389
16564
  if (normalizedToolName !== "edit" || !EDIT_COMPAT_REPAIR_ENABLED) {
16390
16565
  return args;
16391
16566
  }
@@ -16628,6 +16803,9 @@ var init_tool_schema_compat = __esm(() => {
16628
16803
  ["terminalcommand", "command"],
16629
16804
  ["contents", "content"],
16630
16805
  ["text", "content"],
16806
+ ["body", "content"],
16807
+ ["data", "content"],
16808
+ ["payload", "content"],
16631
16809
  ["streamcontent", "content"],
16632
16810
  ["recursive", "force"],
16633
16811
  ["oldstring", "old_string"],
@@ -16641,7 +16819,7 @@ async function handleToolLoopEventLegacy(options) {
16641
16819
  event,
16642
16820
  toolLoopMode,
16643
16821
  allowedToolNames,
16644
- toolSchemaMap: _toolSchemaMap,
16822
+ toolSchemaMap,
16645
16823
  toolLoopGuard,
16646
16824
  toolMapper,
16647
16825
  toolSessionId,
@@ -16656,11 +16834,44 @@ async function handleToolLoopEventLegacy(options) {
16656
16834
  } = options;
16657
16835
  const interceptedToolCall = toolLoopMode === "opencode" ? extractOpenAiToolCall(event, allowedToolNames) : null;
16658
16836
  if (interceptedToolCall) {
16659
- const termination = evaluateToolLoopGuard(toolLoopGuard, interceptedToolCall);
16837
+ const compat2 = applyToolSchemaCompat(interceptedToolCall, toolSchemaMap);
16838
+ let normalizedToolCall = compat2.toolCall;
16839
+ log13.debug("Applied tool schema compatibility (legacy)", {
16840
+ tool: normalizedToolCall.function.name,
16841
+ originalArgKeys: compat2.originalArgKeys,
16842
+ normalizedArgKeys: compat2.normalizedArgKeys,
16843
+ collisionKeys: compat2.collisionKeys,
16844
+ validationOk: compat2.validation.ok
16845
+ });
16846
+ if (compat2.validation.hasSchema && !compat2.validation.ok) {
16847
+ const validationTermination = evaluateSchemaValidationLoopGuard(toolLoopGuard, normalizedToolCall, compat2.validation);
16848
+ if (validationTermination) {
16849
+ return { intercepted: false, skipConverter: true, terminate: validationTermination };
16850
+ }
16851
+ const reroutedWrite = tryRerouteEditToWrite(normalizedToolCall, compat2.normalizedArgs, allowedToolNames, toolSchemaMap);
16852
+ if (reroutedWrite) {
16853
+ log13.debug("Rerouting malformed edit call to write (legacy)", {
16854
+ path: reroutedWrite.path,
16855
+ missing: compat2.validation.missing,
16856
+ typeErrors: compat2.validation.typeErrors
16857
+ });
16858
+ normalizedToolCall = reroutedWrite.toolCall;
16859
+ } else if (shouldEmitNonFatalSchemaValidationHint(normalizedToolCall, compat2.validation)) {
16860
+ const hintChunk = createNonFatalSchemaValidationHintChunk(responseMeta, normalizedToolCall, compat2.validation);
16861
+ log13.debug("Emitting non-fatal schema validation hint in legacy and skipping malformed tool execution", {
16862
+ tool: normalizedToolCall.function.name,
16863
+ missing: compat2.validation.missing,
16864
+ typeErrors: compat2.validation.typeErrors
16865
+ });
16866
+ await onToolResult(hintChunk);
16867
+ return { intercepted: false, skipConverter: true };
16868
+ }
16869
+ }
16870
+ const termination = evaluateToolLoopGuard(toolLoopGuard, normalizedToolCall);
16660
16871
  if (termination) {
16661
16872
  return { intercepted: false, skipConverter: true, terminate: termination };
16662
16873
  }
16663
- await onInterceptedToolCall(interceptedToolCall);
16874
+ await onInterceptedToolCall(normalizedToolCall);
16664
16875
  return { intercepted: true, skipConverter: true };
16665
16876
  }
16666
16877
  const updates = await toolMapper.mapCursorEventToAcp(event, event.session_id ?? toolSessionId);
@@ -16713,7 +16924,7 @@ async function handleToolLoopEventV1(options) {
16713
16924
  rawArgs: safeArgTypeSummary(event),
16714
16925
  normalizedArgs: compat2.normalizedArgs
16715
16926
  } : undefined;
16716
- log12.debug("Applied tool schema compatibility", {
16927
+ log13.debug("Applied tool schema compatibility", {
16717
16928
  tool: interceptedToolCall.function.name,
16718
16929
  originalArgKeys: compat2.originalArgKeys,
16719
16930
  normalizedArgKeys: compat2.normalizedArgKeys,
@@ -16722,7 +16933,7 @@ async function handleToolLoopEventV1(options) {
16722
16933
  ...editDiag ? { editDiag } : {}
16723
16934
  });
16724
16935
  if (compat2.validation.hasSchema && !compat2.validation.ok) {
16725
- log12.warn("Tool schema compatibility validation failed", {
16936
+ log13.debug("Tool schema compatibility validation failed", {
16726
16937
  tool: interceptedToolCall.function.name,
16727
16938
  missing: compat2.validation.missing,
16728
16939
  unexpected: compat2.validation.unexpected,
@@ -16739,7 +16950,7 @@ async function handleToolLoopEventV1(options) {
16739
16950
  }
16740
16951
  const reroutedWrite = tryRerouteEditToWrite(interceptedToolCall, compat2.normalizedArgs, allowedToolNames, toolSchemaMap);
16741
16952
  if (reroutedWrite) {
16742
- log12.info("Rerouting malformed edit call to write", {
16953
+ log13.debug("Rerouting malformed edit call to write", {
16743
16954
  path: reroutedWrite.path,
16744
16955
  missing: compat2.validation.missing,
16745
16956
  typeErrors: compat2.validation.typeErrors
@@ -16759,7 +16970,7 @@ async function handleToolLoopEventV1(options) {
16759
16970
  }
16760
16971
  if (schemaValidationFailureMode === "pass_through" && shouldEmitNonFatalSchemaValidationHint(interceptedToolCall, compat2.validation)) {
16761
16972
  const hintChunk = createNonFatalSchemaValidationHintChunk(responseMeta, interceptedToolCall, compat2.validation);
16762
- log12.debug("Emitting non-fatal schema validation hint and skipping malformed tool execution", {
16973
+ log13.debug("Emitting non-fatal schema validation hint and skipping malformed tool execution", {
16763
16974
  tool: interceptedToolCall.function.name,
16764
16975
  missing: compat2.validation.missing,
16765
16976
  typeErrors: compat2.validation.typeErrors
@@ -16777,7 +16988,7 @@ async function handleToolLoopEventV1(options) {
16777
16988
  terminate: createSchemaValidationTermination(interceptedToolCall, compat2.validation)
16778
16989
  };
16779
16990
  }
16780
- log12.debug("Forwarding schema-invalid tool call to OpenCode loop", {
16991
+ log13.debug("Forwarding schema-invalid tool call to OpenCode loop", {
16781
16992
  tool: interceptedToolCall.function.name,
16782
16993
  repairHint: compat2.validation.repairHint
16783
16994
  });
@@ -16856,16 +17067,28 @@ function evaluateToolLoopGuard(toolLoopGuard, toolCall) {
16856
17067
  if (!decision.triggered) {
16857
17068
  return null;
16858
17069
  }
16859
- log12.warn("Tool loop guard triggered", {
17070
+ log13.debug("Tool loop guard triggered", {
16860
17071
  tool: toolCall.function.name,
16861
17072
  fingerprint: decision.fingerprint,
16862
17073
  repeatCount: decision.repeatCount,
16863
17074
  maxRepeat: decision.maxRepeat,
16864
17075
  errorClass: decision.errorClass
16865
17076
  });
17077
+ if (decision.errorClass === "success") {
17078
+ return {
17079
+ reason: "loop_guard",
17080
+ message: "",
17081
+ tool: toolCall.function.name,
17082
+ fingerprint: decision.fingerprint,
17083
+ repeatCount: decision.repeatCount,
17084
+ maxRepeat: decision.maxRepeat,
17085
+ errorClass: decision.errorClass,
17086
+ silent: true
17087
+ };
17088
+ }
16866
17089
  return {
16867
17090
  reason: "loop_guard",
16868
- message: decision.errorClass === "success" ? `Tool loop guard stopped repeated successful calls to "${toolCall.function.name}" ` + `after ${decision.repeatCount} attempts (limit ${decision.maxRepeat}). ` + "This likely indicates a model/tool-call loop; adjust prompt or tool strategy and retry." : `Tool loop guard stopped repeated failing calls to "${toolCall.function.name}" ` + `after ${decision.repeatCount} attempts (limit ${decision.maxRepeat}). ` + "Adjust tool arguments and retry.",
17091
+ message: `Tool loop guard stopped repeated failing calls to "${toolCall.function.name}" ` + `after ${decision.repeatCount} attempts (limit ${decision.maxRepeat}). ` + "Adjust tool arguments and retry.",
16869
17092
  tool: toolCall.function.name,
16870
17093
  fingerprint: decision.fingerprint,
16871
17094
  repeatCount: decision.repeatCount,
@@ -16903,7 +17126,7 @@ function evaluateSchemaValidationLoopGuard(toolLoopGuard, toolCall, validation)
16903
17126
  if (!decision.tracked || !decision.triggered) {
16904
17127
  return null;
16905
17128
  }
16906
- log12.warn("Tool loop guard triggered on schema validation", {
17129
+ log13.warn("Tool loop guard triggered on schema validation", {
16907
17130
  tool: toolCall.function.name,
16908
17131
  fingerprint: decision.fingerprint,
16909
17132
  repeatCount: decision.repeatCount,
@@ -17036,8 +17259,8 @@ function tryRerouteEditToWrite(toolCall, normalizedArgs, allowedToolNames, toolS
17036
17259
  if (!allowedToolNames.has("write") || !toolSchemaMap.has("write")) {
17037
17260
  return null;
17038
17261
  }
17039
- const path = typeof normalizedArgs.path === "string" && normalizedArgs.path.length > 0 ? normalizedArgs.path : null;
17040
- if (!path) {
17262
+ const path2 = typeof normalizedArgs.path === "string" && normalizedArgs.path.length > 0 ? normalizedArgs.path : null;
17263
+ if (!path2) {
17041
17264
  return null;
17042
17265
  }
17043
17266
  const content = typeof normalizedArgs.new_string === "string" ? normalizedArgs.new_string : typeof normalizedArgs.content === "string" ? normalizedArgs.content : null;
@@ -17049,12 +17272,12 @@ function tryRerouteEditToWrite(toolCall, normalizedArgs, allowedToolNames, toolS
17049
17272
  return null;
17050
17273
  }
17051
17274
  return {
17052
- path,
17275
+ path: path2,
17053
17276
  toolCall: {
17054
17277
  ...toolCall,
17055
17278
  function: {
17056
17279
  name: "write",
17057
- arguments: JSON.stringify({ path, content })
17280
+ arguments: JSON.stringify({ path: path2, content })
17058
17281
  }
17059
17282
  }
17060
17283
  };
@@ -17062,12 +17285,12 @@ function tryRerouteEditToWrite(toolCall, normalizedArgs, allowedToolNames, toolS
17062
17285
  function isRecord3(value) {
17063
17286
  return typeof value === "object" && value !== null && !Array.isArray(value);
17064
17287
  }
17065
- var log12, ToolBoundaryExtractionError;
17288
+ var log13, ToolBoundaryExtractionError;
17066
17289
  var init_runtime_interception = __esm(() => {
17067
17290
  init_tool_loop();
17068
17291
  init_logger();
17069
17292
  init_tool_schema_compat();
17070
- log12 = createLogger("provider:runtime-interception");
17293
+ log13 = createLogger("provider:runtime-interception");
17071
17294
  ToolBoundaryExtractionError = class ToolBoundaryExtractionError extends Error {
17072
17295
  cause;
17073
17296
  constructor(message, cause) {
@@ -17081,11 +17304,11 @@ var init_runtime_interception = __esm(() => {
17081
17304
  // src/provider/tool-loop-guard.ts
17082
17305
  function parseToolLoopMaxRepeat(value) {
17083
17306
  if (value === undefined) {
17084
- return { value: 3, valid: true };
17307
+ return { value: 2, valid: true };
17085
17308
  }
17086
17309
  const parsed = Number(value);
17087
17310
  if (!Number.isFinite(parsed) || parsed < 1) {
17088
- return { value: 3, valid: false };
17311
+ return { value: 2, valid: false };
17089
17312
  }
17090
17313
  return { value: Math.floor(parsed), valid: true };
17091
17314
  }
@@ -17314,8 +17537,8 @@ function deriveSuccessCoarseFingerprint(toolName, rawArguments) {
17314
17537
  if (!isRecord4(parsed)) {
17315
17538
  return null;
17316
17539
  }
17317
- const path = typeof parsed.path === "string" ? parsed.path : "";
17318
- if (!path) {
17540
+ const path2 = typeof parsed.path === "string" ? parsed.path : "";
17541
+ if (!path2) {
17319
17542
  return null;
17320
17543
  }
17321
17544
  if (lowered === "edit") {
@@ -17324,7 +17547,7 @@ function deriveSuccessCoarseFingerprint(toolName, rawArguments) {
17324
17547
  return null;
17325
17548
  }
17326
17549
  }
17327
- return `${toolName}|path:${hashString(path)}|success`;
17550
+ return `${toolName}|path:${hashString(path2)}|success`;
17328
17551
  } catch {
17329
17552
  return null;
17330
17553
  }
@@ -17512,6 +17735,7 @@ var UNKNOWN_AS_SUCCESS_TOOLS;
17512
17735
  var init_tool_loop_guard = __esm(() => {
17513
17736
  UNKNOWN_AS_SUCCESS_TOOLS = new Set([
17514
17737
  "bash",
17738
+ "shell",
17515
17739
  "read",
17516
17740
  "write",
17517
17741
  "edit",
@@ -17519,38 +17743,62 @@ var init_tool_loop_guard = __esm(() => {
17519
17743
  "ls",
17520
17744
  "glob",
17521
17745
  "stat",
17522
- "webfetch"
17746
+ "webfetch",
17747
+ "mkdir",
17748
+ "rm"
17523
17749
  ]);
17524
17750
  });
17525
17751
 
17526
17752
  // src/plugin.ts
17527
17753
  var exports_plugin = {};
17528
17754
  __export(exports_plugin, {
17755
+ shouldProcessModel: () => shouldProcessModel,
17529
17756
  resolveChatParamTools: () => resolveChatParamTools,
17530
17757
  ensurePluginDirectory: () => ensurePluginDirectory,
17531
17758
  default: () => plugin_default,
17532
17759
  CursorPlugin: () => CursorPlugin
17533
17760
  });
17534
- import { realpathSync } from "fs";
17761
+ import { appendFileSync as appendFileSync3, existsSync as existsSync4, realpathSync } from "fs";
17535
17762
  import { mkdir } from "fs/promises";
17536
- import { homedir as homedir2 } from "os";
17537
- import { isAbsolute, join as join2, relative, resolve } from "path";
17763
+ import { homedir as homedir4 } from "os";
17764
+ import { isAbsolute, join as join4, relative, resolve } from "path";
17765
+ function ensureDebugLogDir() {
17766
+ try {
17767
+ if (!existsSync4(DEBUG_LOG_DIR2)) {
17768
+ mkdir(DEBUG_LOG_DIR2, { recursive: true }).catch(() => {});
17769
+ }
17770
+ } catch {}
17771
+ }
17772
+ function debugLogToFile2(message, data) {
17773
+ try {
17774
+ ensureDebugLogDir();
17775
+ const timestamp = new Date().toISOString();
17776
+ const logLine = `[${timestamp}] ${message}: ${JSON.stringify(data, null, 2)}
17777
+ `;
17778
+ appendFileSync3(DEBUG_LOG_FILE2, logLine);
17779
+ } catch {}
17780
+ }
17538
17781
  async function ensurePluginDirectory() {
17539
- const configHome = process.env.XDG_CONFIG_HOME ? resolve(process.env.XDG_CONFIG_HOME) : join2(homedir2(), ".config");
17540
- const pluginDir = join2(configHome, "opencode", "plugin");
17782
+ const configHome = process.env.XDG_CONFIG_HOME ? resolve(process.env.XDG_CONFIG_HOME) : join4(homedir4(), ".config");
17783
+ const pluginDir = join4(configHome, "opencode", "plugin");
17541
17784
  try {
17542
17785
  await mkdir(pluginDir, { recursive: true });
17543
- log13.debug("Plugin directory ensured", { path: pluginDir });
17786
+ log14.debug("Plugin directory ensured", { path: pluginDir });
17544
17787
  } catch (error45) {
17545
- log13.warn("Failed to create plugin directory", { error: String(error45) });
17788
+ log14.warn("Failed to create plugin directory", { error: String(error45) });
17546
17789
  }
17547
17790
  }
17791
+ function shouldProcessModel(model) {
17792
+ if (!model)
17793
+ return false;
17794
+ return model.startsWith(CURSOR_PROVIDER_PREFIX);
17795
+ }
17548
17796
  function getGlobalKey() {
17549
17797
  return "__opencode_cursor_proxy_server__";
17550
17798
  }
17551
17799
  function getOpenCodeConfigPrefix() {
17552
- const configHome = process.env.XDG_CONFIG_HOME ? resolve(process.env.XDG_CONFIG_HOME) : join2(homedir2(), ".config");
17553
- return join2(configHome, "opencode");
17800
+ const configHome = process.env.XDG_CONFIG_HOME ? resolve(process.env.XDG_CONFIG_HOME) : join4(homedir4(), ".config");
17801
+ return join4(configHome, "opencode");
17554
17802
  }
17555
17803
  function canonicalizePathForCompare(pathValue) {
17556
17804
  const resolvedPath = resolve(pathValue);
@@ -17713,9 +17961,9 @@ function createBoundaryRuntimeContext(scope) {
17713
17961
  error: toErrorMessage(error45)
17714
17962
  };
17715
17963
  if (!fallbackActive) {
17716
- log13.warn("Provider boundary v1 failed; switching to legacy for this request", details);
17964
+ log14.warn("Provider boundary v1 failed; switching to legacy for this request", details);
17717
17965
  } else {
17718
- log13.debug("Provider boundary fallback already active", details);
17966
+ log14.debug("Provider boundary fallback already active", details);
17719
17967
  }
17720
17968
  fallbackActive = true;
17721
17969
  return true;
@@ -17792,7 +18040,7 @@ async function findFirstAllowedToolCallInOutput(output, options) {
17792
18040
  if (result.terminate) {
17793
18041
  return {
17794
18042
  toolCall: null,
17795
- terminationMessage: result.terminate.message
18043
+ terminationMessage: result.terminate.silent ? null : result.terminate.message
17796
18044
  };
17797
18045
  }
17798
18046
  if (result.intercepted && interceptedToolCall) {
@@ -17849,7 +18097,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
17849
18097
  headers: { "Content-Type": "application/json" }
17850
18098
  });
17851
18099
  } catch (err) {
17852
- log13.error("Failed to list models", { error: String(err) });
18100
+ log14.error("Failed to list models", { error: String(err) });
17853
18101
  return new Response(JSON.stringify({ error: "Failed to fetch models from cursor-agent" }), {
17854
18102
  status: 500,
17855
18103
  headers: { "Content-Type": "application/json" }
@@ -17862,11 +18110,21 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
17862
18110
  headers: { "Content-Type": "application/json" }
17863
18111
  });
17864
18112
  }
17865
- log13.debug("Proxy request (bun)", { method: req.method, path: url2.pathname });
18113
+ log14.debug("Proxy request (bun)", { method: req.method, path: url2.pathname });
17866
18114
  const body = await req.json().catch(() => ({}));
17867
18115
  const messages = Array.isArray(body?.messages) ? body.messages : [];
17868
18116
  const stream = body?.stream === true;
17869
18117
  const tools = Array.isArray(body?.tools) ? body.tools : [];
18118
+ debugLogToFile2("raw_request_body", {
18119
+ model: body?.model,
18120
+ stream,
18121
+ toolCount: tools.length,
18122
+ toolNames: tools.map((t) => t?.function?.name ?? t?.name ?? "unknown"),
18123
+ messageCount: messages.length,
18124
+ messageRoles: messages.map((m) => m?.role),
18125
+ hasMessagesWithToolCalls: messages.some((m) => Array.isArray(m?.tool_calls) && m.tool_calls.length > 0),
18126
+ hasToolResultMessages: messages.some((m) => m?.role === "tool")
18127
+ });
17870
18128
  const allowedToolNames = extractAllowedToolNames(tools);
17871
18129
  const toolSchemaMap = buildToolSchemaMap(tools);
17872
18130
  const toolLoopGuard = createToolLoopGuard(messages, TOOL_LOOP_MAX_REPEAT);
@@ -17879,7 +18137,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
17879
18137
  const clen = typeof m?.content === "string" ? m.content.length : Array.isArray(m?.content) ? `arr${m.content.length}` : typeof m?.content;
17880
18138
  return `${i}:${role}${hasTc ? `(tc:${hasTc})` : ""}(clen:${clen})`;
17881
18139
  });
17882
- log13.debug("Proxy chat request (bun)", {
18140
+ log14.debug("Proxy chat request (bun)", {
17883
18141
  stream,
17884
18142
  model,
17885
18143
  messages: messages.length,
@@ -17925,7 +18183,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
17925
18183
  const stdout = (stdoutText || "").trim();
17926
18184
  const stderr = (stderrText || "").trim();
17927
18185
  const exitCode = child.exitCode;
17928
- log13.debug("cursor-agent completed (bun non-stream)", {
18186
+ log14.debug("cursor-agent completed (bun non-stream)", {
17929
18187
  exitCode,
17930
18188
  stdoutChars: stdout.length,
17931
18189
  stderrChars: stderr.length
@@ -17951,7 +18209,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
17951
18209
  });
17952
18210
  }
17953
18211
  if (intercepted.toolCall) {
17954
- log13.debug("Intercepted OpenCode tool call (non-stream)", {
18212
+ log14.debug("Intercepted OpenCode tool call (non-stream)", {
17955
18213
  name: intercepted.toolCall.function.name,
17956
18214
  callId: intercepted.toolCall.id
17957
18215
  });
@@ -17965,7 +18223,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
17965
18223
  const errSource = stderr || stdout || `cursor-agent exited with code ${String(exitCode ?? "unknown")} and no output`;
17966
18224
  const parsed = parseAgentError(errSource);
17967
18225
  const userError = formatErrorForUser(parsed);
17968
- log13.error("cursor-cli failed", {
18226
+ log14.error("cursor-cli failed", {
17969
18227
  type: parsed.type,
17970
18228
  message: parsed.message,
17971
18229
  code: exitCode
@@ -17999,7 +18257,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
17999
18257
  const converter = new StreamToSseConverter(model, { id, created });
18000
18258
  const lineBuffer = new LineBuffer;
18001
18259
  const emitToolCallAndTerminate = (toolCall) => {
18002
- log13.debug("Intercepted OpenCode tool call (stream)", {
18260
+ log14.debug("Intercepted OpenCode tool call (stream)", {
18003
18261
  name: toolCall.function.name,
18004
18262
  callId: toolCall.id
18005
18263
  });
@@ -18082,7 +18340,15 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
18082
18340
  }
18083
18341
  });
18084
18342
  if (result.terminate) {
18085
- emitTerminalAssistantErrorAndTerminate(result.terminate.message);
18343
+ if (!result.terminate.silent) {
18344
+ emitTerminalAssistantErrorAndTerminate(result.terminate.message);
18345
+ } else {
18346
+ controller.enqueue(encoder.encode(formatSseDone()));
18347
+ streamTerminated = true;
18348
+ try {
18349
+ child.kill();
18350
+ } catch {}
18351
+ }
18086
18352
  break;
18087
18353
  }
18088
18354
  if (result.intercepted) {
@@ -18140,7 +18406,15 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
18140
18406
  }
18141
18407
  });
18142
18408
  if (result.terminate) {
18143
- emitTerminalAssistantErrorAndTerminate(result.terminate.message);
18409
+ if (!result.terminate.silent) {
18410
+ emitTerminalAssistantErrorAndTerminate(result.terminate.message);
18411
+ } else {
18412
+ controller.enqueue(encoder.encode(formatSseDone()));
18413
+ streamTerminated = true;
18414
+ try {
18415
+ child.kill();
18416
+ } catch {}
18417
+ }
18144
18418
  break;
18145
18419
  }
18146
18420
  if (result.intercepted) {
@@ -18162,7 +18436,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
18162
18436
  const errSource = (stderrText || "").trim() || `cursor-agent exited with code ${String(child.exitCode ?? "unknown")} and no output`;
18163
18437
  const parsed = parseAgentError(errSource);
18164
18438
  const msg = formatErrorForUser(parsed);
18165
- log13.error("cursor-cli streaming failed", {
18439
+ log14.error("cursor-cli streaming failed", {
18166
18440
  type: parsed.type,
18167
18441
  code: child.exitCode
18168
18442
  });
@@ -18173,7 +18447,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
18173
18447
  controller.enqueue(encoder.encode(formatSseDone()));
18174
18448
  return;
18175
18449
  }
18176
- log13.debug("cursor-agent completed (bun stream)", {
18450
+ log14.debug("cursor-agent completed (bun stream)", {
18177
18451
  exitCode: child.exitCode
18178
18452
  });
18179
18453
  const doneChunk = createChatCompletionChunk(id, created, model, "", true);
@@ -18244,7 +18518,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
18244
18518
  res.writeHead(200, { "Content-Type": "application/json" });
18245
18519
  res.end(JSON.stringify({ object: "list", data: models }));
18246
18520
  } catch (err) {
18247
- log13.error("Failed to list models", { error: String(err) });
18521
+ log14.error("Failed to list models", { error: String(err) });
18248
18522
  res.writeHead(500, { "Content-Type": "application/json" });
18249
18523
  res.end(JSON.stringify({ error: "Failed to fetch models" }));
18250
18524
  }
@@ -18255,7 +18529,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
18255
18529
  res.end(JSON.stringify({ error: `Unsupported path: ${url2.pathname}` }));
18256
18530
  return;
18257
18531
  }
18258
- log13.debug("Proxy request (node)", { method: req.method, path: url2.pathname });
18532
+ log14.debug("Proxy request (node)", { method: req.method, path: url2.pathname });
18259
18533
  let body = "";
18260
18534
  for await (const chunk of req) {
18261
18535
  body += chunk;
@@ -18278,7 +18552,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
18278
18552
  const contentLen = typeof m?.content === "string" ? m.content.length : Array.isArray(m?.content) ? `arr${m.content.length}` : typeof m?.content;
18279
18553
  return `${i}:${role}${hasTc ? `(tc:${hasTc})` : ""}${role === "tool" ? `(tcid:${tcId},name:${tcName},clen:${contentLen})` : `(clen:${contentLen})`}`;
18280
18554
  });
18281
- log13.debug("Proxy chat request (node)", {
18555
+ log14.debug("Proxy chat request (node)", {
18282
18556
  stream,
18283
18557
  model,
18284
18558
  messages: messages.length,
@@ -18309,14 +18583,14 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
18309
18583
  let spawnErrorText = null;
18310
18584
  child.on("error", (error45) => {
18311
18585
  spawnErrorText = String(error45?.message || error45);
18312
- log13.error("Failed to spawn cursor-agent", { error: spawnErrorText, model });
18586
+ log14.error("Failed to spawn cursor-agent", { error: spawnErrorText, model });
18313
18587
  });
18314
18588
  child.stdout.on("data", (chunk) => stdoutChunks.push(chunk));
18315
18589
  child.stderr.on("data", (chunk) => stderrChunks.push(chunk));
18316
18590
  child.on("close", async (code) => {
18317
18591
  const stdout = Buffer.concat(stdoutChunks).toString().trim();
18318
18592
  const stderr = Buffer.concat(stderrChunks).toString().trim();
18319
- log13.debug("cursor-agent completed (node non-stream)", {
18593
+ log14.debug("cursor-agent completed (node non-stream)", {
18320
18594
  code,
18321
18595
  stdoutChars: stdout.length,
18322
18596
  stderrChars: stderr.length,
@@ -18342,7 +18616,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
18342
18616
  return;
18343
18617
  }
18344
18618
  if (intercepted.toolCall) {
18345
- log13.debug("Intercepted OpenCode tool call (non-stream)", {
18619
+ log14.debug("Intercepted OpenCode tool call (non-stream)", {
18346
18620
  name: intercepted.toolCall.function.name,
18347
18621
  callId: intercepted.toolCall.id
18348
18622
  });
@@ -18356,7 +18630,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
18356
18630
  const errSource = stderr || stdout || spawnErrorText || `cursor-agent exited with code ${String(code ?? "unknown")} and no output`;
18357
18631
  const parsed = parseAgentError(errSource);
18358
18632
  const userError = formatErrorForUser(parsed);
18359
- log13.error("cursor-cli failed", {
18633
+ log14.error("cursor-cli failed", {
18360
18634
  type: parsed.type,
18361
18635
  message: parsed.message,
18362
18636
  code
@@ -18395,7 +18669,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
18395
18669
  return;
18396
18670
  }
18397
18671
  const errSource = String(error45?.message || error45);
18398
- log13.error("Failed to spawn cursor-agent (stream)", { error: errSource, model });
18672
+ log14.error("Failed to spawn cursor-agent (stream)", { error: errSource, model });
18399
18673
  const parsed = parseAgentError(errSource);
18400
18674
  const msg = formatErrorForUser(parsed);
18401
18675
  const errChunk = createChatCompletionChunk(id, created, model, msg, true);
@@ -18410,7 +18684,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
18410
18684
  if (streamTerminated || res.writableEnded) {
18411
18685
  return;
18412
18686
  }
18413
- log13.debug("Intercepted OpenCode tool call (stream)", {
18687
+ log14.debug("Intercepted OpenCode tool call (stream)", {
18414
18688
  name: toolCall.function.name,
18415
18689
  callId: toolCall.id
18416
18690
  });
@@ -18492,7 +18766,14 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
18492
18766
  }
18493
18767
  });
18494
18768
  if (result.terminate) {
18495
- emitTerminalAssistantErrorAndTerminate(result.terminate.message);
18769
+ if (!result.terminate.silent) {
18770
+ emitTerminalAssistantErrorAndTerminate(result.terminate.message);
18771
+ } else {
18772
+ streamTerminated = true;
18773
+ try {
18774
+ child.kill();
18775
+ } catch {}
18776
+ }
18496
18777
  break;
18497
18778
  }
18498
18779
  if (result.intercepted) {
@@ -18555,7 +18836,14 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
18555
18836
  }
18556
18837
  });
18557
18838
  if (result.terminate) {
18558
- emitTerminalAssistantErrorAndTerminate(result.terminate.message);
18839
+ if (!result.terminate.silent) {
18840
+ emitTerminalAssistantErrorAndTerminate(result.terminate.message);
18841
+ } else {
18842
+ streamTerminated = true;
18843
+ try {
18844
+ child.kill();
18845
+ } catch {}
18846
+ }
18559
18847
  break;
18560
18848
  }
18561
18849
  if (result.intercepted) {
@@ -18578,7 +18866,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
18578
18866
  perf.mark("request:done");
18579
18867
  perf.summarize();
18580
18868
  const stderrText = Buffer.concat(stderrChunks).toString().trim();
18581
- log13.debug("cursor-agent completed (node stream)", {
18869
+ log14.debug("cursor-agent completed (node stream)", {
18582
18870
  code,
18583
18871
  stderrChars: stderrText.length
18584
18872
  });
@@ -18793,7 +19081,7 @@ function buildToolHookEntries(registry2, fallbackBaseDir) {
18793
19081
  const normalizedArgs = applyToolContextDefaults(toolName, args, context, fallbackBaseDir, sessionWorkspaceBySession);
18794
19082
  return await handler(normalizedArgs);
18795
19083
  } catch (error45) {
18796
- log13.warn("Tool hook execution failed", { tool: toolName, error: String(error45?.message || error45) });
19084
+ log14.debug("Tool hook execution failed", { tool: toolName, error: String(error45?.message || error45) });
18797
19085
  throw error45;
18798
19086
  }
18799
19087
  }
@@ -18805,9 +19093,9 @@ function buildToolHookEntries(registry2, fallbackBaseDir) {
18805
19093
  }
18806
19094
  return entries;
18807
19095
  }
18808
- var log13, CURSOR_PROVIDER_ID = "cursor-acp", 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 }) => {
19096
+ var log14, DEBUG_LOG_DIR2, DEBUG_LOG_FILE2, CURSOR_PROVIDER_ID = "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 }) => {
18809
19097
  const workspaceDirectory = resolveWorkspaceDirectory(worktree, directory);
18810
- log13.debug("Plugin initializing", {
19098
+ log14.debug("Plugin initializing", {
18811
19099
  directory,
18812
19100
  worktree,
18813
19101
  workspaceDirectory,
@@ -18815,22 +19103,22 @@ var log13, CURSOR_PROVIDER_ID = "cursor-acp", CURSOR_PROXY_HOST = "127.0.0.1", C
18815
19103
  serverUrl: serverUrl?.toString()
18816
19104
  });
18817
19105
  if (!TOOL_LOOP_MODE_VALID) {
18818
- log13.warn("Invalid CURSOR_ACP_TOOL_LOOP_MODE; defaulting to opencode", { value: TOOL_LOOP_MODE_RAW });
19106
+ log14.warn("Invalid CURSOR_ACP_TOOL_LOOP_MODE; defaulting to opencode", { value: TOOL_LOOP_MODE_RAW });
18819
19107
  }
18820
19108
  if (!PROVIDER_BOUNDARY_MODE_VALID) {
18821
- log13.warn("Invalid CURSOR_ACP_PROVIDER_BOUNDARY; defaulting to v1", {
19109
+ log14.warn("Invalid CURSOR_ACP_PROVIDER_BOUNDARY; defaulting to v1", {
18822
19110
  value: PROVIDER_BOUNDARY_MODE_RAW
18823
19111
  });
18824
19112
  }
18825
19113
  if (!TOOL_LOOP_MAX_REPEAT_VALID) {
18826
- log13.warn("Invalid CURSOR_ACP_TOOL_LOOP_MAX_REPEAT; defaulting to 3", {
19114
+ log14.warn("Invalid CURSOR_ACP_TOOL_LOOP_MAX_REPEAT; defaulting to 3", {
18827
19115
  value: TOOL_LOOP_MAX_REPEAT_RAW
18828
19116
  });
18829
19117
  }
18830
19118
  if (ENABLE_PROVIDER_BOUNDARY_AUTOFALLBACK && PROVIDER_BOUNDARY.mode !== "v1") {
18831
- log13.debug("Provider boundary auto-fallback is enabled but inactive unless mode=v1");
19119
+ log14.debug("Provider boundary auto-fallback is enabled but inactive unless mode=v1");
18832
19120
  }
18833
- log13.info("Tool loop mode configured", {
19121
+ log14.info("Tool loop mode configured", {
18834
19122
  mode: TOOL_LOOP_MODE,
18835
19123
  providerBoundary: PROVIDER_BOUNDARY.mode,
18836
19124
  proxyExecToolCalls: PROXY_EXECUTE_TOOL_CALLS,
@@ -18841,9 +19129,9 @@ var log13, CURSOR_PROVIDER_ID = "cursor-acp", CURSOR_PROXY_HOST = "127.0.0.1", C
18841
19129
  const toolsEnabled = process.env.CURSOR_ACP_ENABLE_OPENCODE_TOOLS !== "false";
18842
19130
  const legacyProxyToolPathsEnabled = toolsEnabled && TOOL_LOOP_MODE === "proxy-exec";
18843
19131
  if (toolsEnabled && TOOL_LOOP_MODE === "opencode") {
18844
- log13.debug("OpenCode mode active; skipping legacy SDK/MCP discovery and proxy-side tool execution");
19132
+ log14.debug("OpenCode mode active; skipping legacy SDK/MCP discovery and proxy-side tool execution");
18845
19133
  } else if (toolsEnabled && TOOL_LOOP_MODE === "off") {
18846
- log13.debug("Tool loop mode off; proxy-side tool execution disabled");
19134
+ log14.debug("Tool loop mode off; proxy-side tool execution disabled");
18847
19135
  }
18848
19136
  const serverClient = legacyProxyToolPathsEnabled ? createOpencodeClient({ baseUrl: serverUrl.toString(), directory: workspaceDirectory }) : null;
18849
19137
  const discovery = legacyProxyToolPathsEnabled ? new OpenCodeToolDiscovery(serverClient ?? client3) : null;
@@ -18895,7 +19183,7 @@ var log13, CURSOR_PROVIDER_ID = "cursor-acp", CURSOR_PROXY_HOST = "127.0.0.1", C
18895
19183
  discoveredList = await discovery.listTools();
18896
19184
  discoveredList.forEach((t) => toolsByName.set(t.name, t));
18897
19185
  } catch (err) {
18898
- log13.debug("Tool discovery failed, using local tools only", { error: String(err) });
19186
+ log14.debug("Tool discovery failed, using local tools only", { error: String(err) });
18899
19187
  }
18900
19188
  }
18901
19189
  const allTools = [...localTools, ...discoveredList];
@@ -18925,11 +19213,11 @@ var log13, CURSOR_PROVIDER_ID = "cursor-acp", CURSOR_PROXY_HOST = "127.0.0.1", C
18925
19213
  }
18926
19214
  lastToolNames = toolEntries.map((e) => e.function.name);
18927
19215
  lastToolMap = allTools.map((t) => ({ id: t.id, name: t.name }));
18928
- log13.debug("Tools refreshed", { local: localTools.length, discovered: discoveredList.length, total: toolEntries.length });
19216
+ log14.debug("Tools refreshed", { local: localTools.length, discovered: discoveredList.length, total: toolEntries.length });
18929
19217
  return toolEntries;
18930
19218
  }
18931
19219
  const proxyBaseURL = await ensureCursorProxyServer(workspaceDirectory, router);
18932
- log13.debug("Proxy server started", { baseURL: proxyBaseURL });
19220
+ log14.debug("Proxy server started", { baseURL: proxyBaseURL });
18933
19221
  const toolHookEntries = buildToolHookEntries(localRegistry, workspaceDirectory);
18934
19222
  return {
18935
19223
  tool: toolHookEntries,
@@ -18944,9 +19232,9 @@ var log13, CURSOR_PROVIDER_ID = "cursor-acp", CURSOR_PROXY_HOST = "127.0.0.1", C
18944
19232
  type: "oauth",
18945
19233
  async authorize() {
18946
19234
  try {
18947
- log13.info("Starting OAuth flow");
19235
+ log14.info("Starting OAuth flow");
18948
19236
  const { url: url2, instructions, callback } = await startCursorOAuth();
18949
- log13.debug("Got OAuth URL", { url: url2.substring(0, 50) + "..." });
19237
+ log14.debug("Got OAuth URL", { url: url2.substring(0, 50) + "..." });
18950
19238
  return {
18951
19239
  url: url2,
18952
19240
  instructions,
@@ -18954,7 +19242,7 @@ var log13, CURSOR_PROVIDER_ID = "cursor-acp", CURSOR_PROXY_HOST = "127.0.0.1", C
18954
19242
  callback
18955
19243
  };
18956
19244
  } catch (error45) {
18957
- log13.error("OAuth error", { error: error45 });
19245
+ log14.error("OAuth error", { error: error45 });
18958
19246
  throw error45;
18959
19247
  }
18960
19248
  }
@@ -18978,10 +19266,10 @@ var log13, CURSOR_PROVIDER_ID = "cursor-acp", CURSOR_PROXY_HOST = "127.0.0.1", C
18978
19266
  output.options.tools = resolved.tools;
18979
19267
  } else if (resolved.action === "preserve") {
18980
19268
  const count = Array.isArray(existingTools) ? existingTools.length : 0;
18981
- log13.debug("Using OpenCode-provided tools from chat.params", { count });
19269
+ log14.debug("Using OpenCode-provided tools from chat.params", { count });
18982
19270
  }
18983
19271
  } catch (err) {
18984
- log13.debug("Failed to refresh tools", { error: String(err) });
19272
+ log14.debug("Failed to refresh tools", { error: String(err) });
18985
19273
  }
18986
19274
  }
18987
19275
  },
@@ -19002,6 +19290,7 @@ var init_plugin = __esm(() => {
19002
19290
  init_parser();
19003
19291
  init_logger();
19004
19292
  init_perf();
19293
+ init_prompt_builder();
19005
19294
  init_tool_loop();
19006
19295
  init_discovery();
19007
19296
  init_schema();
@@ -19015,7 +19304,10 @@ var init_plugin = __esm(() => {
19015
19304
  init_runtime_interception();
19016
19305
  init_tool_schema_compat();
19017
19306
  init_tool_loop_guard();
19018
- log13 = createLogger("plugin");
19307
+ log14 = createLogger("plugin");
19308
+ DEBUG_LOG_DIR2 = join4(homedir4(), ".config", "opencode", "logs");
19309
+ DEBUG_LOG_FILE2 = join4(DEBUG_LOG_DIR2, "tool-loop-debug.log");
19310
+ CURSOR_PROVIDER_PREFIX = `${CURSOR_PROVIDER_ID}/`;
19019
19311
  CURSOR_PROXY_DEFAULT_BASE_URL = `http://${CURSOR_PROXY_HOST}:${CURSOR_PROXY_DEFAULT_PORT}/v1`;
19020
19312
  REUSE_EXISTING_PROXY = process.env.CURSOR_ACP_REUSE_EXISTING_PROXY !== "false";
19021
19313
  FORCE_TOOL_MODE = process.env.CURSOR_ACP_FORCE !== "false";
@@ -19256,7 +19548,7 @@ init_logger();
19256
19548
  import { execSync } from "node:child_process";
19257
19549
  import { createServer } from "node:net";
19258
19550
  import { platform as platform2 } from "node:os";
19259
- var log14 = createLogger("proxy-server");
19551
+ var log15 = createLogger("proxy-server");
19260
19552
  var DEFAULT_PORT = 32124;
19261
19553
  var PORT_RANGE_SIZE = 256;
19262
19554
  async function isPortAvailable(port, host) {
@@ -19275,10 +19567,10 @@ async function isPortAvailable(port, host) {
19275
19567
  }
19276
19568
  function getUsedPortsInRange(minPort, maxPort) {
19277
19569
  const used = new Set;
19278
- const os = platform2();
19570
+ const os2 = platform2();
19279
19571
  try {
19280
19572
  let out;
19281
- if (os === "linux") {
19573
+ if (os2 === "linux") {
19282
19574
  out = execSync("ss -tlnH", { encoding: "utf8", timeout: 5000, stdio: ["pipe", "pipe", "ignore"] });
19283
19575
  for (const line of out.split(`
19284
19576
  `)) {
@@ -19291,7 +19583,7 @@ function getUsedPortsInRange(minPort, maxPort) {
19291
19583
  if (!Number.isNaN(port) && port >= minPort && port < maxPort)
19292
19584
  used.add(port);
19293
19585
  }
19294
- } else if (os === "darwin") {
19586
+ } else if (os2 === "darwin") {
19295
19587
  out = execSync("lsof -iTCP -sTCP:LISTEN -nP", { encoding: "utf8", timeout: 5000, stdio: ["pipe", "pipe", "ignore"] });
19296
19588
  for (const line of out.split(`
19297
19589
  `)) {
@@ -19303,11 +19595,11 @@ function getUsedPortsInRange(minPort, maxPort) {
19303
19595
  }
19304
19596
  }
19305
19597
  } else {
19306
- log14.debug(`Port detection not supported on ${os}. Using probe-based discovery.`);
19598
+ log15.debug(`Port detection not supported on ${os2}. Using probe-based discovery.`);
19307
19599
  }
19308
19600
  } catch (error45) {
19309
19601
  const msg = error45 instanceof Error ? error45.message : String(error45);
19310
- log14.debug(`Port detection failed: ${msg}. Using probe-based discovery.`);
19602
+ log15.debug(`Port detection failed: ${msg}. Using probe-based discovery.`);
19311
19603
  }
19312
19604
  return used;
19313
19605
  }
@@ -19346,8 +19638,8 @@ function createProxyServer(config2) {
19346
19638
  hostname: host,
19347
19639
  fetch(request) {
19348
19640
  const url2 = new URL(request.url);
19349
- const path = url2.pathname;
19350
- if (path === healthCheckPath && request.method === "GET") {
19641
+ const path2 = url2.pathname;
19642
+ if (path2 === healthCheckPath && request.method === "GET") {
19351
19643
  return Response.json({ ok: true });
19352
19644
  }
19353
19645
  return new Response("Not Found", { status: 404 });
@@ -19358,7 +19650,7 @@ function createProxyServer(config2) {
19358
19650
  const err = error45 instanceof Error ? error45 : new Error(String(error45));
19359
19651
  const isPortInUse = err.message.includes("EADDRINUSE") || err.message.includes("address already in use") || err.message.includes("port is already in use");
19360
19652
  if (!isPortInUse) {
19361
- log14.debug(`Unexpected error starting on port ${port}: ${err.message}`);
19653
+ log15.debug(`Unexpected error starting on port ${port}: ${err.message}`);
19362
19654
  }
19363
19655
  return { success: false, error: err };
19364
19656
  }
@@ -19374,13 +19666,13 @@ function createProxyServer(config2) {
19374
19666
  if (result.success) {
19375
19667
  port = requestedPort;
19376
19668
  } else {
19377
- log14.debug(`Requested port ${requestedPort} unavailable: ${result.error?.message ?? "unknown"}. Falling back to automatic port selection.`);
19669
+ log15.debug(`Requested port ${requestedPort} unavailable: ${result.error?.message ?? "unknown"}. Falling back to automatic port selection.`);
19378
19670
  port = await findAvailablePort(host);
19379
19671
  const fallbackResult = tryStart(port);
19380
19672
  if (!fallbackResult.success) {
19381
19673
  throw new Error(`Failed to start server on port ${requestedPort} (${result.error?.message ?? "unknown"}) ` + `and fallback port ${port} (${fallbackResult.error?.message ?? "unknown"})`);
19382
19674
  }
19383
- log14.debug(`Server started on fallback port ${port} instead of requested port ${requestedPort}`);
19675
+ log15.debug(`Server started on fallback port ${port} instead of requested port ${requestedPort}`);
19384
19676
  }
19385
19677
  } else {
19386
19678
  port = await findAvailablePort(host);
@@ -19725,12 +20017,12 @@ init_auth();
19725
20017
  // src/commands/status.ts
19726
20018
  init_auth();
19727
20019
  init_logger();
19728
- import { existsSync as existsSync2 } from "fs";
19729
- var log15 = createLogger("status");
20020
+ import { existsSync as existsSync5 } from "fs";
20021
+ var log16 = createLogger("status");
19730
20022
  function checkAuthStatus() {
19731
20023
  const authFilePath = getAuthFilePath();
19732
- const exists = existsSync2(authFilePath);
19733
- log15.debug("Checking auth status", { path: authFilePath });
20024
+ const exists = existsSync5(authFilePath);
20025
+ log16.debug("Checking auth status", { path: authFilePath });
19734
20026
  if (exists) {
19735
20027
  return {
19736
20028
  authenticated: true,