cursor-openai-byok 1.1.3 → 1.1.4
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/lib/cli.js +69 -30
- package/lib/daemon-entry.js +1 -1
- package/lib/watcher-entry.js +11 -3
- package/package.json +1 -1
package/lib/cli.js
CHANGED
|
@@ -144,7 +144,7 @@ async function doctor(options) {
|
|
|
144
144
|
|
|
145
145
|
try {
|
|
146
146
|
const st = patcher.status(options);
|
|
147
|
-
checks.push({ name: "cursor", ok: st.supportedVersion, ...st });
|
|
147
|
+
checks.push({ name: "cursor", ok: st.supportedVersion && st.patched, ...st });
|
|
148
148
|
} catch (err) {
|
|
149
149
|
checks.push({ name: "cursor", ok: false, error: err.message });
|
|
150
150
|
}
|
|
@@ -266,7 +266,7 @@ module.exports = {
|
|
|
266
266
|
"package.json": function(module, exports, require, __filename, __dirname) {
|
|
267
267
|
module.exports = {
|
|
268
268
|
"name": "cursor-openai-byok",
|
|
269
|
-
"version": "1.1.
|
|
269
|
+
"version": "1.1.4",
|
|
270
270
|
"description": "Local BYOK bridge for Cursor using OpenAI-compatible providers.",
|
|
271
271
|
"displayName": "Cursor OpenAI BYOK",
|
|
272
272
|
"publisher": "cursor-openai-byok",
|
|
@@ -1028,8 +1028,7 @@ function candidateCursorAppRoots() {
|
|
|
1028
1028
|
function findCursorAppRoot(explicitRoot) {
|
|
1029
1029
|
const roots = explicitRoot ? [explicitRoot] : candidateCursorAppRoots();
|
|
1030
1030
|
for (const root of roots) {
|
|
1031
|
-
|
|
1032
|
-
if (fs.existsSync(workbench)) return root;
|
|
1031
|
+
if (workbenchPaths(root).length > 0) return root;
|
|
1033
1032
|
}
|
|
1034
1033
|
throw new Error(`Cursor app root not found. Checked: ${roots.join(", ")}`);
|
|
1035
1034
|
}
|
|
@@ -1038,6 +1037,13 @@ function workbenchPath(appRoot) {
|
|
|
1038
1037
|
return path.join(appRoot, "out", "vs", "workbench", "workbench.desktop.main.js");
|
|
1039
1038
|
}
|
|
1040
1039
|
|
|
1040
|
+
function workbenchPaths(appRoot) {
|
|
1041
|
+
const dir = path.join(appRoot, "out", "vs", "workbench");
|
|
1042
|
+
return ["workbench.desktop.main.js", "workbench.glass.main.js"]
|
|
1043
|
+
.map((name) => path.join(dir, name))
|
|
1044
|
+
.filter((file) => fs.existsSync(file));
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1041
1047
|
function productJsonPath(appRoot) {
|
|
1042
1048
|
return path.join(appRoot, "product.json");
|
|
1043
1049
|
}
|
|
@@ -1056,6 +1062,7 @@ function readCursorInfo(appRoot) {
|
|
|
1056
1062
|
version: product.version || pkg.version || "unknown",
|
|
1057
1063
|
commit: product.commit || "unknown",
|
|
1058
1064
|
workbenchPath: workbenchPath(appRoot),
|
|
1065
|
+
workbenchPaths: workbenchPaths(appRoot),
|
|
1059
1066
|
};
|
|
1060
1067
|
}
|
|
1061
1068
|
|
|
@@ -1063,6 +1070,7 @@ module.exports = {
|
|
|
1063
1070
|
candidateCursorAppRoots,
|
|
1064
1071
|
findCursorAppRoot,
|
|
1065
1072
|
workbenchPath,
|
|
1073
|
+
workbenchPaths,
|
|
1066
1074
|
readCursorInfo,
|
|
1067
1075
|
};
|
|
1068
1076
|
|
|
@@ -1831,16 +1839,29 @@ const MODEL_ENRICH_NEEDLE = `s=XI_(s,a.models);`;
|
|
|
1831
1839
|
function status(options = {}) {
|
|
1832
1840
|
const appRoot = findCursorAppRoot(options.appRoot);
|
|
1833
1841
|
const info = readCursorInfo(appRoot);
|
|
1834
|
-
const
|
|
1835
|
-
const unary = findUnaryPatchPoint(source);
|
|
1842
|
+
const bundles = info.workbenchPaths.map((workbenchPath) => bundleStatus(workbenchPath));
|
|
1836
1843
|
return {
|
|
1837
1844
|
...info,
|
|
1838
1845
|
supportedVersion: isSupportedVersion(info.version),
|
|
1846
|
+
patched: bundles.every((bundle) => bundle.patched),
|
|
1847
|
+
legacyPatched: bundles.some((bundle) => bundle.legacyPatched),
|
|
1848
|
+
hasRunLoopNeedle: bundles.every((bundle) => bundle.hasRunLoopNeedle),
|
|
1849
|
+
hasConnectNeedle: bundles.every((bundle) => bundle.hasConnectNeedle),
|
|
1850
|
+
hasUnaryNeedle: bundles.every((bundle) => bundle.hasUnaryNeedle),
|
|
1851
|
+
hasModelEnrichNeedle: bundles.some((bundle) => bundle.hasModelEnrichNeedle),
|
|
1852
|
+
bundles,
|
|
1853
|
+
};
|
|
1854
|
+
}
|
|
1855
|
+
|
|
1856
|
+
function bundleStatus(workbenchPath) {
|
|
1857
|
+
const source = fs.readFileSync(workbenchPath, "utf8");
|
|
1858
|
+
return {
|
|
1859
|
+
workbenchPath,
|
|
1839
1860
|
patched: source.includes(MARKER),
|
|
1840
1861
|
legacyPatched: source.includes(LEGACY_MARKER),
|
|
1841
1862
|
hasRunLoopNeedle: !!findRunLoopPatchPoint(source),
|
|
1842
1863
|
hasConnectNeedle: !!findConnectHelperNeedle(source),
|
|
1843
|
-
hasUnaryNeedle: !!
|
|
1864
|
+
hasUnaryNeedle: !!findUnaryPatchPoint(source) || source.includes(`await ${MARKER}().patchAvailableModels(`),
|
|
1844
1865
|
hasModelEnrichNeedle: source.includes(MODEL_ENRICH_NEEDLE),
|
|
1845
1866
|
};
|
|
1846
1867
|
}
|
|
@@ -1851,41 +1872,58 @@ function installPatch(options = {}) {
|
|
|
1851
1872
|
if (!isSupportedVersion(info.version) && !options.force) {
|
|
1852
1873
|
throw new Error(`Unsupported Cursor version ${info.version}. Re-run with --force only after validating needles.`);
|
|
1853
1874
|
}
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1875
|
+
const changes = [];
|
|
1876
|
+
for (const workbenchPath of info.workbenchPaths) {
|
|
1877
|
+
let source = fs.readFileSync(workbenchPath, "utf8");
|
|
1878
|
+
if (source.includes(MARKER)) continue;
|
|
1879
|
+
if (source.includes(LEGACY_MARKER) && !options.force) {
|
|
1880
|
+
throw new Error(`Legacy local BYOK patch is already present in ${workbenchPath}. Restore Cursor from backup or use --force after manual review.`);
|
|
1881
|
+
}
|
|
1882
|
+
source = patchSource(source, workbenchPath);
|
|
1883
|
+
changes.push({ workbenchPath, source });
|
|
1858
1884
|
}
|
|
1885
|
+
if (changes.length === 0) return { ...info, changed: false, alreadyInstalled: true };
|
|
1886
|
+
|
|
1887
|
+
const backupPaths = changes.map(({ workbenchPath }) => backupWorkbench(workbenchPath));
|
|
1888
|
+
changes.forEach(({ workbenchPath, source }) => fs.writeFileSync(workbenchPath, source));
|
|
1889
|
+
return { ...info, changed: true, backupPath: backupPaths[0], backupPaths };
|
|
1890
|
+
}
|
|
1891
|
+
|
|
1892
|
+
function patchSource(source, workbenchPath) {
|
|
1859
1893
|
const connectNeedle = findConnectHelperNeedle(source);
|
|
1860
1894
|
const unary = findUnaryPatchPoint(source);
|
|
1861
1895
|
const runLoop = findRunLoopPatchPoint(source);
|
|
1862
|
-
if (!runLoop) throw new Error(
|
|
1863
|
-
if (!connectNeedle) throw new Error(
|
|
1864
|
-
if (!unary) throw new Error(
|
|
1896
|
+
if (!runLoop) throw new Error(`AgentCompatService.runAgentLoop needle not found in ${workbenchPath}`);
|
|
1897
|
+
if (!connectNeedle) throw new Error(`Connect helper needle not found in ${workbenchPath}`);
|
|
1898
|
+
if (!unary) throw new Error(`Unary transport needle not found in ${workbenchPath}`);
|
|
1865
1899
|
|
|
1866
|
-
const backupPath = backupWorkbench(info.workbenchPath);
|
|
1867
1900
|
source = source.replace(connectNeedle, helperSnippet() + connectNeedle);
|
|
1868
1901
|
source = source.replace(unary.needle, `${unary.call};try{if(${unary.service}?.typeName==="aiserver.v1.AiService"&&${unary.method}?.name==="AvailableModels")await ${MARKER}().patchAvailableModels(${unary.response}.message,${unary.request})}catch{}${unary.returnStatement}`);
|
|
1869
1902
|
if (source.includes(MODEL_ENRICH_NEEDLE)) {
|
|
1870
1903
|
source = source.replace(MODEL_ENRICH_NEEDLE, `s=XI_(s,a.models);s=await ${MARKER}().enrichModels(s);`);
|
|
1871
1904
|
}
|
|
1872
1905
|
source = source.replace(runLoop.needle, runLoop.needle + agentLoopSnippet(runLoop.vars));
|
|
1873
|
-
|
|
1874
|
-
return { ...info, changed: true, backupPath };
|
|
1906
|
+
return source;
|
|
1875
1907
|
}
|
|
1876
1908
|
|
|
1877
1909
|
function uninstallPatch(options = {}) {
|
|
1878
1910
|
const appRoot = findCursorAppRoot(options.appRoot);
|
|
1879
1911
|
const info = readCursorInfo(appRoot);
|
|
1880
|
-
const
|
|
1881
|
-
const
|
|
1882
|
-
|
|
1912
|
+
const restores = info.workbenchPaths.map((workbenchPath) => {
|
|
1913
|
+
const backups = findBackups(workbenchPath).filter((file) => !fs.readFileSync(file, "utf8").includes(MARKER));
|
|
1914
|
+
if (backups.length === 0) throw new Error(`No suitable cursor-openai-byok backup found for ${workbenchPath}`);
|
|
1915
|
+
return { workbenchPath, restoredFrom: backups[backups.length - 1] };
|
|
1883
1916
|
});
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
return {
|
|
1917
|
+
restores.forEach((restore) => {
|
|
1918
|
+
restore.currentBackup = backupWorkbench(restore.workbenchPath, "pre-uninstall");
|
|
1919
|
+
fs.copyFileSync(restore.restoredFrom, restore.workbenchPath);
|
|
1920
|
+
});
|
|
1921
|
+
return {
|
|
1922
|
+
...info,
|
|
1923
|
+
restoredFrom: restores[0].restoredFrom,
|
|
1924
|
+
currentBackup: restores[0].currentBackup,
|
|
1925
|
+
restores,
|
|
1926
|
+
};
|
|
1889
1927
|
}
|
|
1890
1928
|
|
|
1891
1929
|
function backupWorkbench(workbenchPath, label = "backup") {
|
|
@@ -1899,7 +1937,7 @@ function findBackups(workbenchPath) {
|
|
|
1899
1937
|
const dir = path.dirname(workbenchPath);
|
|
1900
1938
|
const base = path.basename(workbenchPath);
|
|
1901
1939
|
return fs.readdirSync(dir)
|
|
1902
|
-
.filter((name) => name.startsWith(`${base}
|
|
1940
|
+
.filter((name) => name.startsWith(`${base}.`) && name.includes("cursor-openai-byok"))
|
|
1903
1941
|
.map((name) => path.join(dir, name))
|
|
1904
1942
|
.sort();
|
|
1905
1943
|
}
|
|
@@ -1964,9 +2002,10 @@ function findRunLoopPatchPoint(source) {
|
|
|
1964
2002
|
const start = Math.max(0, source.lastIndexOf("async runAgentLoop", anchor));
|
|
1965
2003
|
const segment = source.slice(start, anchor + 500);
|
|
1966
2004
|
const args = segment.match(/const\{userText:(\w+),richText:(\w+),mode:(\w+),selectedContext:(\w+),requestContext:(\w+),modelDetails:(\w+),generationUUID:(\w+),conversationId:(\w+),messageId:(\w+),[\s\S]{0,900}?conversationState:(\w+),/);
|
|
1967
|
-
const context = segment.match(/const\s
|
|
1968
|
-
const adapter = segment.match(
|
|
1969
|
-
|
|
2005
|
+
const context = segment.match(/const\s+[\w$]+=[\w$]+,\[([\w$]+),[\w$]+\]=[\w$]+\.withCancel\(\)/);
|
|
2006
|
+
const adapter = segment.match(/[\w$]+=[\w$]+\([\w$]+\.withName\("AgentCompatService\.agentClientService\.run"\)\),([\w$]+)=new\s+[\w$]+\(this\.instantiationService,[^;]+?\);/);
|
|
2007
|
+
const functionArgs = segment.match(/async runAgentLoop\([\w$]+,([\w$]+)\)/);
|
|
2008
|
+
if (!args || !context || !adapter || !functionArgs) return null;
|
|
1970
2009
|
const eventFactory = findInteractionUpdateFactory(source);
|
|
1971
2010
|
if (!eventFactory) return null;
|
|
1972
2011
|
const needleStart = segment.indexOf(args[0]);
|
|
@@ -1986,7 +2025,7 @@ function findRunLoopPatchPoint(source) {
|
|
|
1986
2025
|
conversationState: args[10],
|
|
1987
2026
|
contextExpression: context[1],
|
|
1988
2027
|
adapter: adapter[1],
|
|
1989
|
-
event:
|
|
2028
|
+
event: functionArgs[1],
|
|
1990
2029
|
eventFactory,
|
|
1991
2030
|
},
|
|
1992
2031
|
};
|
package/lib/daemon-entry.js
CHANGED
|
@@ -488,7 +488,7 @@ module.exports = {
|
|
|
488
488
|
"package.json": function(module, exports, require, __filename, __dirname) {
|
|
489
489
|
module.exports = {
|
|
490
490
|
"name": "cursor-openai-byok",
|
|
491
|
-
"version": "1.1.
|
|
491
|
+
"version": "1.1.4",
|
|
492
492
|
"description": "Local BYOK bridge for Cursor using OpenAI-compatible providers.",
|
|
493
493
|
"displayName": "Cursor OpenAI BYOK",
|
|
494
494
|
"publisher": "cursor-openai-byok",
|
package/lib/watcher-entry.js
CHANGED
|
@@ -115,7 +115,7 @@ module.exports = {
|
|
|
115
115
|
"package.json": function(module, exports, require, __filename, __dirname) {
|
|
116
116
|
module.exports = {
|
|
117
117
|
"name": "cursor-openai-byok",
|
|
118
|
-
"version": "1.1.
|
|
118
|
+
"version": "1.1.4",
|
|
119
119
|
"description": "Local BYOK bridge for Cursor using OpenAI-compatible providers.",
|
|
120
120
|
"displayName": "Cursor OpenAI BYOK",
|
|
121
121
|
"publisher": "cursor-openai-byok",
|
|
@@ -510,8 +510,7 @@ function candidateCursorAppRoots() {
|
|
|
510
510
|
function findCursorAppRoot(explicitRoot) {
|
|
511
511
|
const roots = explicitRoot ? [explicitRoot] : candidateCursorAppRoots();
|
|
512
512
|
for (const root of roots) {
|
|
513
|
-
|
|
514
|
-
if (fs.existsSync(workbench)) return root;
|
|
513
|
+
if (workbenchPaths(root).length > 0) return root;
|
|
515
514
|
}
|
|
516
515
|
throw new Error(`Cursor app root not found. Checked: ${roots.join(", ")}`);
|
|
517
516
|
}
|
|
@@ -520,6 +519,13 @@ function workbenchPath(appRoot) {
|
|
|
520
519
|
return path.join(appRoot, "out", "vs", "workbench", "workbench.desktop.main.js");
|
|
521
520
|
}
|
|
522
521
|
|
|
522
|
+
function workbenchPaths(appRoot) {
|
|
523
|
+
const dir = path.join(appRoot, "out", "vs", "workbench");
|
|
524
|
+
return ["workbench.desktop.main.js", "workbench.glass.main.js"]
|
|
525
|
+
.map((name) => path.join(dir, name))
|
|
526
|
+
.filter((file) => fs.existsSync(file));
|
|
527
|
+
}
|
|
528
|
+
|
|
523
529
|
function productJsonPath(appRoot) {
|
|
524
530
|
return path.join(appRoot, "product.json");
|
|
525
531
|
}
|
|
@@ -538,6 +544,7 @@ function readCursorInfo(appRoot) {
|
|
|
538
544
|
version: product.version || pkg.version || "unknown",
|
|
539
545
|
commit: product.commit || "unknown",
|
|
540
546
|
workbenchPath: workbenchPath(appRoot),
|
|
547
|
+
workbenchPaths: workbenchPaths(appRoot),
|
|
541
548
|
};
|
|
542
549
|
}
|
|
543
550
|
|
|
@@ -545,6 +552,7 @@ module.exports = {
|
|
|
545
552
|
candidateCursorAppRoots,
|
|
546
553
|
findCursorAppRoot,
|
|
547
554
|
workbenchPath,
|
|
555
|
+
workbenchPaths,
|
|
548
556
|
readCursorInfo,
|
|
549
557
|
};
|
|
550
558
|
|