@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.
- package/README.md +50 -48
- package/dist/cli/discover.js +177 -8
- package/dist/cli/mcptool.js +6 -1
- package/dist/cli/opencode-cursor.js +930 -50
- package/dist/index.js +587 -227
- package/dist/plugin-entry.js +565 -207
- package/package.json +4 -2
- package/src/auth.ts +3 -1
- package/src/cli/model-discovery.ts +3 -2
- package/src/cli/opencode-cursor.ts +402 -23
- package/src/client/simple.ts +6 -3
- package/src/mcp/tool-bridge.ts +1 -1
- package/src/models/discovery.ts +3 -2
- package/src/models/pricing.ts +196 -0
- package/src/models/variants.ts +446 -0
- package/src/plugin-toggle.ts +7 -1
- package/src/plugin.ts +150 -32
- package/src/provider/boundary.ts +10 -0
- package/src/proxy/formatter.ts +30 -12
- package/src/streaming/types.ts +5 -0
- package/src/tools/defaults.ts +181 -1
- package/src/tools/executors/cli.ts +1 -0
- package/src/usage.ts +112 -0
- package/src/utils/binary.ts +57 -0
package/dist/plugin-entry.js
CHANGED
|
@@ -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 ? "
|
|
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
|
|
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
|
-
|
|
549
|
+
log2.debug("Auth file detected", { path: authPath });
|
|
504
550
|
resolve2(true);
|
|
505
551
|
return;
|
|
506
552
|
}
|
|
507
553
|
}
|
|
508
|
-
|
|
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
|
-
|
|
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
|
-
|
|
526
|
-
const proc = spawn(
|
|
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
|
-
|
|
552
|
-
|
|
553
|
-
|
|
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
|
-
|
|
614
|
+
log2.debug("Login process closed", { code });
|
|
568
615
|
if (code === 0) {
|
|
569
|
-
|
|
616
|
+
log2.info("Process exited successfully, polling for auth file...");
|
|
570
617
|
const isAuthenticated = await pollForAuthFile();
|
|
571
618
|
if (isAuthenticated) {
|
|
572
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
677
|
+
log2.debug("Auth file found", { path: authPath });
|
|
631
678
|
return true;
|
|
632
679
|
}
|
|
633
680
|
}
|
|
634
|
-
|
|
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(
|
|
691
|
+
paths.push(join4(home, ".cursor", file));
|
|
645
692
|
}
|
|
646
693
|
for (const file of authFiles) {
|
|
647
|
-
paths.push(
|
|
694
|
+
paths.push(join4(home, ".config", "cursor", file));
|
|
648
695
|
}
|
|
649
696
|
} else {
|
|
650
697
|
for (const file of authFiles) {
|
|
651
|
-
paths.push(
|
|
698
|
+
paths.push(join4(home, ".config", "cursor", file));
|
|
652
699
|
}
|
|
653
700
|
const xdgConfig = process.env.XDG_CONFIG_HOME;
|
|
654
|
-
if (xdgConfig && xdgConfig !==
|
|
701
|
+
if (xdgConfig && xdgConfig !== join4(home, ".config")) {
|
|
655
702
|
for (const file of authFiles) {
|
|
656
|
-
paths.push(
|
|
703
|
+
paths.push(join4(xdgConfig, "cursor", file));
|
|
657
704
|
}
|
|
658
705
|
}
|
|
659
706
|
for (const file of authFiles) {
|
|
660
|
-
paths.push(
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
1038
|
+
var log4;
|
|
924
1039
|
var init_perf = __esm(() => {
|
|
925
1040
|
init_logger();
|
|
926
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
1184
|
+
var log5, DEBUG_LOG_DIR, DEBUG_LOG_FILE;
|
|
1070
1185
|
var init_prompt_builder = __esm(() => {
|
|
1071
1186
|
init_logger();
|
|
1072
|
-
|
|
1073
|
-
DEBUG_LOG_DIR =
|
|
1074
|
-
DEBUG_LOG_FILE =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
1386
|
+
var log6, TOOL_NAME_ALIASES;
|
|
1272
1387
|
var init_tool_loop = __esm(() => {
|
|
1273
1388
|
init_logger();
|
|
1274
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1515
|
+
log7.debug("CLI tool list failed", { status: res.status, stderr: res.stderr });
|
|
1401
1516
|
}
|
|
1402
1517
|
} catch (err) {
|
|
1403
|
-
|
|
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
|
-
|
|
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
|
|
1575
|
+
var log7;
|
|
1461
1576
|
var init_discovery = __esm(() => {
|
|
1462
1577
|
init_logger();
|
|
1463
1578
|
init_strip_ansi();
|
|
1464
|
-
|
|
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
|
|
1636
|
+
var log8;
|
|
1522
1637
|
var init_schema = __esm(() => {
|
|
1523
1638
|
init_logger();
|
|
1524
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1673
|
+
log9.warn("Tool execution returned error", { name, error: result.error, elapsed });
|
|
1559
1674
|
} else {
|
|
1560
|
-
|
|
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
|
|
1724
|
+
var log9;
|
|
1610
1725
|
var init_router = __esm(() => {
|
|
1611
1726
|
init_logger();
|
|
1612
|
-
|
|
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(
|
|
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
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
|
2074
|
+
var log11;
|
|
1958
2075
|
var init_config = __esm(() => {
|
|
1959
2076
|
init_plugin_toggle();
|
|
1960
2077
|
init_logger();
|
|
1961
|
-
|
|
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,
|
|
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[
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
11864
|
+
log12.info("MCP server connected", {
|
|
11748
11865
|
server: config.name,
|
|
11749
11866
|
tools: tools.length
|
|
11750
11867
|
});
|
|
11751
11868
|
} catch (err) {
|
|
11752
|
-
|
|
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
|
-
|
|
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
|
-
|
|
11913
|
+
log12.debug("MCP server disconnected", { server: name });
|
|
11797
11914
|
} catch (err) {
|
|
11798
|
-
|
|
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
|
|
11924
|
+
var log12, defaultDeps2 = null;
|
|
11808
11925
|
var init_client_manager = __esm(() => {
|
|
11809
11926
|
init_logger();
|
|
11810
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
12020
|
+
var log13;
|
|
11904
12021
|
var init_tool_bridge = __esm(() => {
|
|
11905
12022
|
init_logger();
|
|
11906
|
-
|
|
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
|
-
|
|
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
|
|
13439
|
+
var log14;
|
|
13323
13440
|
var init_local = __esm(() => {
|
|
13324
13441
|
init_logger();
|
|
13325
|
-
|
|
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
|
-
|
|
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
|
|
13482
|
+
var log15;
|
|
13366
13483
|
var init_sdk = __esm(() => {
|
|
13367
13484
|
init_logger();
|
|
13368
|
-
|
|
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
|
-
|
|
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
|
|
13525
|
+
var log16;
|
|
13409
13526
|
var init_mcp = __esm(() => {
|
|
13410
13527
|
init_logger();
|
|
13411
|
-
|
|
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
|
-
|
|
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
|
|
13545
|
+
var log17;
|
|
13429
13546
|
var init_executor = __esm(() => {
|
|
13430
13547
|
init_logger();
|
|
13431
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
15460
|
+
var log19, toastService;
|
|
15183
15461
|
var init_toast_service = __esm(() => {
|
|
15184
15462
|
init_logger();
|
|
15185
|
-
|
|
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
|
|
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) :
|
|
15707
|
-
const pluginDir =
|
|
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
|
-
|
|
15991
|
+
log20.debug("Plugin directory ensured", { path: pluginDir });
|
|
15711
15992
|
} catch (error) {
|
|
15712
|
-
|
|
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) :
|
|
15725
|
-
return
|
|
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
|
|
15759
|
-
|
|
15760
|
-
|
|
15761
|
-
return resolve2(envWorkspace);
|
|
16039
|
+
function isRootPath(pathValue) {
|
|
16040
|
+
if (!pathValue) {
|
|
16041
|
+
return false;
|
|
15762
16042
|
}
|
|
15763
|
-
const
|
|
15764
|
-
if (
|
|
15765
|
-
return
|
|
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
|
|
16072
|
+
if (isAcceptableWorkspace(worktreeCandidate, configPrefix)) {
|
|
15770
16073
|
return worktreeCandidate;
|
|
15771
16074
|
}
|
|
15772
16075
|
const dirCandidate = resolveCandidate(directory);
|
|
15773
|
-
if (dirCandidate
|
|
16076
|
+
if (isAcceptableWorkspace(dirCandidate, configPrefix)) {
|
|
15774
16077
|
return dirCandidate;
|
|
15775
16078
|
}
|
|
15776
16079
|
const cwd = resolve2(process.cwd());
|
|
15777
|
-
if (cwd
|
|
16080
|
+
if (isAcceptableWorkspace(cwd, configPrefix)) {
|
|
15778
16081
|
return cwd;
|
|
15779
16082
|
}
|
|
15780
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
16226
|
+
log20.warn("Provider boundary v1 failed; switching to legacy for this request", details);
|
|
15901
16227
|
} else {
|
|
15902
|
-
|
|
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([
|
|
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
|
-
|
|
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
|
-
|
|
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("
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 {
|
|
16459
|
-
const output =
|
|
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
|
-
|
|
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
|
-
|
|
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("
|
|
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
|
-
|
|
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
|
-
|
|
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), {
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
17448
|
+
log20.debug("Provider boundary auto-fallback is enabled but inactive unless mode=v1");
|
|
17093
17449
|
}
|
|
17094
|
-
|
|
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
|
-
|
|
17468
|
+
log20.debug("No MCP servers configured, skipping MCP bridge");
|
|
17113
17469
|
} else {
|
|
17114
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
17601
|
+
log20.info("Starting OAuth flow");
|
|
17246
17602
|
const { url, instructions, callback } = await startCursorOAuth();
|
|
17247
|
-
|
|
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
|
-
|
|
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
|
-
|
|
17635
|
+
log20.debug("Using OpenCode-provided tools from chat.params", { count });
|
|
17280
17636
|
}
|
|
17281
17637
|
} catch (err) {
|
|
17282
|
-
|
|
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
|
-
|
|
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
|
-
|
|
17340
|
-
|
|
17341
|
-
|
|
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
|
|
17732
|
+
var log21 = createLogger("plugin-entry");
|
|
17375
17733
|
var CursorPluginEntry = async (input) => {
|
|
17376
17734
|
const state = shouldEnableCursorPlugin();
|
|
17377
17735
|
if (!state.enabled) {
|
|
17378
|
-
|
|
17736
|
+
log21.info("Plugin disabled in OpenCode config; skipping initialization", {
|
|
17379
17737
|
configPath: state.configPath,
|
|
17380
17738
|
reason: state.reason
|
|
17381
17739
|
});
|