@rama_nigg/open-cursor 2.2.0 → 2.2.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/dist/cli/opencode-cursor.js +27 -8
- package/dist/index.js +44 -15
- package/dist/plugin-entry.js +44 -15
- package/package.json +1 -1
|
@@ -412,11 +412,22 @@ function resolvePluginSource() {
|
|
|
412
412
|
}
|
|
413
413
|
throw new Error("Unable to locate plugin-entry.js next to CLI distribution files");
|
|
414
414
|
}
|
|
415
|
+
function isErrnoException(error) {
|
|
416
|
+
return typeof error === "object" && error !== null && "code" in error;
|
|
417
|
+
}
|
|
415
418
|
function readConfig(configPath) {
|
|
416
419
|
if (!existsSync(configPath)) {
|
|
417
420
|
return { plugin: [], provider: {} };
|
|
418
421
|
}
|
|
419
|
-
|
|
422
|
+
let raw;
|
|
423
|
+
try {
|
|
424
|
+
raw = readFileSync(configPath, "utf8");
|
|
425
|
+
} catch (error) {
|
|
426
|
+
if (isErrnoException(error) && error.code === "ENOENT") {
|
|
427
|
+
return { plugin: [], provider: {} };
|
|
428
|
+
}
|
|
429
|
+
throw error;
|
|
430
|
+
}
|
|
420
431
|
try {
|
|
421
432
|
return JSON.parse(raw);
|
|
422
433
|
} catch (error) {
|
|
@@ -536,14 +547,22 @@ function getStatusResult(configPath, pluginPath) {
|
|
|
536
547
|
let pluginType = "missing";
|
|
537
548
|
let pluginTarget;
|
|
538
549
|
if (existsSync(pluginPath)) {
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
550
|
+
try {
|
|
551
|
+
const stat = lstatSync(pluginPath);
|
|
552
|
+
pluginType = stat.isSymbolicLink() ? "symlink" : "file";
|
|
553
|
+
if (pluginType === "symlink") {
|
|
554
|
+
try {
|
|
555
|
+
pluginTarget = readFileSync(pluginPath, "utf8");
|
|
556
|
+
} catch {
|
|
557
|
+
pluginTarget = undefined;
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
} catch (error) {
|
|
561
|
+
if (!isErrnoException(error) || error.code !== "ENOENT") {
|
|
562
|
+
throw error;
|
|
546
563
|
}
|
|
564
|
+
pluginType = "missing";
|
|
565
|
+
pluginTarget = undefined;
|
|
547
566
|
}
|
|
548
567
|
}
|
|
549
568
|
let providerEnabled = false;
|
package/dist/index.js
CHANGED
|
@@ -17754,6 +17754,8 @@ var exports_plugin = {};
|
|
|
17754
17754
|
__export(exports_plugin, {
|
|
17755
17755
|
shouldProcessModel: () => shouldProcessModel,
|
|
17756
17756
|
resolveChatParamTools: () => resolveChatParamTools,
|
|
17757
|
+
normalizeWorkspaceForCompare: () => normalizeWorkspaceForCompare,
|
|
17758
|
+
isReusableProxyHealthPayload: () => isReusableProxyHealthPayload,
|
|
17757
17759
|
ensurePluginDirectory: () => ensurePluginDirectory,
|
|
17758
17760
|
default: () => plugin_default,
|
|
17759
17761
|
CursorPlugin: () => CursorPlugin
|
|
@@ -17855,6 +17857,18 @@ function resolveWorkspaceDirectory(worktree, directory) {
|
|
|
17855
17857
|
}
|
|
17856
17858
|
return dirCandidate || cwd || configPrefix;
|
|
17857
17859
|
}
|
|
17860
|
+
function normalizeWorkspaceForCompare(pathValue) {
|
|
17861
|
+
return resolve(pathValue);
|
|
17862
|
+
}
|
|
17863
|
+
function isReusableProxyHealthPayload(payload, workspaceDirectory) {
|
|
17864
|
+
if (!payload || payload.ok !== true) {
|
|
17865
|
+
return false;
|
|
17866
|
+
}
|
|
17867
|
+
if (typeof payload.workspaceDirectory !== "string" || payload.workspaceDirectory.length === 0) {
|
|
17868
|
+
return false;
|
|
17869
|
+
}
|
|
17870
|
+
return normalizeWorkspaceForCompare(payload.workspaceDirectory) === normalizeWorkspaceForCompare(workspaceDirectory);
|
|
17871
|
+
}
|
|
17858
17872
|
function parseToolLoopMode(value) {
|
|
17859
17873
|
const normalized = (value ?? "opencode").trim().toLowerCase();
|
|
17860
17874
|
if (normalized === "opencode" || normalized === "proxy-exec" || normalized === "off") {
|
|
@@ -18055,16 +18069,20 @@ async function findFirstAllowedToolCallInOutput(output, options) {
|
|
|
18055
18069
|
async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
|
|
18056
18070
|
const key = getGlobalKey();
|
|
18057
18071
|
const g = globalThis;
|
|
18058
|
-
const
|
|
18072
|
+
const normalizedWorkspace = normalizeWorkspaceForCompare(workspaceDirectory);
|
|
18073
|
+
const state = g[key] ?? { baseURL: "", baseURLByWorkspace: {} };
|
|
18074
|
+
state.baseURLByWorkspace = state.baseURLByWorkspace ?? {};
|
|
18075
|
+
g[key] = state;
|
|
18076
|
+
const existingBaseURL = state.baseURLByWorkspace[normalizedWorkspace] ?? state.baseURL;
|
|
18059
18077
|
if (typeof existingBaseURL === "string" && existingBaseURL.length > 0) {
|
|
18060
18078
|
return existingBaseURL;
|
|
18061
18079
|
}
|
|
18062
|
-
|
|
18080
|
+
state.baseURL = "";
|
|
18063
18081
|
const handler = async (req) => {
|
|
18064
18082
|
try {
|
|
18065
18083
|
const url2 = new URL(req.url);
|
|
18066
18084
|
if (url2.pathname === "/health") {
|
|
18067
|
-
return new Response(JSON.stringify({ ok: true }), {
|
|
18085
|
+
return new Response(JSON.stringify({ ok: true, workspaceDirectory }), {
|
|
18068
18086
|
status: 200,
|
|
18069
18087
|
headers: { "Content-Type": "application/json" }
|
|
18070
18088
|
});
|
|
@@ -18182,7 +18200,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
|
|
|
18182
18200
|
]);
|
|
18183
18201
|
const stdout = (stdoutText || "").trim();
|
|
18184
18202
|
const stderr = (stderrText || "").trim();
|
|
18185
|
-
const exitCode = child.
|
|
18203
|
+
const exitCode = await child.exited;
|
|
18186
18204
|
log14.debug("cursor-agent completed (bun non-stream)", {
|
|
18187
18205
|
exitCode,
|
|
18188
18206
|
stdoutChars: stdout.length,
|
|
@@ -18431,14 +18449,15 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
|
|
|
18431
18449
|
if (streamTerminated) {
|
|
18432
18450
|
return;
|
|
18433
18451
|
}
|
|
18434
|
-
|
|
18452
|
+
const exitCode = await child.exited;
|
|
18453
|
+
if (exitCode !== 0) {
|
|
18435
18454
|
const stderrText = await new Response(child.stderr).text();
|
|
18436
|
-
const errSource = (stderrText || "").trim() || `cursor-agent exited with code ${String(
|
|
18455
|
+
const errSource = (stderrText || "").trim() || `cursor-agent exited with code ${String(exitCode ?? "unknown")} and no output`;
|
|
18437
18456
|
const parsed = parseAgentError(errSource);
|
|
18438
18457
|
const msg = formatErrorForUser(parsed);
|
|
18439
18458
|
log14.error("cursor-cli streaming failed", {
|
|
18440
18459
|
type: parsed.type,
|
|
18441
|
-
code:
|
|
18460
|
+
code: exitCode
|
|
18442
18461
|
});
|
|
18443
18462
|
const errChunk = createChatCompletionChunk(id, created, model, msg, true);
|
|
18444
18463
|
controller.enqueue(encoder.encode(`data: ${JSON.stringify(errChunk)}
|
|
@@ -18448,7 +18467,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
|
|
|
18448
18467
|
return;
|
|
18449
18468
|
}
|
|
18450
18469
|
log14.debug("cursor-agent completed (bun stream)", {
|
|
18451
|
-
exitCode
|
|
18470
|
+
exitCode
|
|
18452
18471
|
});
|
|
18453
18472
|
const doneChunk = createChatCompletionChunk(id, created, model, "", true);
|
|
18454
18473
|
controller.enqueue(encoder.encode(`data: ${JSON.stringify(doneChunk)}
|
|
@@ -18482,8 +18501,12 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
|
|
|
18482
18501
|
try {
|
|
18483
18502
|
const res = await fetch(`http://${CURSOR_PROXY_HOST}:${CURSOR_PROXY_DEFAULT_PORT}/health`).catch(() => null);
|
|
18484
18503
|
if (res && res.ok) {
|
|
18485
|
-
|
|
18486
|
-
|
|
18504
|
+
const payload = await res.json().catch(() => null);
|
|
18505
|
+
if (isReusableProxyHealthPayload(payload, workspaceDirectory)) {
|
|
18506
|
+
state.baseURL = CURSOR_PROXY_DEFAULT_BASE_URL;
|
|
18507
|
+
state.baseURLByWorkspace[normalizedWorkspace] = CURSOR_PROXY_DEFAULT_BASE_URL;
|
|
18508
|
+
return CURSOR_PROXY_DEFAULT_BASE_URL;
|
|
18509
|
+
}
|
|
18487
18510
|
}
|
|
18488
18511
|
} catch {}
|
|
18489
18512
|
}
|
|
@@ -18494,7 +18517,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
|
|
|
18494
18517
|
const url2 = new URL(req.url || "/", `http://${req.headers.host}`);
|
|
18495
18518
|
if (url2.pathname === "/health") {
|
|
18496
18519
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
18497
|
-
res.end(JSON.stringify({ ok: true }));
|
|
18520
|
+
res.end(JSON.stringify({ ok: true, workspaceDirectory }));
|
|
18498
18521
|
return;
|
|
18499
18522
|
}
|
|
18500
18523
|
if (url2.pathname === "/v1/models" || url2.pathname === "/models") {
|
|
@@ -18916,7 +18939,8 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
|
|
|
18916
18939
|
server2.once("error", reject);
|
|
18917
18940
|
});
|
|
18918
18941
|
const baseURL = `http://${CURSOR_PROXY_HOST}:${CURSOR_PROXY_DEFAULT_PORT}/v1`;
|
|
18919
|
-
|
|
18942
|
+
state.baseURL = baseURL;
|
|
18943
|
+
state.baseURLByWorkspace[normalizedWorkspace] = baseURL;
|
|
18920
18944
|
return baseURL;
|
|
18921
18945
|
} catch (error45) {
|
|
18922
18946
|
if (error45?.code !== "EADDRINUSE") {
|
|
@@ -18926,8 +18950,12 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
|
|
|
18926
18950
|
try {
|
|
18927
18951
|
const res = await fetch(`http://${CURSOR_PROXY_HOST}:${CURSOR_PROXY_DEFAULT_PORT}/health`).catch(() => null);
|
|
18928
18952
|
if (res && res.ok) {
|
|
18929
|
-
|
|
18930
|
-
|
|
18953
|
+
const payload = await res.json().catch(() => null);
|
|
18954
|
+
if (isReusableProxyHealthPayload(payload, workspaceDirectory)) {
|
|
18955
|
+
state.baseURL = CURSOR_PROXY_DEFAULT_BASE_URL;
|
|
18956
|
+
state.baseURLByWorkspace[normalizedWorkspace] = CURSOR_PROXY_DEFAULT_BASE_URL;
|
|
18957
|
+
return CURSOR_PROXY_DEFAULT_BASE_URL;
|
|
18958
|
+
}
|
|
18931
18959
|
}
|
|
18932
18960
|
} catch {}
|
|
18933
18961
|
}
|
|
@@ -18938,7 +18966,8 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
|
|
|
18938
18966
|
});
|
|
18939
18967
|
const addr = server2.address();
|
|
18940
18968
|
const baseURL = `http://${CURSOR_PROXY_HOST}:${addr.port}/v1`;
|
|
18941
|
-
|
|
18969
|
+
state.baseURL = baseURL;
|
|
18970
|
+
state.baseURLByWorkspace[normalizedWorkspace] = baseURL;
|
|
18942
18971
|
return baseURL;
|
|
18943
18972
|
}
|
|
18944
18973
|
}
|
package/dist/plugin-entry.js
CHANGED
|
@@ -17754,6 +17754,8 @@ var exports_plugin = {};
|
|
|
17754
17754
|
__export(exports_plugin, {
|
|
17755
17755
|
shouldProcessModel: () => shouldProcessModel,
|
|
17756
17756
|
resolveChatParamTools: () => resolveChatParamTools,
|
|
17757
|
+
normalizeWorkspaceForCompare: () => normalizeWorkspaceForCompare,
|
|
17758
|
+
isReusableProxyHealthPayload: () => isReusableProxyHealthPayload,
|
|
17757
17759
|
ensurePluginDirectory: () => ensurePluginDirectory,
|
|
17758
17760
|
default: () => plugin_default,
|
|
17759
17761
|
CursorPlugin: () => CursorPlugin
|
|
@@ -17855,6 +17857,18 @@ function resolveWorkspaceDirectory(worktree, directory) {
|
|
|
17855
17857
|
}
|
|
17856
17858
|
return dirCandidate || cwd || configPrefix;
|
|
17857
17859
|
}
|
|
17860
|
+
function normalizeWorkspaceForCompare(pathValue) {
|
|
17861
|
+
return resolve2(pathValue);
|
|
17862
|
+
}
|
|
17863
|
+
function isReusableProxyHealthPayload(payload, workspaceDirectory) {
|
|
17864
|
+
if (!payload || payload.ok !== true) {
|
|
17865
|
+
return false;
|
|
17866
|
+
}
|
|
17867
|
+
if (typeof payload.workspaceDirectory !== "string" || payload.workspaceDirectory.length === 0) {
|
|
17868
|
+
return false;
|
|
17869
|
+
}
|
|
17870
|
+
return normalizeWorkspaceForCompare(payload.workspaceDirectory) === normalizeWorkspaceForCompare(workspaceDirectory);
|
|
17871
|
+
}
|
|
17858
17872
|
function parseToolLoopMode(value) {
|
|
17859
17873
|
const normalized = (value ?? "opencode").trim().toLowerCase();
|
|
17860
17874
|
if (normalized === "opencode" || normalized === "proxy-exec" || normalized === "off") {
|
|
@@ -18055,16 +18069,20 @@ async function findFirstAllowedToolCallInOutput(output, options) {
|
|
|
18055
18069
|
async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
|
|
18056
18070
|
const key = getGlobalKey();
|
|
18057
18071
|
const g = globalThis;
|
|
18058
|
-
const
|
|
18072
|
+
const normalizedWorkspace = normalizeWorkspaceForCompare(workspaceDirectory);
|
|
18073
|
+
const state = g[key] ?? { baseURL: "", baseURLByWorkspace: {} };
|
|
18074
|
+
state.baseURLByWorkspace = state.baseURLByWorkspace ?? {};
|
|
18075
|
+
g[key] = state;
|
|
18076
|
+
const existingBaseURL = state.baseURLByWorkspace[normalizedWorkspace] ?? state.baseURL;
|
|
18059
18077
|
if (typeof existingBaseURL === "string" && existingBaseURL.length > 0) {
|
|
18060
18078
|
return existingBaseURL;
|
|
18061
18079
|
}
|
|
18062
|
-
|
|
18080
|
+
state.baseURL = "";
|
|
18063
18081
|
const handler = async (req) => {
|
|
18064
18082
|
try {
|
|
18065
18083
|
const url2 = new URL(req.url);
|
|
18066
18084
|
if (url2.pathname === "/health") {
|
|
18067
|
-
return new Response(JSON.stringify({ ok: true }), {
|
|
18085
|
+
return new Response(JSON.stringify({ ok: true, workspaceDirectory }), {
|
|
18068
18086
|
status: 200,
|
|
18069
18087
|
headers: { "Content-Type": "application/json" }
|
|
18070
18088
|
});
|
|
@@ -18182,7 +18200,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
|
|
|
18182
18200
|
]);
|
|
18183
18201
|
const stdout = (stdoutText || "").trim();
|
|
18184
18202
|
const stderr = (stderrText || "").trim();
|
|
18185
|
-
const exitCode = child.
|
|
18203
|
+
const exitCode = await child.exited;
|
|
18186
18204
|
log14.debug("cursor-agent completed (bun non-stream)", {
|
|
18187
18205
|
exitCode,
|
|
18188
18206
|
stdoutChars: stdout.length,
|
|
@@ -18431,14 +18449,15 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
|
|
|
18431
18449
|
if (streamTerminated) {
|
|
18432
18450
|
return;
|
|
18433
18451
|
}
|
|
18434
|
-
|
|
18452
|
+
const exitCode = await child.exited;
|
|
18453
|
+
if (exitCode !== 0) {
|
|
18435
18454
|
const stderrText = await new Response(child.stderr).text();
|
|
18436
|
-
const errSource = (stderrText || "").trim() || `cursor-agent exited with code ${String(
|
|
18455
|
+
const errSource = (stderrText || "").trim() || `cursor-agent exited with code ${String(exitCode ?? "unknown")} and no output`;
|
|
18437
18456
|
const parsed = parseAgentError(errSource);
|
|
18438
18457
|
const msg = formatErrorForUser(parsed);
|
|
18439
18458
|
log14.error("cursor-cli streaming failed", {
|
|
18440
18459
|
type: parsed.type,
|
|
18441
|
-
code:
|
|
18460
|
+
code: exitCode
|
|
18442
18461
|
});
|
|
18443
18462
|
const errChunk = createChatCompletionChunk(id, created, model, msg, true);
|
|
18444
18463
|
controller.enqueue(encoder.encode(`data: ${JSON.stringify(errChunk)}
|
|
@@ -18448,7 +18467,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
|
|
|
18448
18467
|
return;
|
|
18449
18468
|
}
|
|
18450
18469
|
log14.debug("cursor-agent completed (bun stream)", {
|
|
18451
|
-
exitCode
|
|
18470
|
+
exitCode
|
|
18452
18471
|
});
|
|
18453
18472
|
const doneChunk = createChatCompletionChunk(id, created, model, "", true);
|
|
18454
18473
|
controller.enqueue(encoder.encode(`data: ${JSON.stringify(doneChunk)}
|
|
@@ -18482,8 +18501,12 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
|
|
|
18482
18501
|
try {
|
|
18483
18502
|
const res = await fetch(`http://${CURSOR_PROXY_HOST}:${CURSOR_PROXY_DEFAULT_PORT}/health`).catch(() => null);
|
|
18484
18503
|
if (res && res.ok) {
|
|
18485
|
-
|
|
18486
|
-
|
|
18504
|
+
const payload = await res.json().catch(() => null);
|
|
18505
|
+
if (isReusableProxyHealthPayload(payload, workspaceDirectory)) {
|
|
18506
|
+
state.baseURL = CURSOR_PROXY_DEFAULT_BASE_URL;
|
|
18507
|
+
state.baseURLByWorkspace[normalizedWorkspace] = CURSOR_PROXY_DEFAULT_BASE_URL;
|
|
18508
|
+
return CURSOR_PROXY_DEFAULT_BASE_URL;
|
|
18509
|
+
}
|
|
18487
18510
|
}
|
|
18488
18511
|
} catch {}
|
|
18489
18512
|
}
|
|
@@ -18494,7 +18517,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
|
|
|
18494
18517
|
const url2 = new URL(req.url || "/", `http://${req.headers.host}`);
|
|
18495
18518
|
if (url2.pathname === "/health") {
|
|
18496
18519
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
18497
|
-
res.end(JSON.stringify({ ok: true }));
|
|
18520
|
+
res.end(JSON.stringify({ ok: true, workspaceDirectory }));
|
|
18498
18521
|
return;
|
|
18499
18522
|
}
|
|
18500
18523
|
if (url2.pathname === "/v1/models" || url2.pathname === "/models") {
|
|
@@ -18916,7 +18939,8 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
|
|
|
18916
18939
|
server2.once("error", reject);
|
|
18917
18940
|
});
|
|
18918
18941
|
const baseURL = `http://${CURSOR_PROXY_HOST}:${CURSOR_PROXY_DEFAULT_PORT}/v1`;
|
|
18919
|
-
|
|
18942
|
+
state.baseURL = baseURL;
|
|
18943
|
+
state.baseURLByWorkspace[normalizedWorkspace] = baseURL;
|
|
18920
18944
|
return baseURL;
|
|
18921
18945
|
} catch (error45) {
|
|
18922
18946
|
if (error45?.code !== "EADDRINUSE") {
|
|
@@ -18926,8 +18950,12 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
|
|
|
18926
18950
|
try {
|
|
18927
18951
|
const res = await fetch(`http://${CURSOR_PROXY_HOST}:${CURSOR_PROXY_DEFAULT_PORT}/health`).catch(() => null);
|
|
18928
18952
|
if (res && res.ok) {
|
|
18929
|
-
|
|
18930
|
-
|
|
18953
|
+
const payload = await res.json().catch(() => null);
|
|
18954
|
+
if (isReusableProxyHealthPayload(payload, workspaceDirectory)) {
|
|
18955
|
+
state.baseURL = CURSOR_PROXY_DEFAULT_BASE_URL;
|
|
18956
|
+
state.baseURLByWorkspace[normalizedWorkspace] = CURSOR_PROXY_DEFAULT_BASE_URL;
|
|
18957
|
+
return CURSOR_PROXY_DEFAULT_BASE_URL;
|
|
18958
|
+
}
|
|
18931
18959
|
}
|
|
18932
18960
|
} catch {}
|
|
18933
18961
|
}
|
|
@@ -18938,7 +18966,8 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
|
|
|
18938
18966
|
});
|
|
18939
18967
|
const addr = server2.address();
|
|
18940
18968
|
const baseURL = `http://${CURSOR_PROXY_HOST}:${addr.port}/v1`;
|
|
18941
|
-
|
|
18969
|
+
state.baseURL = baseURL;
|
|
18970
|
+
state.baseURLByWorkspace[normalizedWorkspace] = baseURL;
|
|
18942
18971
|
return baseURL;
|
|
18943
18972
|
}
|
|
18944
18973
|
}
|
package/package.json
CHANGED