pi-cursor-bridge 0.1.3 → 0.1.5
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/.codex-plugin/plugin.json +1 -1
- package/README.md +1 -1
- package/dist/cursor-bridge.mjs +615 -129
- package/extensions/index.ts +1 -1
- package/package.json +2 -2
- package/skills/cce-routing/SKILL.md +2 -0
- package/skills/cursor-delegate/SKILL.md +7 -5
package/dist/cursor-bridge.mjs
CHANGED
|
@@ -2990,7 +2990,7 @@ var require_compile = __commonJS({
|
|
|
2990
2990
|
const schOrFunc = root.refs[ref];
|
|
2991
2991
|
if (schOrFunc)
|
|
2992
2992
|
return schOrFunc;
|
|
2993
|
-
let _sch =
|
|
2993
|
+
let _sch = resolve7.call(this, root, ref);
|
|
2994
2994
|
if (_sch === void 0) {
|
|
2995
2995
|
const schema = (_a3 = root.localRefs) === null || _a3 === void 0 ? void 0 : _a3[ref];
|
|
2996
2996
|
const { schemaId } = this.opts;
|
|
@@ -3017,7 +3017,7 @@ var require_compile = __commonJS({
|
|
|
3017
3017
|
function sameSchemaEnv(s1, s2) {
|
|
3018
3018
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
3019
3019
|
}
|
|
3020
|
-
function
|
|
3020
|
+
function resolve7(root, ref) {
|
|
3021
3021
|
let sch;
|
|
3022
3022
|
while (typeof (sch = this.refs[ref]) == "string")
|
|
3023
3023
|
ref = sch;
|
|
@@ -3648,7 +3648,7 @@ var require_fast_uri = __commonJS({
|
|
|
3648
3648
|
}
|
|
3649
3649
|
return uri;
|
|
3650
3650
|
}
|
|
3651
|
-
function
|
|
3651
|
+
function resolve7(baseURI, relativeURI, options) {
|
|
3652
3652
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
3653
3653
|
const resolved = resolveComponent(parse3(baseURI, schemelessOptions), parse3(relativeURI, schemelessOptions), schemelessOptions, true);
|
|
3654
3654
|
schemelessOptions.skipEscape = true;
|
|
@@ -3906,7 +3906,7 @@ var require_fast_uri = __commonJS({
|
|
|
3906
3906
|
var fastUri = {
|
|
3907
3907
|
SCHEMES,
|
|
3908
3908
|
normalize,
|
|
3909
|
-
resolve:
|
|
3909
|
+
resolve: resolve7,
|
|
3910
3910
|
resolveComponent,
|
|
3911
3911
|
equal,
|
|
3912
3912
|
serialize,
|
|
@@ -10897,20 +10897,20 @@ public static class CursorBridgeWindowControl {
|
|
|
10897
10897
|
|
|
10898
10898
|
// lifecycle-paths.mjs
|
|
10899
10899
|
import { createHash } from "node:crypto";
|
|
10900
|
-
import { homedir as
|
|
10901
|
-
import { join as
|
|
10902
|
-
import { mkdirSync as
|
|
10900
|
+
import { homedir as homedir3 } from "node:os";
|
|
10901
|
+
import { join as join3 } from "node:path";
|
|
10902
|
+
import { mkdirSync as mkdirSync3 } from "node:fs";
|
|
10903
10903
|
function defaultLifecycleDir() {
|
|
10904
10904
|
if (process.env.CURSOR_BRIDGE_LIFECYCLE_DIR) return process.env.CURSOR_BRIDGE_LIFECYCLE_DIR;
|
|
10905
10905
|
if (process.platform === "win32") {
|
|
10906
|
-
const root2 = process.env.LOCALAPPDATA ||
|
|
10907
|
-
return
|
|
10906
|
+
const root2 = process.env.LOCALAPPDATA || join3(homedir3(), "AppData", "Local");
|
|
10907
|
+
return join3(root2, "cursor-bridge", "lifecycle");
|
|
10908
10908
|
}
|
|
10909
|
-
const root = process.env.XDG_RUNTIME_DIR || process.env.XDG_STATE_HOME ||
|
|
10910
|
-
return
|
|
10909
|
+
const root = process.env.XDG_RUNTIME_DIR || process.env.XDG_STATE_HOME || join3(homedir3(), ".local", "state");
|
|
10910
|
+
return join3(root, "cursor-bridge", "lifecycle");
|
|
10911
10911
|
}
|
|
10912
10912
|
function ensureLifecycleDir(dir = defaultLifecycleDir()) {
|
|
10913
|
-
|
|
10913
|
+
mkdirSync3(dir, { recursive: true });
|
|
10914
10914
|
return dir;
|
|
10915
10915
|
}
|
|
10916
10916
|
function lifecycleEndpointTag(dir) {
|
|
@@ -10921,13 +10921,13 @@ function supervisorSockPath(dir = defaultLifecycleDir()) {
|
|
|
10921
10921
|
if (process.platform === "win32") {
|
|
10922
10922
|
return `\\\\.\\pipe\\cursor-bridge-lifecycle-${lifecycleEndpointTag(dir)}`;
|
|
10923
10923
|
}
|
|
10924
|
-
return
|
|
10924
|
+
return join3(dir, "supervisor.sock");
|
|
10925
10925
|
}
|
|
10926
10926
|
function supervisorPidPath(dir = defaultLifecycleDir()) {
|
|
10927
|
-
return
|
|
10927
|
+
return join3(dir, "supervisor.pid");
|
|
10928
10928
|
}
|
|
10929
10929
|
function supervisorLockPath(dir = defaultLifecycleDir()) {
|
|
10930
|
-
return
|
|
10930
|
+
return join3(dir, "supervisor.lock");
|
|
10931
10931
|
}
|
|
10932
10932
|
var init_lifecycle_paths = __esm({
|
|
10933
10933
|
"lifecycle-paths.mjs"() {
|
|
@@ -10937,15 +10937,15 @@ var init_lifecycle_paths = __esm({
|
|
|
10937
10937
|
// workspace-binding.mjs
|
|
10938
10938
|
import {
|
|
10939
10939
|
existsSync,
|
|
10940
|
-
mkdirSync as
|
|
10941
|
-
readFileSync as
|
|
10942
|
-
renameSync as
|
|
10943
|
-
rmSync as
|
|
10940
|
+
mkdirSync as mkdirSync4,
|
|
10941
|
+
readFileSync as readFileSync3,
|
|
10942
|
+
renameSync as renameSync3,
|
|
10943
|
+
rmSync as rmSync3,
|
|
10944
10944
|
statSync,
|
|
10945
|
-
writeFileSync as
|
|
10945
|
+
writeFileSync as writeFileSync3
|
|
10946
10946
|
} from "node:fs";
|
|
10947
|
-
import { dirname as
|
|
10948
|
-
import { homedir as
|
|
10947
|
+
import { dirname as dirname3, extname, isAbsolute, join as join4, resolve as resolve3 } from "node:path";
|
|
10948
|
+
import { homedir as homedir4 } from "node:os";
|
|
10949
10949
|
function pluginRuntimePath(candidate) {
|
|
10950
10950
|
const value = String(candidate || "").replace(/\//g, "\\").toLowerCase();
|
|
10951
10951
|
return value.includes("\\.codex\\.tmp\\marketplaces\\") || value.includes("\\.codex\\plugins\\cache\\") || value.includes("\\.claude\\plugins\\cache\\") || value.includes("\\appdata\\local\\npm-cache\\_npx\\");
|
|
@@ -10953,11 +10953,11 @@ function pluginRuntimePath(candidate) {
|
|
|
10953
10953
|
function normalizeWorkspacePath(value) {
|
|
10954
10954
|
let raw = String(value || "").trim().replace(/^(["'])(.*)\1$/, "$2").trim();
|
|
10955
10955
|
if (!raw) return "";
|
|
10956
|
-
if (raw === "~") raw =
|
|
10957
|
-
else if (raw.startsWith("~/") || raw.startsWith("~\\")) raw =
|
|
10958
|
-
if (/^\\\\\?\\UNC\\/i.test(raw)) return
|
|
10959
|
-
if (/^\\\\\?\\[a-zA-Z]:\\/.test(raw)) return
|
|
10960
|
-
return
|
|
10956
|
+
if (raw === "~") raw = homedir4();
|
|
10957
|
+
else if (raw.startsWith("~/") || raw.startsWith("~\\")) raw = join4(homedir4(), raw.slice(2));
|
|
10958
|
+
if (/^\\\\\?\\UNC\\/i.test(raw)) return resolve3(`\\\\${raw.slice(8)}`);
|
|
10959
|
+
if (/^\\\\\?\\[a-zA-Z]:\\/.test(raw)) return resolve3(raw.slice(4));
|
|
10960
|
+
return resolve3(raw);
|
|
10961
10961
|
}
|
|
10962
10962
|
function isAbsoluteWorkspacePath(value) {
|
|
10963
10963
|
const raw = String(value || "").trim().replace(/^(["'])(.*)\1$/, "$2").trim();
|
|
@@ -10977,7 +10977,7 @@ function isWorkspaceTarget(projectPath, options = {}) {
|
|
|
10977
10977
|
}
|
|
10978
10978
|
}
|
|
10979
10979
|
function resolveWorkspaceBindingFile(env = process.env) {
|
|
10980
|
-
return
|
|
10980
|
+
return resolve3(env.CURSOR_BRIDGE_WORKSPACE_FILE || join4(defaultLifecycleDir(), "workspaces.json"));
|
|
10981
10981
|
}
|
|
10982
10982
|
function resolveWorkspaceBindingKey(env = process.env, options = {}) {
|
|
10983
10983
|
const codexThreadId = String(env.CODEX_THREAD_ID || "").trim();
|
|
@@ -11001,7 +11001,7 @@ function resolveWorkspaceBindingKey(env = process.env, options = {}) {
|
|
|
11001
11001
|
function readWorkspaceBindings(filePath) {
|
|
11002
11002
|
if (!filePath) return { version: WORKSPACE_BINDING_VERSION, bindings: {} };
|
|
11003
11003
|
try {
|
|
11004
|
-
const parsed = JSON.parse(
|
|
11004
|
+
const parsed = JSON.parse(readFileSync3(filePath, "utf8"));
|
|
11005
11005
|
if (!parsed || parsed.version !== WORKSPACE_BINDING_VERSION || !parsed.bindings || typeof parsed.bindings !== "object") {
|
|
11006
11006
|
return { version: WORKSPACE_BINDING_VERSION, bindings: {} };
|
|
11007
11007
|
}
|
|
@@ -11038,13 +11038,13 @@ function writeWorkspaceBinding(filePath, bindingKey, projectPath, options = {})
|
|
|
11038
11038
|
const state = readWorkspaceBindings(filePath);
|
|
11039
11039
|
const updatedAt = options.updatedAt || (/* @__PURE__ */ new Date()).toISOString();
|
|
11040
11040
|
state.bindings[key] = { projectPath: normalized, updatedAt };
|
|
11041
|
-
|
|
11041
|
+
mkdirSync4(dirname3(filePath), { recursive: true });
|
|
11042
11042
|
const temporary = `${filePath}.${process.pid}.${Date.now()}.tmp`;
|
|
11043
11043
|
try {
|
|
11044
|
-
|
|
11045
|
-
|
|
11044
|
+
writeFileSync3(temporary, JSON.stringify(state, null, 2) + "\n", "utf8");
|
|
11045
|
+
renameSync3(temporary, filePath);
|
|
11046
11046
|
} catch (error2) {
|
|
11047
|
-
|
|
11047
|
+
rmSync3(temporary, { force: true });
|
|
11048
11048
|
throw new Error(`failed to persist cursor_init at ${filePath}: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
11049
11049
|
}
|
|
11050
11050
|
return { projectPath: normalized, updatedAt };
|
|
@@ -11068,8 +11068,8 @@ var init_workspace_binding = __esm({
|
|
|
11068
11068
|
import { spawn as spawn2, execFileSync as execFileSync2 } from "child_process";
|
|
11069
11069
|
import { existsSync as existsSync2 } from "fs";
|
|
11070
11070
|
import { createRequire as createNodeRequire } from "node:module";
|
|
11071
|
-
import { homedir as
|
|
11072
|
-
import { basename as
|
|
11071
|
+
import { homedir as homedir5 } from "node:os";
|
|
11072
|
+
import { basename as basename3, extname as extname2, join as join5, resolve as resolve4, win32 as winPath, posix as posixPath } from "node:path";
|
|
11073
11073
|
import http from "http";
|
|
11074
11074
|
function resolveCursorLaunchCdpPort(port = process.env.CURSOR_BRIDGE_CDP_PORT) {
|
|
11075
11075
|
const parsed = Number(port == null || String(port).trim() === "" ? 9223 : port);
|
|
@@ -11096,13 +11096,13 @@ function resolveCodexThreadProjectPath(options = {}) {
|
|
|
11096
11096
|
try {
|
|
11097
11097
|
const lookupThreadCwd = options.lookupThreadCwd || ((id) => {
|
|
11098
11098
|
const { DatabaseSync } = (options.requireImpl || loadModule)("node:sqlite");
|
|
11099
|
-
const databasePath = options.databasePath ||
|
|
11099
|
+
const databasePath = options.databasePath || join5(homedir5(), ".codex", "state_5.sqlite");
|
|
11100
11100
|
database = new DatabaseSync(databasePath, { readOnly: true });
|
|
11101
11101
|
return database.prepare("SELECT cwd FROM threads WHERE id = ?").get(id)?.cwd || null;
|
|
11102
11102
|
});
|
|
11103
11103
|
const candidate = normalizeCodexThreadCwd(lookupThreadCwd(threadId));
|
|
11104
11104
|
const existsImpl = options.existsImpl || existsSync2;
|
|
11105
|
-
const resolved = candidate && !looksLikePluginRuntimePath(candidate) && existsImpl(candidate) ?
|
|
11105
|
+
const resolved = candidate && !looksLikePluginRuntimePath(candidate) && existsImpl(candidate) ? resolve4(candidate) : null;
|
|
11106
11106
|
if (options.useCache !== false) CODEX_THREAD_PROJECTS.set(threadId, resolved);
|
|
11107
11107
|
return resolved;
|
|
11108
11108
|
} catch {
|
|
@@ -11117,14 +11117,14 @@ function resolveCodexThreadProjectPath(options = {}) {
|
|
|
11117
11117
|
}
|
|
11118
11118
|
function resolveProjectPath(value = process.env.CURSOR_PROJECT_PATH, options = {}) {
|
|
11119
11119
|
const explicit = String(value || "").trim();
|
|
11120
|
-
if (explicit) return
|
|
11120
|
+
if (explicit) return resolve4(explicit);
|
|
11121
11121
|
const persisted = String(options.persistedProjectPath || "").trim();
|
|
11122
|
-
if (persisted) return
|
|
11122
|
+
if (persisted) return resolve4(normalizeCodexThreadCwd(persisted));
|
|
11123
11123
|
const threadProjectPath = options.threadProjectPath === void 0 ? resolveCodexThreadProjectPath(options) : options.threadProjectPath;
|
|
11124
|
-
if (threadProjectPath) return
|
|
11124
|
+
if (threadProjectPath) return resolve4(normalizeCodexThreadCwd(threadProjectPath));
|
|
11125
11125
|
const cwd = options.cwd ?? process.cwd();
|
|
11126
11126
|
if (!cwd || looksLikePluginRuntimePath(cwd)) return null;
|
|
11127
|
-
return
|
|
11127
|
+
return resolve4(cwd);
|
|
11128
11128
|
}
|
|
11129
11129
|
function cursorFromRegistry(options = {}) {
|
|
11130
11130
|
const execFileSyncImpl = options.execFileSyncImpl || execFileSync2;
|
|
@@ -11189,7 +11189,7 @@ function findCursorExeDetails(options = {}) {
|
|
|
11189
11189
|
existsImpl
|
|
11190
11190
|
});
|
|
11191
11191
|
if (fromReg) return { path: fromReg, source: "windows_registry", platform };
|
|
11192
|
-
const localAppData = env.LOCALAPPDATA ||
|
|
11192
|
+
const localAppData = env.LOCALAPPDATA || join5(homedir5(), "AppData", "Local");
|
|
11193
11193
|
const programFiles = env.ProgramFiles || env.PROGRAMFILES || "C:\\Program Files";
|
|
11194
11194
|
const programFilesX86 = env["ProgramFiles(x86)"] || env.PROGRAMFILES_X86 || "";
|
|
11195
11195
|
const candidates = [
|
|
@@ -11206,7 +11206,7 @@ function findCursorExeDetails(options = {}) {
|
|
|
11206
11206
|
return null;
|
|
11207
11207
|
}
|
|
11208
11208
|
if (platform === "darwin") {
|
|
11209
|
-
const userHome = env.HOME ||
|
|
11209
|
+
const userHome = env.HOME || homedir5();
|
|
11210
11210
|
const candidates = [
|
|
11211
11211
|
"/Applications/Cursor.app/Contents/MacOS/Cursor",
|
|
11212
11212
|
userHome && posixPath.join(userHome, "Applications", "Cursor.app", "Contents", "MacOS", "Cursor")
|
|
@@ -11225,42 +11225,42 @@ function findCursorExe(options = {}) {
|
|
|
11225
11225
|
return findCursorExeDetails(options)?.path || null;
|
|
11226
11226
|
}
|
|
11227
11227
|
function cdpUp(timeoutMs = 1500) {
|
|
11228
|
-
return new Promise((
|
|
11228
|
+
return new Promise((resolve7) => {
|
|
11229
11229
|
const req = http.get({ host: CDP_HOST, port: CDP_PORT, path: "/json/version" }, (res) => {
|
|
11230
11230
|
res.resume();
|
|
11231
|
-
|
|
11231
|
+
resolve7(res.statusCode === 200);
|
|
11232
11232
|
});
|
|
11233
|
-
req.on("error", () =>
|
|
11233
|
+
req.on("error", () => resolve7(false));
|
|
11234
11234
|
req.setTimeout(timeoutMs, () => {
|
|
11235
11235
|
try {
|
|
11236
11236
|
req.destroy();
|
|
11237
11237
|
} catch {
|
|
11238
11238
|
}
|
|
11239
|
-
|
|
11239
|
+
resolve7(false);
|
|
11240
11240
|
});
|
|
11241
11241
|
});
|
|
11242
11242
|
}
|
|
11243
11243
|
function cdpIsCursor(timeoutMs = 1500) {
|
|
11244
|
-
return new Promise((
|
|
11244
|
+
return new Promise((resolve7) => {
|
|
11245
11245
|
const req = http.get({ host: CDP_HOST, port: CDP_PORT, path: "/json/list" }, (res) => {
|
|
11246
11246
|
let d = "";
|
|
11247
11247
|
res.on("data", (c) => d += c);
|
|
11248
11248
|
res.on("end", () => {
|
|
11249
11249
|
try {
|
|
11250
|
-
if (/[\/\\](windsurf)[\/\\]/i.test(d)) return
|
|
11251
|
-
|
|
11250
|
+
if (/[\/\\](windsurf)[\/\\]/i.test(d)) return resolve7(false);
|
|
11251
|
+
resolve7(/[\/\\]cursor[\/\\](resources|app)|cursor\.exe|vscode-app[^"]*[\/\\]cursor[\/\\]/i.test(d));
|
|
11252
11252
|
} catch {
|
|
11253
|
-
|
|
11253
|
+
resolve7(false);
|
|
11254
11254
|
}
|
|
11255
11255
|
});
|
|
11256
11256
|
});
|
|
11257
|
-
req.on("error", () =>
|
|
11257
|
+
req.on("error", () => resolve7(false));
|
|
11258
11258
|
req.setTimeout(timeoutMs, () => {
|
|
11259
11259
|
try {
|
|
11260
11260
|
req.destroy();
|
|
11261
11261
|
} catch {
|
|
11262
11262
|
}
|
|
11263
|
-
|
|
11263
|
+
resolve7(false);
|
|
11264
11264
|
});
|
|
11265
11265
|
});
|
|
11266
11266
|
}
|
|
@@ -11300,7 +11300,7 @@ async function ensureCursorRunningLocal(options = {}) {
|
|
|
11300
11300
|
const cdpIsCursorImpl = options.cdpIsCursorImpl || cdpIsCursor;
|
|
11301
11301
|
const cursorRunningImpl = options.cursorRunningImpl || cursorRunning;
|
|
11302
11302
|
const findCursorExeDetailsImpl = options.findCursorExeDetailsImpl || findCursorExeDetails;
|
|
11303
|
-
const projectPath = Object.hasOwn(options, "projectPath") ? options.projectPath ?
|
|
11303
|
+
const projectPath = Object.hasOwn(options, "projectPath") ? options.projectPath ? resolve4(String(options.projectPath)) : null : resolveProjectPath();
|
|
11304
11304
|
const listCdpPageTargetsImpl = options.listCdpPageTargetsImpl || listCdpPageTargets;
|
|
11305
11305
|
const spawnImpl = options.spawnImpl || spawn2;
|
|
11306
11306
|
if (await cdpUpImpl()) {
|
|
@@ -11517,10 +11517,10 @@ async function ensureCursorRunningLocal(options = {}) {
|
|
|
11517
11517
|
};
|
|
11518
11518
|
}
|
|
11519
11519
|
function normalizeProjectKey(projectPath) {
|
|
11520
|
-
return projectPath ?
|
|
11520
|
+
return projectPath ? resolve4(String(projectPath)).replace(/\\/g, "/").toLowerCase() : "";
|
|
11521
11521
|
}
|
|
11522
11522
|
function targetTitleMatchesProject(title, projectPath) {
|
|
11523
|
-
const name =
|
|
11523
|
+
const name = basename3(String(projectPath || "")).trim().toLowerCase();
|
|
11524
11524
|
if (!name) return false;
|
|
11525
11525
|
const extension2 = extname2(name);
|
|
11526
11526
|
const candidates = [...new Set([name, extension2 ? name.slice(0, -extension2.length) : name].filter(Boolean))];
|
|
@@ -11707,66 +11707,66 @@ import net from "node:net";
|
|
|
11707
11707
|
import { createHash as createHash2 } from "node:crypto";
|
|
11708
11708
|
import {
|
|
11709
11709
|
existsSync as existsSync4,
|
|
11710
|
-
mkdirSync as
|
|
11711
|
-
readFileSync as
|
|
11710
|
+
mkdirSync as mkdirSync5,
|
|
11711
|
+
readFileSync as readFileSync4,
|
|
11712
11712
|
readdirSync,
|
|
11713
|
-
renameSync as
|
|
11714
|
-
rmSync as
|
|
11713
|
+
renameSync as renameSync4,
|
|
11714
|
+
rmSync as rmSync4,
|
|
11715
11715
|
unlinkSync,
|
|
11716
|
-
writeFileSync as
|
|
11716
|
+
writeFileSync as writeFileSync4
|
|
11717
11717
|
} from "node:fs";
|
|
11718
11718
|
import { fileURLToPath } from "node:url";
|
|
11719
|
-
import { dirname as
|
|
11719
|
+
import { dirname as dirname4, join as join6, resolve as resolve5 } from "node:path";
|
|
11720
11720
|
function sleep(ms) {
|
|
11721
11721
|
return new Promise((r) => setTimeout(r, ms));
|
|
11722
11722
|
}
|
|
11723
11723
|
function resolveSupervisorScript() {
|
|
11724
11724
|
if (process.env.CURSOR_BRIDGE_SUPERVISOR_SCRIPT && existsSync4(process.env.CURSOR_BRIDGE_SUPERVISOR_SCRIPT)) {
|
|
11725
|
-
return
|
|
11725
|
+
return resolve5(process.env.CURSOR_BRIDGE_SUPERVISOR_SCRIPT);
|
|
11726
11726
|
}
|
|
11727
|
-
const here =
|
|
11727
|
+
const here = dirname4(fileURLToPath(import.meta.url));
|
|
11728
11728
|
const candidates = [];
|
|
11729
11729
|
if (typeof process.argv[1] === "string") {
|
|
11730
|
-
const entryDir =
|
|
11731
|
-
candidates.push(
|
|
11732
|
-
candidates.push(
|
|
11730
|
+
const entryDir = dirname4(resolve5(process.argv[1]));
|
|
11731
|
+
candidates.push(join6(entryDir, "dist", "cursor-lifecycle-supervisor.mjs"));
|
|
11732
|
+
candidates.push(join6(entryDir, "cursor-lifecycle-supervisor.mjs"));
|
|
11733
11733
|
}
|
|
11734
11734
|
candidates.push(
|
|
11735
|
-
|
|
11736
|
-
|
|
11735
|
+
join6(here, "dist", "cursor-lifecycle-supervisor.mjs"),
|
|
11736
|
+
join6(here, "cursor-lifecycle-supervisor.mjs")
|
|
11737
11737
|
);
|
|
11738
11738
|
for (const c of candidates) {
|
|
11739
11739
|
if (existsSync4(c)) return c;
|
|
11740
11740
|
}
|
|
11741
|
-
return
|
|
11741
|
+
return join6(here, "cursor-lifecycle-supervisor.mjs");
|
|
11742
11742
|
}
|
|
11743
11743
|
function writeRuntimeFile(target, content) {
|
|
11744
|
-
if (existsSync4(target) &&
|
|
11744
|
+
if (existsSync4(target) && readFileSync4(target).equals(content)) return;
|
|
11745
11745
|
const temporary = `${target}.${process.pid}.${Date.now()}.tmp`;
|
|
11746
|
-
|
|
11746
|
+
writeFileSync4(temporary, content);
|
|
11747
11747
|
try {
|
|
11748
|
-
|
|
11748
|
+
renameSync4(temporary, target);
|
|
11749
11749
|
} catch (error2) {
|
|
11750
11750
|
if (!existsSync4(target)) {
|
|
11751
|
-
|
|
11751
|
+
rmSync4(temporary, { force: true });
|
|
11752
11752
|
throw error2;
|
|
11753
11753
|
}
|
|
11754
|
-
if (
|
|
11755
|
-
|
|
11754
|
+
if (readFileSync4(target).equals(content)) {
|
|
11755
|
+
rmSync4(temporary, { force: true });
|
|
11756
11756
|
return;
|
|
11757
11757
|
}
|
|
11758
|
-
|
|
11759
|
-
|
|
11758
|
+
rmSync4(target, { force: true });
|
|
11759
|
+
renameSync4(temporary, target);
|
|
11760
11760
|
}
|
|
11761
11761
|
}
|
|
11762
11762
|
function materializeLifecycleSupervisorRuntime({ sourceScript, dir = defaultLifecycleDir() } = {}) {
|
|
11763
|
-
const source =
|
|
11763
|
+
const source = resolve5(sourceScript || resolveSupervisorScript());
|
|
11764
11764
|
if (!existsSync4(source)) throw new Error(`lifecycle supervisor script missing: ${source}`);
|
|
11765
|
-
const content =
|
|
11765
|
+
const content = readFileSync4(source);
|
|
11766
11766
|
const fingerprint = createHash2("sha256").update(content).digest("hex");
|
|
11767
|
-
const runtimeRoot =
|
|
11768
|
-
|
|
11769
|
-
const script =
|
|
11767
|
+
const runtimeRoot = join6(ensureLifecycleDir(dir), "runtime", `supervisor-${fingerprint.slice(0, 20)}`);
|
|
11768
|
+
mkdirSync5(runtimeRoot, { recursive: true });
|
|
11769
|
+
const script = join6(runtimeRoot, "cursor-lifecycle-supervisor.mjs");
|
|
11770
11770
|
writeRuntimeFile(script, content);
|
|
11771
11771
|
return { sourceScript: source, script, runtimeRoot, fingerprint };
|
|
11772
11772
|
}
|
|
@@ -11781,7 +11781,7 @@ function isProcessAlive(pid) {
|
|
|
11781
11781
|
}
|
|
11782
11782
|
function readPidFile(pidPath) {
|
|
11783
11783
|
try {
|
|
11784
|
-
const n = Number(String(
|
|
11784
|
+
const n = Number(String(readFileSync4(pidPath, "utf8")).trim());
|
|
11785
11785
|
return Number.isFinite(n) ? n : null;
|
|
11786
11786
|
} catch {
|
|
11787
11787
|
return null;
|
|
@@ -11874,7 +11874,7 @@ function tryUnlink(path) {
|
|
|
11874
11874
|
}
|
|
11875
11875
|
}
|
|
11876
11876
|
function writeBootEnv(dir, extra = {}) {
|
|
11877
|
-
const bootPath =
|
|
11877
|
+
const bootPath = join6(dir, `boot-env-${process.pid}-${Date.now()}.json`);
|
|
11878
11878
|
const payload = { ...extra };
|
|
11879
11879
|
for (const [key, value] of Object.entries(process.env)) {
|
|
11880
11880
|
if (key.startsWith("CURSOR_BRIDGE_") || key === "CURSOR_PROJECT_PATH" || key === "CURSOR_EXE") {
|
|
@@ -11885,7 +11885,7 @@ function writeBootEnv(dir, extra = {}) {
|
|
|
11885
11885
|
for (const [k, v] of Object.entries(payload)) {
|
|
11886
11886
|
if (v != null && v !== "") cleaned[k] = String(v);
|
|
11887
11887
|
}
|
|
11888
|
-
|
|
11888
|
+
writeFileSync4(bootPath, `${JSON.stringify(cleaned, null, 2)}
|
|
11889
11889
|
`, { encoding: "utf8" });
|
|
11890
11890
|
return bootPath;
|
|
11891
11891
|
}
|
|
@@ -11897,9 +11897,9 @@ async function ensureSupervisorConnected(options = {}) {
|
|
|
11897
11897
|
const createWaitMs = Number(options.createWaitMs || DEFAULT_CREATE_WAIT_MS);
|
|
11898
11898
|
const sourceScript = options.supervisorScript || resolveSupervisorScript();
|
|
11899
11899
|
const runtime = options.persistSupervisorRuntime === false ? {
|
|
11900
|
-
sourceScript:
|
|
11901
|
-
script:
|
|
11902
|
-
runtimeRoot:
|
|
11900
|
+
sourceScript: resolve5(sourceScript),
|
|
11901
|
+
script: resolve5(sourceScript),
|
|
11902
|
+
runtimeRoot: dirname4(resolve5(sourceScript)),
|
|
11903
11903
|
fingerprint: null
|
|
11904
11904
|
} : materializeLifecycleSupervisorRuntime({ sourceScript, dir });
|
|
11905
11905
|
let socket = await tryConnect(sock);
|
|
@@ -19478,7 +19478,7 @@ var Protocol = class {
|
|
|
19478
19478
|
return;
|
|
19479
19479
|
}
|
|
19480
19480
|
const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1e3;
|
|
19481
|
-
await new Promise((
|
|
19481
|
+
await new Promise((resolve7) => setTimeout(resolve7, pollInterval));
|
|
19482
19482
|
options?.signal?.throwIfAborted();
|
|
19483
19483
|
}
|
|
19484
19484
|
} catch (error2) {
|
|
@@ -19495,7 +19495,7 @@ var Protocol = class {
|
|
|
19495
19495
|
*/
|
|
19496
19496
|
request(request2, resultSchema, options) {
|
|
19497
19497
|
const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
|
|
19498
|
-
return new Promise((
|
|
19498
|
+
return new Promise((resolve7, reject) => {
|
|
19499
19499
|
const earlyReject = (error2) => {
|
|
19500
19500
|
reject(error2);
|
|
19501
19501
|
};
|
|
@@ -19573,7 +19573,7 @@ var Protocol = class {
|
|
|
19573
19573
|
if (!parseResult.success) {
|
|
19574
19574
|
reject(parseResult.error);
|
|
19575
19575
|
} else {
|
|
19576
|
-
|
|
19576
|
+
resolve7(parseResult.data);
|
|
19577
19577
|
}
|
|
19578
19578
|
} catch (error2) {
|
|
19579
19579
|
reject(error2);
|
|
@@ -19834,12 +19834,12 @@ var Protocol = class {
|
|
|
19834
19834
|
}
|
|
19835
19835
|
} catch {
|
|
19836
19836
|
}
|
|
19837
|
-
return new Promise((
|
|
19837
|
+
return new Promise((resolve7, reject) => {
|
|
19838
19838
|
if (signal.aborted) {
|
|
19839
19839
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
19840
19840
|
return;
|
|
19841
19841
|
}
|
|
19842
|
-
const timeoutId = setTimeout(
|
|
19842
|
+
const timeoutId = setTimeout(resolve7, interval);
|
|
19843
19843
|
signal.addEventListener("abort", () => {
|
|
19844
19844
|
clearTimeout(timeoutId);
|
|
19845
19845
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
@@ -20709,19 +20709,19 @@ var StdioServerTransport = class {
|
|
|
20709
20709
|
this.onclose?.();
|
|
20710
20710
|
}
|
|
20711
20711
|
send(message) {
|
|
20712
|
-
return new Promise((
|
|
20712
|
+
return new Promise((resolve7) => {
|
|
20713
20713
|
const json = serializeMessage(message);
|
|
20714
20714
|
if (this._stdout.write(json)) {
|
|
20715
|
-
|
|
20715
|
+
resolve7();
|
|
20716
20716
|
} else {
|
|
20717
|
-
this._stdout.once("drain",
|
|
20717
|
+
this._stdout.once("drain", resolve7);
|
|
20718
20718
|
}
|
|
20719
20719
|
});
|
|
20720
20720
|
}
|
|
20721
20721
|
};
|
|
20722
20722
|
|
|
20723
20723
|
// server.mjs
|
|
20724
|
-
import { basename as
|
|
20724
|
+
import { basename as basename4, dirname as dirname5, join as join7, resolve as resolve6 } from "node:path";
|
|
20725
20725
|
|
|
20726
20726
|
// node_modules/ws/wrapper.mjs
|
|
20727
20727
|
var import_stream = __toESM(require_stream(), 1);
|
|
@@ -20735,12 +20735,119 @@ var import_websocket_server = __toESM(require_websocket_server(), 1);
|
|
|
20735
20735
|
|
|
20736
20736
|
// server.mjs
|
|
20737
20737
|
init_cursor_runtime();
|
|
20738
|
+
import http2 from "http";
|
|
20739
|
+
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
20740
|
+
|
|
20741
|
+
// cursor-model-preferences.mjs
|
|
20742
|
+
import { mkdirSync as mkdirSync2, readFileSync as readFileSync2, renameSync as renameSync2, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
20743
|
+
import { homedir as homedir2 } from "node:os";
|
|
20744
|
+
import { basename as basename2, dirname as dirname2, join as join2, resolve as resolve2 } from "node:path";
|
|
20745
|
+
var CURSOR_MODEL_TARGETS = Object.freeze(["cce", "cursor_do"]);
|
|
20746
|
+
var CURSOR_MODEL_EFFORTS = Object.freeze(["low", "medium", "high", "xhigh", "max"]);
|
|
20747
|
+
function normalizeCursorModelTarget(value, fallback = "") {
|
|
20748
|
+
const normalized = String(value || "").trim().toLowerCase().replace(/-/g, "_");
|
|
20749
|
+
if (normalized === "context_engine" || normalized === "cursor_context_engine") return "cce";
|
|
20750
|
+
if (normalized === "do" || normalized === "delegate") return "cursor_do";
|
|
20751
|
+
return CURSOR_MODEL_TARGETS.includes(normalized) ? normalized : fallback;
|
|
20752
|
+
}
|
|
20753
|
+
function normalizeCursorModelEffort(value, fallback = "") {
|
|
20754
|
+
const normalized = String(value || "").trim().toLowerCase().replace(/[_\s]+/g, "-");
|
|
20755
|
+
if (normalized === "extra-high" || normalized === "extra-high-thinking") return "xhigh";
|
|
20756
|
+
return CURSOR_MODEL_EFFORTS.includes(normalized) ? normalized : fallback;
|
|
20757
|
+
}
|
|
20758
|
+
function cursorEffortUiValue(value) {
|
|
20759
|
+
const normalized = normalizeCursorModelEffort(value, "");
|
|
20760
|
+
return normalized === "xhigh" ? "extra-high" : normalized;
|
|
20761
|
+
}
|
|
20762
|
+
function normalizeCursorModelPreference(value, options = {}) {
|
|
20763
|
+
if (value == null) return null;
|
|
20764
|
+
const model = String(value.model || "").trim();
|
|
20765
|
+
if (!model) {
|
|
20766
|
+
if (options.allowEmpty) return null;
|
|
20767
|
+
throw new Error("model must not be empty");
|
|
20768
|
+
}
|
|
20769
|
+
if (model.length > 200) throw new Error("model exceeds the 200-character limit");
|
|
20770
|
+
const rawEffort = value.effort == null ? "" : String(value.effort).trim();
|
|
20771
|
+
const effort = rawEffort ? normalizeCursorModelEffort(rawEffort, "") : null;
|
|
20772
|
+
if (rawEffort && !effort) {
|
|
20773
|
+
throw new Error(`unsupported Cursor model effort: ${value.effort}; expected low, medium, high, xhigh, or max`);
|
|
20774
|
+
}
|
|
20775
|
+
return { model, effort };
|
|
20776
|
+
}
|
|
20777
|
+
function resolveCursorModelPreferencesFile(value = process.env.CURSOR_BRIDGE_MODEL_PREFERENCES_FILE) {
|
|
20778
|
+
const configured = String(value || "").trim();
|
|
20779
|
+
if (configured) return resolve2(configured);
|
|
20780
|
+
const configRoot = process.platform === "win32" && process.env.APPDATA ? process.env.APPDATA : process.env.XDG_CONFIG_HOME || join2(homedir2(), ".config");
|
|
20781
|
+
return join2(configRoot, "cursor-bridge", "model-preferences.json");
|
|
20782
|
+
}
|
|
20783
|
+
function emptyPreferences() {
|
|
20784
|
+
return { version: 1, targets: { cce: null, cursor_do: null }, updatedAt: null };
|
|
20785
|
+
}
|
|
20786
|
+
function readCursorModelPreferences(filePath) {
|
|
20787
|
+
const empty = emptyPreferences();
|
|
20788
|
+
if (!filePath) return empty;
|
|
20789
|
+
try {
|
|
20790
|
+
const parsed = JSON.parse(readFileSync2(filePath, "utf8"));
|
|
20791
|
+
const targets = parsed && typeof parsed.targets === "object" ? parsed.targets : {};
|
|
20792
|
+
return {
|
|
20793
|
+
version: 1,
|
|
20794
|
+
targets: {
|
|
20795
|
+
cce: normalizeCursorModelPreference(targets.cce, { allowEmpty: true }),
|
|
20796
|
+
cursor_do: normalizeCursorModelPreference(targets.cursor_do, { allowEmpty: true })
|
|
20797
|
+
},
|
|
20798
|
+
updatedAt: parsed && parsed.updatedAt ? String(parsed.updatedAt) : null
|
|
20799
|
+
};
|
|
20800
|
+
} catch (error2) {
|
|
20801
|
+
if (error2 && error2.code === "ENOENT") return empty;
|
|
20802
|
+
console.error(`[cursor-bridge] ignoring unreadable model preferences file ${filePath}: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
20803
|
+
return empty;
|
|
20804
|
+
}
|
|
20805
|
+
}
|
|
20806
|
+
function writeCursorModelPreferences(filePath, preferences) {
|
|
20807
|
+
if (!filePath) throw new Error("persistent cursor_model storage is disabled for this server");
|
|
20808
|
+
const target = resolve2(filePath);
|
|
20809
|
+
const normalized = {
|
|
20810
|
+
version: 1,
|
|
20811
|
+
targets: {
|
|
20812
|
+
cce: normalizeCursorModelPreference(preferences && preferences.targets && preferences.targets.cce, { allowEmpty: true }),
|
|
20813
|
+
cursor_do: normalizeCursorModelPreference(preferences && preferences.targets && preferences.targets.cursor_do, { allowEmpty: true })
|
|
20814
|
+
},
|
|
20815
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
20816
|
+
};
|
|
20817
|
+
mkdirSync2(dirname2(target), { recursive: true });
|
|
20818
|
+
const temporary = join2(dirname2(target), `.${basename2(target)}.${process.pid}.${Date.now()}.tmp`);
|
|
20819
|
+
try {
|
|
20820
|
+
writeFileSync2(temporary, `${JSON.stringify(normalized, null, 2)}
|
|
20821
|
+
`, { encoding: "utf8", mode: 384 });
|
|
20822
|
+
renameSync2(temporary, target);
|
|
20823
|
+
} catch (error2) {
|
|
20824
|
+
rmSync2(temporary, { force: true });
|
|
20825
|
+
throw new Error(`failed to persist cursor_model at ${target}: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
20826
|
+
}
|
|
20827
|
+
return normalized;
|
|
20828
|
+
}
|
|
20829
|
+
function updateCursorModelPreferences(filePath, { action, target, model, effort } = {}) {
|
|
20830
|
+
const normalizedAction = String(action || "show").trim().toLowerCase();
|
|
20831
|
+
if (!["show", "set", "reset"].includes(normalizedAction)) {
|
|
20832
|
+
throw new Error(`unsupported cursor_model action: ${action}; expected show, set, or reset`);
|
|
20833
|
+
}
|
|
20834
|
+
const selectedTargets = String(target || "").trim().toLowerCase() === "both" ? [...CURSOR_MODEL_TARGETS] : [normalizeCursorModelTarget(target, "")].filter(Boolean);
|
|
20835
|
+
if (normalizedAction !== "show" && selectedTargets.length === 0) {
|
|
20836
|
+
throw new Error("cursor_model set/reset requires target=cce, cursor_do, or both");
|
|
20837
|
+
}
|
|
20838
|
+
const current = readCursorModelPreferences(filePath);
|
|
20839
|
+
if (normalizedAction === "show") return current;
|
|
20840
|
+
const next = { ...current, targets: { ...current.targets } };
|
|
20841
|
+
const preference = normalizedAction === "set" ? normalizeCursorModelPreference({ model, effort }) : null;
|
|
20842
|
+
for (const selectedTarget of selectedTargets) next.targets[selectedTarget] = preference;
|
|
20843
|
+
return writeCursorModelPreferences(filePath, next);
|
|
20844
|
+
}
|
|
20845
|
+
|
|
20846
|
+
// server.mjs
|
|
20738
20847
|
init_workspace_binding();
|
|
20739
20848
|
init_cursor_ensure_core();
|
|
20740
20849
|
init_lifecycle_paths();
|
|
20741
|
-
|
|
20742
|
-
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
20743
|
-
var PLUGIN_VERSION = "5.5.0";
|
|
20850
|
+
var PLUGIN_VERSION = "5.6.0";
|
|
20744
20851
|
var CDP_PORT2 = Number(process.env.CURSOR_BRIDGE_CDP_PORT || 9223);
|
|
20745
20852
|
var ORIGIN = `http://localhost:${CDP_PORT2}`;
|
|
20746
20853
|
var QUERY_TIMEOUT = Number(process.env.CURSOR_BRIDGE_TIMEOUT || 3e5);
|
|
@@ -20797,13 +20904,13 @@ var DO_DEFAULT_CONTRACT = "\n\nCompletion requirements: Work directly in the wor
|
|
|
20797
20904
|
var DO_LANGUAGE_CONTRACT = "\n\nResponse language: Reply in the language of the user task unless it explicitly requests another language. Never translate paths, commands, identifiers, keys, enum values, exact options, or error/status codes.";
|
|
20798
20905
|
var CDP_HOST2 = "127.0.0.1";
|
|
20799
20906
|
function httpJson(path) {
|
|
20800
|
-
return new Promise((
|
|
20907
|
+
return new Promise((resolve7, reject) => {
|
|
20801
20908
|
const req = http2.get({ host: CDP_HOST2, port: CDP_PORT2, path }, (res) => {
|
|
20802
20909
|
let d = "";
|
|
20803
20910
|
res.on("data", (c) => d += c);
|
|
20804
20911
|
res.on("end", () => {
|
|
20805
20912
|
try {
|
|
20806
|
-
|
|
20913
|
+
resolve7(JSON.parse(d));
|
|
20807
20914
|
} catch {
|
|
20808
20915
|
reject(new Error("CDP returned a non-JSON response"));
|
|
20809
20916
|
}
|
|
@@ -21185,6 +21292,73 @@ function exprClickBoundComposerStop(agentId) {
|
|
|
21185
21292
|
})()`;
|
|
21186
21293
|
}
|
|
21187
21294
|
var EXPR_FIND_NEWAGENT = `(function(){const b=[...document.querySelectorAll('button,[role=button],a.action-label,.codicon')].find(e=>{if(e.offsetParent===null||e.closest('.glass-sidebar-agent-menu-btn'))return false;const s=(e.getAttribute('aria-label')||'')+' '+(e.getAttribute('title')||'')+' '+(e.innerText||'');return /(?:^|\\s)New (?:Agent|Chat)(?:\\s|$)/i.test(s);});if(!b)return '';const r=b.getBoundingClientRect();return JSON.stringify({x:Math.round(r.x+r.width/2),y:Math.round(r.y+r.height/2)});})()`;
|
|
21295
|
+
var MODEL_PICKER_VISIBLE_BODY = `
|
|
21296
|
+
const visible=(node)=>!!(node&&(node.offsetParent!==null||(node.getClientRects&&node.getClientRects().length>0)));
|
|
21297
|
+
const composers=[...document.querySelectorAll('.composer-bar[data-composer-id],.composer-bar,.ui-prompt-input-root')].filter(visible);
|
|
21298
|
+
const composer=composers[composers.length-1]||document;
|
|
21299
|
+
`;
|
|
21300
|
+
var EXPR_MODEL_PICKER_TRIGGER = `(function(){
|
|
21301
|
+
${MODEL_PICKER_VISIBLE_BODY}
|
|
21302
|
+
const triggerSelector='.ui-model-picker__trigger,.vscode-model-picker__trigger';
|
|
21303
|
+
const candidates=[...composer.querySelectorAll(triggerSelector)].filter(visible);
|
|
21304
|
+
const trigger=candidates[candidates.length-1]||[...document.querySelectorAll(triggerSelector)].filter(visible).pop();
|
|
21305
|
+
if(!trigger)return JSON.stringify({found:false,state:'trigger_missing'});
|
|
21306
|
+
const rect=trigger.getBoundingClientRect();
|
|
21307
|
+
const text=String(trigger.querySelector('.ui-model-picker__trigger-text,.vscode-model-picker__trigger-text')?.innerText||trigger.innerText||'').replace(/\\s+/g,' ').trim();
|
|
21308
|
+
const detail=String(trigger.querySelector('.ui-model-picker__trigger-variant-suffix,.vscode-model-picker__trigger-variant-suffix')?.innerText||'').replace(/\\s+/g,' ').trim();
|
|
21309
|
+
return JSON.stringify({found:true,state:'ready',text,detail,x:Math.round(rect.x+rect.width/2),y:Math.round(rect.y+rect.height/2)});
|
|
21310
|
+
})()`;
|
|
21311
|
+
var EXPR_MODEL_PICKER_ROWS = `(function(){
|
|
21312
|
+
${MODEL_PICKER_VISIBLE_BODY}
|
|
21313
|
+
const menus=[...document.querySelectorAll('[data-testid="model-picker-menu"],[data-testid*="model-parameters"],[data-testid*="parameter-submenu"],[data-component="menu-popup"][data-submenu]')].filter(visible);
|
|
21314
|
+
const rows=[];
|
|
21315
|
+
const seen=new Set();
|
|
21316
|
+
for(const menu of menus){
|
|
21317
|
+
for(const row of menu.querySelectorAll('[data-component="menu-row"],[data-component="menu-submenu-trigger"],[role="menuitem"],[role="menuitemradio"],[role="menuitemcheckbox"]')){
|
|
21318
|
+
if(!visible(row)||seen.has(row))continue;
|
|
21319
|
+
seen.add(row);
|
|
21320
|
+
const rect=row.getBoundingClientRect();
|
|
21321
|
+
const text=String(row.innerText||row.textContent||'').replace(/\\s+/g,' ').trim();
|
|
21322
|
+
if(!text)continue;
|
|
21323
|
+
const menuTestId=String(menu.getAttribute('data-testid')||'').toLowerCase();
|
|
21324
|
+
let kind='control';
|
|
21325
|
+
if(row.querySelector('.ui-model-picker__item-content-name,.vscode-model-picker__item-content-name'))kind='model';
|
|
21326
|
+
else if(/^model(?:\\s|$)/i.test(text)&&row.getAttribute('aria-haspopup')==='menu')kind='model_control';
|
|
21327
|
+
else if(/^effort(?:\\s|$)/i.test(text)&&row.getAttribute('aria-haspopup')==='menu')kind='effort_control';
|
|
21328
|
+
else if(menuTestId.includes('parameter-submenu')||row.closest('[data-submenu]'))kind='parameter';
|
|
21329
|
+
else if(menuTestId.includes('model-picker-menu')||menuTestId.includes('model-selection'))kind='model';
|
|
21330
|
+
rows.push({
|
|
21331
|
+
text,
|
|
21332
|
+
kind,
|
|
21333
|
+
selected:row.getAttribute('data-selected')==='true'||row.getAttribute('aria-checked')==='true'||!!row.querySelector('.ui-model-picker__item-check,.ui-model-picker__param-check'),
|
|
21334
|
+
disabled:row.getAttribute('data-disabled')==='true'||row.getAttribute('aria-disabled')==='true',
|
|
21335
|
+
hasSubmenu:row.getAttribute('aria-haspopup')==='menu',
|
|
21336
|
+
submenu:!!row.closest('[data-submenu]'),
|
|
21337
|
+
x:Math.round(rect.x+rect.width/2),
|
|
21338
|
+
y:Math.round(rect.y+rect.height/2),
|
|
21339
|
+
});
|
|
21340
|
+
}
|
|
21341
|
+
}
|
|
21342
|
+
return JSON.stringify({open:menus.length>0,rows});
|
|
21343
|
+
})()`;
|
|
21344
|
+
function normalizeModelPickerText(value) {
|
|
21345
|
+
return String(value || "").trim().toLowerCase().replace(/extra[\s_-]*high/g, "xhigh").replace(/[^a-z0-9]+/g, "");
|
|
21346
|
+
}
|
|
21347
|
+
function selectModelPickerRow(rows, requested, kind = "model") {
|
|
21348
|
+
const wanted = normalizeModelPickerText(requested);
|
|
21349
|
+
if (!wanted) return null;
|
|
21350
|
+
const candidates = (Array.isArray(rows) ? rows : []).filter((row) => row && row.disabled !== true && (kind === "any" || row.kind === kind)).map((row) => {
|
|
21351
|
+
const normalized = normalizeModelPickerText(row.text);
|
|
21352
|
+
let score = normalized === wanted ? 1e3 : 0;
|
|
21353
|
+
if (!score && normalized.startsWith(wanted)) score = 800;
|
|
21354
|
+
if (!score && wanted.startsWith(normalized)) score = 700;
|
|
21355
|
+
if (!score && normalized.includes(wanted)) score = 600;
|
|
21356
|
+
return { row, score, distance: Math.abs(normalized.length - wanted.length) };
|
|
21357
|
+
}).filter((entry) => entry.score > 0).sort((a, b) => b.score - a.score || a.distance - b.distance);
|
|
21358
|
+
if (candidates.length === 0) return null;
|
|
21359
|
+
if (candidates.length > 1 && candidates[0].score === candidates[1].score && candidates[0].distance === candidates[1].distance) return null;
|
|
21360
|
+
return candidates[0].row;
|
|
21361
|
+
}
|
|
21188
21362
|
var WORKSPACE_SECTION_BODY = `
|
|
21189
21363
|
const headText=(el)=>String(el&&(el.innerText||el.textContent)||'').trim();
|
|
21190
21364
|
const isNewAgentButton=(node)=>{
|
|
@@ -21228,7 +21402,7 @@ var WORKSPACE_SECTION_BODY = `
|
|
|
21228
21402
|
};
|
|
21229
21403
|
`;
|
|
21230
21404
|
function exprCreateAgentForWorkspace(projectPath) {
|
|
21231
|
-
const workspaceLabel = JSON.stringify(
|
|
21405
|
+
const workspaceLabel = JSON.stringify(basename4(String(projectPath || "")).trim().toLowerCase());
|
|
21232
21406
|
return `(function(){
|
|
21233
21407
|
${WORKSPACE_SECTION_BODY}
|
|
21234
21408
|
const wanted=${workspaceLabel};
|
|
@@ -21244,7 +21418,7 @@ function exprCreateAgentForWorkspace(projectPath) {
|
|
|
21244
21418
|
})()`;
|
|
21245
21419
|
}
|
|
21246
21420
|
function exprInspectWorkspaceRepository(projectPath) {
|
|
21247
|
-
const workspaceLabel = JSON.stringify(
|
|
21421
|
+
const workspaceLabel = JSON.stringify(basename4(String(projectPath || "")).trim().toLowerCase());
|
|
21248
21422
|
return `(function(){
|
|
21249
21423
|
${WORKSPACE_SECTION_BODY}
|
|
21250
21424
|
const wanted=${workspaceLabel};
|
|
@@ -21314,6 +21488,8 @@ var REACT_ADAPTER_BODY = `
|
|
|
21314
21488
|
};
|
|
21315
21489
|
const findV2Props=()=>{
|
|
21316
21490
|
const found=[]; const seen=new Set();
|
|
21491
|
+
let globalSelectAgent=null;
|
|
21492
|
+
let sectionIdByAgentId=null;
|
|
21317
21493
|
for(const root of document.querySelectorAll('.glass-sidebar-agent-list-container')){
|
|
21318
21494
|
const nodes=[]; let n=root;
|
|
21319
21495
|
for(let i=0;n&&i<24;i++,n=n.parentElement)nodes.push(n);
|
|
@@ -21324,6 +21500,8 @@ var REACT_ADAPTER_BODY = `
|
|
|
21324
21500
|
let f=key.startsWith('__reactFiber$')?seed:{memoizedProps:seed,return:null};
|
|
21325
21501
|
for(let j=0;f&&j<80;j++,f=f.return){
|
|
21326
21502
|
for(const p of [f.memoizedProps,f.pendingProps,f.stateNode&&f.stateNode.props]){
|
|
21503
|
+
if(p&&typeof p.onSelectAgent==='function'&&!globalSelectAgent)globalSelectAgent=p.onSelectAgent;
|
|
21504
|
+
if(p&&p.sectionIdByAgentId&&!sectionIdByAgentId)sectionIdByAgentId=p.sectionIdByAgentId;
|
|
21327
21505
|
const selectAgent=p&&(typeof p.onSelectAgent==='function'
|
|
21328
21506
|
?p.onSelectAgent
|
|
21329
21507
|
:(p.rowHandlers&&typeof p.rowHandlers.onSelect==='function'?p.rowHandlers.onSelect:null));
|
|
@@ -21339,6 +21517,8 @@ var REACT_ADAPTER_BODY = `
|
|
|
21339
21517
|
}
|
|
21340
21518
|
}
|
|
21341
21519
|
}
|
|
21520
|
+
found.globalSelectAgent=globalSelectAgent;
|
|
21521
|
+
found.sectionIdByAgentId=sectionIdByAgentId;
|
|
21342
21522
|
return found;
|
|
21343
21523
|
};
|
|
21344
21524
|
const findAdapter=()=>{
|
|
@@ -21368,10 +21548,28 @@ var REACT_ADAPTER_BODY = `
|
|
|
21368
21548
|
else if(/needs_attention/.test(status))icon='needs-attention';
|
|
21369
21549
|
else if(/failed|error/.test(status))icon='warning';
|
|
21370
21550
|
else if(/cancel/.test(status))icon='circle-slash';
|
|
21551
|
+
seen.add(selectedId);
|
|
21371
21552
|
entries.push({
|
|
21372
21553
|
id:selectedId,label:'',searchText:'',timestamp:0,isSelected:true,
|
|
21373
21554
|
showSpinner:/in_progress|running|generating/.test(status),icon,
|
|
21374
|
-
workspaceId:''
|
|
21555
|
+
workspaceId:String(v2.sectionIdByAgentId instanceof Map?v2.sectionIdByAgentId.get(selectedRaw)||'':v2.sectionIdByAgentId&&readScalar(v2.sectionIdByAgentId[selectedRaw])||''),
|
|
21556
|
+
workspaceLabel:'',durable:!!(v2.sectionIdByAgentId&&(v2.sectionIdByAgentId instanceof Map?v2.sectionIdByAgentId.has(selectedRaw):v2.sectionIdByAgentId[selectedRaw]!==undefined)),
|
|
21557
|
+
registeredBySectionMap:true
|
|
21558
|
+
});
|
|
21559
|
+
}
|
|
21560
|
+
}
|
|
21561
|
+
if(v2.sectionIdByAgentId){
|
|
21562
|
+
const registered=v2.sectionIdByAgentId instanceof Map?[...v2.sectionIdByAgentId.entries()]:Object.entries(v2.sectionIdByAgentId);
|
|
21563
|
+
for(const pair of registered){
|
|
21564
|
+
const raw=String(pair&&pair[0]||'').replace(/^local:/,'');
|
|
21565
|
+
if(!raw)continue;
|
|
21566
|
+
const id='local:'+raw;
|
|
21567
|
+
if(seen.has(id))continue;
|
|
21568
|
+
seen.add(id);
|
|
21569
|
+
entries.push({
|
|
21570
|
+
id,label:'',searchText:'',timestamp:0,isSelected:id===selectedId,
|
|
21571
|
+
showSpinner:false,icon:'registered',workspaceId:String(readScalar(pair[1])||''),workspaceLabel:'',
|
|
21572
|
+
durable:true,registeredBySectionMap:true
|
|
21375
21573
|
});
|
|
21376
21574
|
}
|
|
21377
21575
|
}
|
|
@@ -21384,6 +21582,8 @@ var REACT_ADAPTER_BODY = `
|
|
|
21384
21582
|
const header=p.section.headers.find(h=>String(readScalar(h&&h.id)||'')===raw);
|
|
21385
21583
|
if(header){p.onSelectAgent(header);return true;}
|
|
21386
21584
|
}
|
|
21585
|
+
const registered=v2.sectionIdByAgentId&&(v2.sectionIdByAgentId instanceof Map?v2.sectionIdByAgentId.has(raw):v2.sectionIdByAgentId[raw]!==undefined);
|
|
21586
|
+
if(registered&&typeof v2.globalSelectAgent==='function'){v2.globalSelectAgent(raw);return true;}
|
|
21387
21587
|
return false;
|
|
21388
21588
|
}
|
|
21389
21589
|
};
|
|
@@ -21481,6 +21681,13 @@ function classifyParallelTerminalIcon(icon) {
|
|
|
21481
21681
|
function isDurablyRegisteredParallelEntry(entry) {
|
|
21482
21682
|
return !!entry && entry.durable !== false && (entry.showSpinner || classifyParallelTerminalIcon(entry.icon) !== "unknown");
|
|
21483
21683
|
}
|
|
21684
|
+
function selectPromotedFifoEntry(beforeEntries, currentAgentId, afterEntries) {
|
|
21685
|
+
if (!Array.isArray(beforeEntries) || !Array.isArray(afterEntries)) return null;
|
|
21686
|
+
if (currentAgentId && afterEntries.some((entry) => entry && entry.id === currentAgentId)) return null;
|
|
21687
|
+
const candidate = selectNewAgentEntry(beforeEntries, afterEntries);
|
|
21688
|
+
if (!candidate || candidate.id === currentAgentId || candidate.isSelected !== true) return null;
|
|
21689
|
+
return isDurablyRegisteredParallelEntry(candidate) ? candidate : null;
|
|
21690
|
+
}
|
|
21484
21691
|
function uncertainSubmissionReservationScope(job, error2) {
|
|
21485
21692
|
if (error2 && error2.requiresGlobalReservation) return "global";
|
|
21486
21693
|
return job && job.readOnly ? "agent" : "paths";
|
|
@@ -21527,10 +21734,10 @@ function releaseAdapterWorkingDirectory({ targetDir = defaultLifecycleDir(), chd
|
|
|
21527
21734
|
}
|
|
21528
21735
|
var CursorBridge = class {
|
|
21529
21736
|
constructor(options = {}) {
|
|
21530
|
-
this.adapterStartCwd =
|
|
21737
|
+
this.adapterStartCwd = resolve6(options.adapterStartCwd || process.cwd());
|
|
21531
21738
|
this.environmentDelegationMode = normalizeDelegationMode(options.delegationMode || DELEGATION_MODE);
|
|
21532
21739
|
this._syncDelegationState();
|
|
21533
|
-
this.runtimeFile = options.runtimeFile === null ? null :
|
|
21740
|
+
this.runtimeFile = options.runtimeFile === null ? null : resolve6(options.runtimeFile || resolveCursorRuntimeFile());
|
|
21534
21741
|
this.runtimeModeDefault = normalizeCursorRuntimeMode(
|
|
21535
21742
|
options.runtimeModeDefault || process.env.CURSOR_BRIDGE_RUNTIME_MODE,
|
|
21536
21743
|
"normal"
|
|
@@ -21541,12 +21748,14 @@ var CursorBridge = class {
|
|
|
21541
21748
|
this.runtimeMode = normalizeCursorRuntimeMode(requestedRuntimeMode);
|
|
21542
21749
|
this.runtimeModeSource = options.runtimeMode !== void 0 ? "constructor" : persistedRuntimeMode ? "persistent" : process.env.CURSOR_BRIDGE_RUNTIME_MODE ? "environment" : "default";
|
|
21543
21750
|
this.runtimeModeScope = persistedRuntimeMode ? "persistent" : options.runtimeMode !== void 0 ? "constructor" : process.env.CURSOR_BRIDGE_RUNTIME_MODE ? "environment" : "default";
|
|
21544
|
-
this.workspaceFile = options.workspaceFile === null ? null :
|
|
21751
|
+
this.workspaceFile = options.workspaceFile === null ? null : resolve6(options.workspaceFile || resolveWorkspaceBindingFile());
|
|
21545
21752
|
this.workspaceKey = options.workspaceKey || resolveWorkspaceBindingKey();
|
|
21546
21753
|
const persistedWorkspace = options.projectPath === void 0 ? readWorkspaceBinding(this.workspaceFile, this.workspaceKey) : null;
|
|
21547
|
-
this.projectPath = options.projectPath !== void 0 ?
|
|
21754
|
+
this.projectPath = options.projectPath !== void 0 ? resolve6(String(options.projectPath)) : persistedWorkspace && persistedWorkspace.projectPath || null;
|
|
21548
21755
|
this.workspaceSource = options.projectPath !== void 0 ? "constructor" : persistedWorkspace ? "persistent_init" : "auto_detect";
|
|
21549
21756
|
this.workspaceUpdatedAt = persistedWorkspace && persistedWorkspace.updatedAt || null;
|
|
21757
|
+
this.modelPreferencesFile = options.modelPreferencesFile === null ? null : resolve6(options.modelPreferencesFile || resolveCursorModelPreferencesFile());
|
|
21758
|
+
this.modelPreferences = readCursorModelPreferences(this.modelPreferencesFile);
|
|
21550
21759
|
this._lastPresentation = null;
|
|
21551
21760
|
this.busy = false;
|
|
21552
21761
|
this.queue = [];
|
|
@@ -21654,6 +21863,36 @@ var CursorBridge = class {
|
|
|
21654
21863
|
environmentLockedOff: this.environmentDelegationMode === "off"
|
|
21655
21864
|
};
|
|
21656
21865
|
}
|
|
21866
|
+
_refreshModelPreferences() {
|
|
21867
|
+
if (!this.modelPreferencesFile) return false;
|
|
21868
|
+
const next = readCursorModelPreferences(this.modelPreferencesFile);
|
|
21869
|
+
const changed = JSON.stringify(next) !== JSON.stringify(this.modelPreferences);
|
|
21870
|
+
this.modelPreferences = next;
|
|
21871
|
+
return changed;
|
|
21872
|
+
}
|
|
21873
|
+
modelPreferencesView() {
|
|
21874
|
+
this._refreshModelPreferences();
|
|
21875
|
+
return {
|
|
21876
|
+
modelPreferencesFile: this.modelPreferencesFile,
|
|
21877
|
+
modelPreferencesPersistAcrossRestart: !!this.modelPreferencesFile,
|
|
21878
|
+
modelPreferenceTargets: [...CURSOR_MODEL_TARGETS],
|
|
21879
|
+
availableEfforts: [...CURSOR_MODEL_EFFORTS],
|
|
21880
|
+
modelPreferences: {
|
|
21881
|
+
cce: this.modelPreferences.targets.cce,
|
|
21882
|
+
cursor_do: this.modelPreferences.targets.cursor_do
|
|
21883
|
+
},
|
|
21884
|
+
modelPreferencesUpdatedAt: this.modelPreferences.updatedAt
|
|
21885
|
+
};
|
|
21886
|
+
}
|
|
21887
|
+
configureModelPreferences(options = {}) {
|
|
21888
|
+
this.modelPreferences = updateCursorModelPreferences(this.modelPreferencesFile, options);
|
|
21889
|
+
return this.modelPreferencesView();
|
|
21890
|
+
}
|
|
21891
|
+
_modelPreferenceFor(target) {
|
|
21892
|
+
this._refreshModelPreferences();
|
|
21893
|
+
const preference = this.modelPreferences.targets[target];
|
|
21894
|
+
return preference ? { ...preference } : null;
|
|
21895
|
+
}
|
|
21657
21896
|
_refreshPersistedRuntimeMode() {
|
|
21658
21897
|
if (!this.runtimeFile || this.runtimeModeScope === "session" || this.runtimeModeScope === "constructor") {
|
|
21659
21898
|
return false;
|
|
@@ -21750,7 +21989,8 @@ var CursorBridge = class {
|
|
|
21750
21989
|
newChat: true,
|
|
21751
21990
|
execution: "fifo",
|
|
21752
21991
|
readOnly: true,
|
|
21753
|
-
allowedPaths: []
|
|
21992
|
+
allowedPaths: [],
|
|
21993
|
+
modelPreference: this._modelPreferenceFor("cce")
|
|
21754
21994
|
});
|
|
21755
21995
|
return normalizeCceSearchResult(await job.promise);
|
|
21756
21996
|
}
|
|
@@ -21802,7 +22042,8 @@ var CursorBridge = class {
|
|
|
21802
22042
|
execution,
|
|
21803
22043
|
readOnly,
|
|
21804
22044
|
allowedPaths,
|
|
21805
|
-
preferLegacyUi: options.preferLegacyUi === true
|
|
22045
|
+
preferLegacyUi: options.preferLegacyUi === true,
|
|
22046
|
+
modelPreference: this._modelPreferenceFor("cursor_do")
|
|
21806
22047
|
});
|
|
21807
22048
|
if (options.background !== false) return this._taskView(job);
|
|
21808
22049
|
await job.promise;
|
|
@@ -21835,8 +22076,8 @@ var CursorBridge = class {
|
|
|
21835
22076
|
const id = `cursor-${Date.now().toString(36)}-${this.nextTaskId++}`;
|
|
21836
22077
|
let resolvePromise;
|
|
21837
22078
|
let rejectPromise;
|
|
21838
|
-
const promise = new Promise((
|
|
21839
|
-
resolvePromise =
|
|
22079
|
+
const promise = new Promise((resolve7, reject) => {
|
|
22080
|
+
resolvePromise = resolve7;
|
|
21840
22081
|
rejectPromise = reject;
|
|
21841
22082
|
});
|
|
21842
22083
|
promise.catch(() => {
|
|
@@ -21852,6 +22093,8 @@ var CursorBridge = class {
|
|
|
21852
22093
|
effectiveExecution: options.execution || "fifo",
|
|
21853
22094
|
readOnly: options.readOnly === true,
|
|
21854
22095
|
allowedPaths: options.allowedPaths || [],
|
|
22096
|
+
modelPreference: options.modelPreference ? { ...options.modelPreference } : null,
|
|
22097
|
+
modelSelection: options.modelPreference ? { configured: true, applied: false, ...options.modelPreference } : null,
|
|
21855
22098
|
projectPath: options.projectPath || this._lastLifecycle && this._lastLifecycle.projectPath || this.projectPath || null,
|
|
21856
22099
|
status: "queued",
|
|
21857
22100
|
phase: "queued",
|
|
@@ -22202,6 +22445,8 @@ var CursorBridge = class {
|
|
|
22202
22445
|
await this._bindFifoAgentAfterComposerReady(c, options, historyBefore);
|
|
22203
22446
|
await this._bindFifoComposerIdentity(c, options);
|
|
22204
22447
|
this._throwIfCancelledBeforeSend(options);
|
|
22448
|
+
await this._applyModelPreference(c, options.modelPreference, options);
|
|
22449
|
+
this._throwIfCancelledBeforeSend(options);
|
|
22205
22450
|
const filled = await evalJS(c, exprFill(prompt));
|
|
22206
22451
|
if (filled === "NO_INPUT" || filled === "EXEC_FAIL") throw new Error("Failed to enter the query because the input state was invalid");
|
|
22207
22452
|
await sleep2(450);
|
|
@@ -22218,10 +22463,8 @@ var CursorBridge = class {
|
|
|
22218
22463
|
await this._confirmSubmission(c, baseline.messageCount || 0, providerErrorBaseline);
|
|
22219
22464
|
options.sendState = "sent";
|
|
22220
22465
|
options.sentAt = options.sentAt || (/* @__PURE__ */ new Date()).toISOString();
|
|
22221
|
-
|
|
22222
|
-
|
|
22223
|
-
await this._bindFifoComposerIdentity(c, options);
|
|
22224
|
-
}
|
|
22466
|
+
await this._bindFifoAgentAfterSend(c, options, historyBefore, providerErrorBaseline);
|
|
22467
|
+
await this._bindFifoComposerIdentity(c, options);
|
|
22225
22468
|
return await this._waitComplete(
|
|
22226
22469
|
c,
|
|
22227
22470
|
options.timeoutMs || QUERY_TIMEOUT,
|
|
@@ -22250,6 +22493,176 @@ var CursorBridge = class {
|
|
|
22250
22493
|
error2.preSend = true;
|
|
22251
22494
|
throw error2;
|
|
22252
22495
|
}
|
|
22496
|
+
async _readModelPickerTrigger(c) {
|
|
22497
|
+
try {
|
|
22498
|
+
return JSON.parse(await evalJS(c, EXPR_MODEL_PICKER_TRIGGER) || "{}");
|
|
22499
|
+
} catch {
|
|
22500
|
+
return { found: false, state: "trigger_unreadable" };
|
|
22501
|
+
}
|
|
22502
|
+
}
|
|
22503
|
+
async _readModelPickerRows(c) {
|
|
22504
|
+
try {
|
|
22505
|
+
const snapshot = JSON.parse(await evalJS(c, EXPR_MODEL_PICKER_ROWS) || "{}");
|
|
22506
|
+
return { open: snapshot.open === true, rows: Array.isArray(snapshot.rows) ? snapshot.rows : [] };
|
|
22507
|
+
} catch {
|
|
22508
|
+
return { open: false, rows: [] };
|
|
22509
|
+
}
|
|
22510
|
+
}
|
|
22511
|
+
async _clickModelPickerPoint(c, point) {
|
|
22512
|
+
if (!point || !Number.isFinite(Number(point.x)) || !Number.isFinite(Number(point.y))) {
|
|
22513
|
+
throw new Error("Cursor model picker returned an invalid target");
|
|
22514
|
+
}
|
|
22515
|
+
const x = Number(point.x);
|
|
22516
|
+
const y = Number(point.y);
|
|
22517
|
+
await c.send("Input.dispatchMouseEvent", { type: "mousePressed", x, y, button: "left", clickCount: 1 });
|
|
22518
|
+
await c.send("Input.dispatchMouseEvent", { type: "mouseReleased", x, y, button: "left", clickCount: 1 });
|
|
22519
|
+
}
|
|
22520
|
+
async _hoverModelPickerPoint(c, point) {
|
|
22521
|
+
if (!point || !Number.isFinite(Number(point.x)) || !Number.isFinite(Number(point.y))) return;
|
|
22522
|
+
await c.send("Input.dispatchMouseEvent", { type: "mouseMoved", x: Number(point.x), y: Number(point.y) });
|
|
22523
|
+
}
|
|
22524
|
+
async _openModelPicker(c) {
|
|
22525
|
+
const trigger = await this._readModelPickerTrigger(c);
|
|
22526
|
+
if (!trigger.found) {
|
|
22527
|
+
throw new Error("Cursor model picker is unavailable in the active Agent composer");
|
|
22528
|
+
}
|
|
22529
|
+
let snapshot = await this._readModelPickerRows(c);
|
|
22530
|
+
if (!snapshot.open) {
|
|
22531
|
+
await this._clickModelPickerPoint(c, trigger);
|
|
22532
|
+
await sleep2(450);
|
|
22533
|
+
snapshot = await this._readModelPickerRows(c);
|
|
22534
|
+
}
|
|
22535
|
+
if (!snapshot.open) throw new Error("Cursor model picker did not open");
|
|
22536
|
+
return { trigger, ...snapshot };
|
|
22537
|
+
}
|
|
22538
|
+
async _closeModelPicker(c) {
|
|
22539
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
22540
|
+
const snapshot = await this._readModelPickerRows(c);
|
|
22541
|
+
if (!snapshot.open) return;
|
|
22542
|
+
await c.send("Input.dispatchKeyEvent", { type: "keyDown", key: "Escape", code: "Escape", windowsVirtualKeyCode: 27, nativeVirtualKeyCode: 27 });
|
|
22543
|
+
await c.send("Input.dispatchKeyEvent", { type: "keyUp", key: "Escape", code: "Escape", windowsVirtualKeyCode: 27, nativeVirtualKeyCode: 27 });
|
|
22544
|
+
await sleep2(150);
|
|
22545
|
+
}
|
|
22546
|
+
if ((await this._readModelPickerRows(c)).open) throw new Error("Cursor model picker did not close after selection");
|
|
22547
|
+
}
|
|
22548
|
+
async _openModelPickerControl(c, snapshot, controlKind) {
|
|
22549
|
+
const control = (snapshot && snapshot.rows || []).find((row) => row.kind === controlKind && row.disabled !== true);
|
|
22550
|
+
if (!control) return snapshot;
|
|
22551
|
+
await this._clickModelPickerPoint(c, control);
|
|
22552
|
+
await sleep2(400);
|
|
22553
|
+
let next = await this._readModelPickerRows(c);
|
|
22554
|
+
const expectedKind = controlKind === "model_control" ? "model" : "parameter";
|
|
22555
|
+
if (!next.rows.some((row) => row.kind === expectedKind)) {
|
|
22556
|
+
await this._hoverModelPickerPoint(c, control);
|
|
22557
|
+
await sleep2(350);
|
|
22558
|
+
next = await this._readModelPickerRows(c);
|
|
22559
|
+
}
|
|
22560
|
+
return next;
|
|
22561
|
+
}
|
|
22562
|
+
async _findModelPickerModel(c, snapshot, requestedModel) {
|
|
22563
|
+
let modelRow = selectModelPickerRow(snapshot && snapshot.rows, requestedModel, "model");
|
|
22564
|
+
if (modelRow) return { snapshot, modelRow };
|
|
22565
|
+
const expanded = await this._openModelPickerControl(c, snapshot, "model_control");
|
|
22566
|
+
modelRow = selectModelPickerRow(expanded && expanded.rows, requestedModel, "model");
|
|
22567
|
+
return { snapshot: expanded, modelRow };
|
|
22568
|
+
}
|
|
22569
|
+
async _selectedEffortRow(c, modelRow, effort) {
|
|
22570
|
+
let snapshot = await this._readModelPickerRows(c);
|
|
22571
|
+
let effortRow = selectModelPickerRow(snapshot.rows, cursorEffortUiValue(effort), "parameter");
|
|
22572
|
+
if (!effortRow) {
|
|
22573
|
+
snapshot = await this._openModelPickerControl(c, snapshot, "effort_control");
|
|
22574
|
+
effortRow = selectModelPickerRow(snapshot.rows, cursorEffortUiValue(effort), "parameter");
|
|
22575
|
+
}
|
|
22576
|
+
if (effortRow) return effortRow;
|
|
22577
|
+
await this._hoverModelPickerPoint(c, modelRow);
|
|
22578
|
+
await sleep2(400);
|
|
22579
|
+
snapshot = await this._readModelPickerRows(c);
|
|
22580
|
+
effortRow = selectModelPickerRow(snapshot.rows, cursorEffortUiValue(effort), "parameter");
|
|
22581
|
+
if (!effortRow && modelRow && modelRow.hasSubmenu) {
|
|
22582
|
+
await this._clickModelPickerPoint(c, modelRow);
|
|
22583
|
+
await sleep2(350);
|
|
22584
|
+
snapshot = await this._readModelPickerRows(c);
|
|
22585
|
+
effortRow = selectModelPickerRow(snapshot.rows, cursorEffortUiValue(effort), "parameter");
|
|
22586
|
+
}
|
|
22587
|
+
return effortRow;
|
|
22588
|
+
}
|
|
22589
|
+
async _applyModelPreference(c, preference, job) {
|
|
22590
|
+
if (!preference) {
|
|
22591
|
+
if (job) job.modelSelection = null;
|
|
22592
|
+
return null;
|
|
22593
|
+
}
|
|
22594
|
+
const requestedModel = String(preference.model || "").trim();
|
|
22595
|
+
const requestedEffort = preference.effort ? normalizeCursorModelEffort(preference.effort, "") : null;
|
|
22596
|
+
const opened = await this._openModelPicker(c);
|
|
22597
|
+
let located = await this._findModelPickerModel(c, opened, requestedModel);
|
|
22598
|
+
let modelRow = located.modelRow;
|
|
22599
|
+
if (!modelRow) {
|
|
22600
|
+
throw new Error(`Configured Cursor model is unavailable or ambiguous: ${requestedModel}`);
|
|
22601
|
+
}
|
|
22602
|
+
let selectedEffortRow = null;
|
|
22603
|
+
if (requestedEffort && modelRow.hasSubmenu) {
|
|
22604
|
+
selectedEffortRow = await this._selectedEffortRow(c, modelRow, requestedEffort);
|
|
22605
|
+
if (!selectedEffortRow) {
|
|
22606
|
+
throw new Error(`Cursor model ${requestedModel} does not expose effort ${requestedEffort}`);
|
|
22607
|
+
}
|
|
22608
|
+
if (!selectedEffortRow.selected || !modelRow.selected) {
|
|
22609
|
+
await this._clickModelPickerPoint(c, selectedEffortRow);
|
|
22610
|
+
await sleep2(550);
|
|
22611
|
+
}
|
|
22612
|
+
} else if (!modelRow.selected) {
|
|
22613
|
+
await this._clickModelPickerPoint(c, modelRow);
|
|
22614
|
+
await sleep2(550);
|
|
22615
|
+
}
|
|
22616
|
+
let trigger = await this._readModelPickerTrigger(c);
|
|
22617
|
+
if (!trigger.found || !normalizeModelPickerText(trigger.text).includes(normalizeModelPickerText(requestedModel))) {
|
|
22618
|
+
const reopened = await this._openModelPicker(c);
|
|
22619
|
+
located = await this._findModelPickerModel(c, reopened, requestedModel);
|
|
22620
|
+
const selected = selectModelPickerRow(located.snapshot.rows.filter((row) => row.selected), requestedModel, "model");
|
|
22621
|
+
if (!selected) throw new Error(`Cursor did not confirm configured model ${requestedModel}`);
|
|
22622
|
+
modelRow = selected;
|
|
22623
|
+
}
|
|
22624
|
+
let effectiveEffort = null;
|
|
22625
|
+
if (requestedEffort) {
|
|
22626
|
+
const reopened = await this._openModelPicker(c);
|
|
22627
|
+
located = await this._findModelPickerModel(c, reopened, requestedModel);
|
|
22628
|
+
modelRow = located.modelRow;
|
|
22629
|
+
if (!modelRow) throw new Error(`Cursor model row disappeared while applying effort: ${requestedModel}`);
|
|
22630
|
+
let effortRow = await this._selectedEffortRow(c, modelRow, requestedEffort);
|
|
22631
|
+
if (!effortRow) {
|
|
22632
|
+
throw new Error(`Cursor model ${requestedModel} does not expose effort ${requestedEffort}`);
|
|
22633
|
+
}
|
|
22634
|
+
if (!effortRow.selected) {
|
|
22635
|
+
await this._clickModelPickerPoint(c, effortRow);
|
|
22636
|
+
await sleep2(450);
|
|
22637
|
+
}
|
|
22638
|
+
trigger = await this._readModelPickerTrigger(c);
|
|
22639
|
+
const detailMatches = normalizeModelPickerText(`${trigger.detail || ""} ${trigger.text || ""}`).includes(normalizeModelPickerText(requestedEffort));
|
|
22640
|
+
if (!detailMatches) {
|
|
22641
|
+
const verify = await this._openModelPicker(c);
|
|
22642
|
+
const verifiedModel = await this._findModelPickerModel(c, verify, requestedModel);
|
|
22643
|
+
const selectedModel = verifiedModel.modelRow;
|
|
22644
|
+
effortRow = await this._selectedEffortRow(c, selectedModel, requestedEffort);
|
|
22645
|
+
if (!effortRow || !effortRow.selected) {
|
|
22646
|
+
throw new Error(`Cursor did not confirm effort ${requestedEffort} for model ${requestedModel}`);
|
|
22647
|
+
}
|
|
22648
|
+
}
|
|
22649
|
+
effectiveEffort = requestedEffort;
|
|
22650
|
+
}
|
|
22651
|
+
await this._closeModelPicker(c);
|
|
22652
|
+
trigger = await this._readModelPickerTrigger(c);
|
|
22653
|
+
const result = {
|
|
22654
|
+
configured: true,
|
|
22655
|
+
applied: true,
|
|
22656
|
+
requestedModel,
|
|
22657
|
+
requestedEffort,
|
|
22658
|
+
effectiveModel: trigger.text || modelRow.text,
|
|
22659
|
+
effectiveEffort,
|
|
22660
|
+
pickerDetail: trigger.detail || null,
|
|
22661
|
+
verifiedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
22662
|
+
};
|
|
22663
|
+
if (job) job.modelSelection = result;
|
|
22664
|
+
return result;
|
|
22665
|
+
}
|
|
22253
22666
|
async _ensureChatPanel(c) {
|
|
22254
22667
|
let vis = await evalJS(c, EXPR_VISIBLE);
|
|
22255
22668
|
if (!vis) {
|
|
@@ -22272,7 +22685,7 @@ var CursorBridge = class {
|
|
|
22272
22685
|
const created = JSON.parse(await evalJS(c, exprCreateAgentForWorkspace(options.projectPath)) || "{}");
|
|
22273
22686
|
if (!created.ok) {
|
|
22274
22687
|
const available = Array.isArray(created.available) ? `; available=${created.available.join(", ")}` : "";
|
|
22275
|
-
throw new Error(`Cursor Agents workspace binding failed: ${created.state || "unknown"}; wanted=${created.wanted ||
|
|
22688
|
+
throw new Error(`Cursor Agents workspace binding failed: ${created.state || "unknown"}; wanted=${created.wanted || basename4(options.projectPath)}${available}`);
|
|
22276
22689
|
}
|
|
22277
22690
|
await sleep2(1100);
|
|
22278
22691
|
return true;
|
|
@@ -22383,12 +22796,31 @@ var CursorBridge = class {
|
|
|
22383
22796
|
}
|
|
22384
22797
|
}
|
|
22385
22798
|
async _bindFifoAgentAfterSend(c, job, beforeEntries, providerErrorBaseline) {
|
|
22386
|
-
if (!this._canBindFifoHistory(job) || !Array.isArray(beforeEntries)
|
|
22387
|
-
for (let i = 0; i < 24
|
|
22799
|
+
if (!this._canBindFifoHistory(job) || !Array.isArray(beforeEntries)) return;
|
|
22800
|
+
for (let i = 0; i < 24; i++) {
|
|
22388
22801
|
await sleep2(350);
|
|
22389
22802
|
await this._throwIfNewProviderError(c, providerErrorBaseline);
|
|
22390
|
-
|
|
22391
|
-
|
|
22803
|
+
let entries = null;
|
|
22804
|
+
try {
|
|
22805
|
+
entries = await this._readAgentEntries(c);
|
|
22806
|
+
} catch {
|
|
22807
|
+
}
|
|
22808
|
+
if (!Array.isArray(entries)) continue;
|
|
22809
|
+
const promoted = selectPromotedFifoEntry(beforeEntries, job.agentId, entries);
|
|
22810
|
+
if (promoted) {
|
|
22811
|
+
job.provisionalAgentId = job.agentId || null;
|
|
22812
|
+
this._applyAgentIdentity(job, promoted);
|
|
22813
|
+
return;
|
|
22814
|
+
}
|
|
22815
|
+
const current = job.agentId ? entries.find((entry) => entry && entry.id === job.agentId) : null;
|
|
22816
|
+
if (current && isDurablyRegisteredParallelEntry(current)) return;
|
|
22817
|
+
if (!job.agentId) {
|
|
22818
|
+
const candidate = selectNewAgentEntry(beforeEntries, entries);
|
|
22819
|
+
if (candidate && isDurablyRegisteredParallelEntry(candidate)) {
|
|
22820
|
+
this._applyAgentIdentity(job, candidate);
|
|
22821
|
+
return;
|
|
22822
|
+
}
|
|
22823
|
+
}
|
|
22392
22824
|
}
|
|
22393
22825
|
}
|
|
22394
22826
|
async _confirmSubmission(c, baselineCount = 0, providerErrorBaseline = "") {
|
|
@@ -22481,6 +22913,8 @@ var CursorBridge = class {
|
|
|
22481
22913
|
await this._closeHistory(c);
|
|
22482
22914
|
await this._ensureChatPanel(c);
|
|
22483
22915
|
this._throwIfCancelledBeforeSend(job);
|
|
22916
|
+
await this._applyModelPreference(c, job.modelPreference, job);
|
|
22917
|
+
this._throwIfCancelledBeforeSend(job);
|
|
22484
22918
|
const filled = await evalJS(c, exprFill(job.prompt));
|
|
22485
22919
|
if (filled === "NO_INPUT" || filled === "EXEC_FAIL") throw new Error("Failed to enter the parallel_agent task");
|
|
22486
22920
|
await sleep2(350);
|
|
@@ -22537,8 +22971,25 @@ var CursorBridge = class {
|
|
|
22537
22971
|
const c = makeClient(page.webSocketDebuggerUrl);
|
|
22538
22972
|
await c.ready;
|
|
22539
22973
|
try {
|
|
22540
|
-
|
|
22541
|
-
|
|
22974
|
+
let entries = await this._readAgentEntries(c);
|
|
22975
|
+
let entry = entries.find((e) => e.id === job.agentId) || null;
|
|
22976
|
+
if (!entry && (job.execution === "fifo" || job.effectiveExecution === "fifo")) {
|
|
22977
|
+
const promoted = selectPromotedFifoEntry(job.historyBeforeEntries, job.agentId, entries);
|
|
22978
|
+
if (promoted) {
|
|
22979
|
+
job.provisionalAgentId = job.agentId || null;
|
|
22980
|
+
this._applyAgentIdentity(job, promoted);
|
|
22981
|
+
entry = promoted;
|
|
22982
|
+
}
|
|
22983
|
+
}
|
|
22984
|
+
if (entry && entry.registeredBySectionMap && classifyParallelTerminalIcon(entry.icon) === "unknown") {
|
|
22985
|
+
const opened = await evalJS(c, exprOpenAgent(job.agentId));
|
|
22986
|
+
if (opened === "OPENED") {
|
|
22987
|
+
await sleep2(350);
|
|
22988
|
+
entries = await this._readAgentEntries(c);
|
|
22989
|
+
entry = entries.find((e) => e.id === job.agentId) || entry;
|
|
22990
|
+
}
|
|
22991
|
+
}
|
|
22992
|
+
return entry;
|
|
22542
22993
|
} finally {
|
|
22543
22994
|
c.close();
|
|
22544
22995
|
}
|
|
@@ -23287,8 +23738,11 @@ var CursorBridge = class {
|
|
|
23287
23738
|
effectiveExecution: job.effectiveExecution,
|
|
23288
23739
|
readOnly: job.readOnly,
|
|
23289
23740
|
allowedPaths: job.allowedPaths,
|
|
23741
|
+
modelPreference: job.modelPreference,
|
|
23742
|
+
modelSelection: job.modelSelection,
|
|
23290
23743
|
projectPath: job.projectPath,
|
|
23291
23744
|
agentId: job.agentId,
|
|
23745
|
+
provisionalAgentId: job.provisionalAgentId || null,
|
|
23292
23746
|
agentLabel: job.agentLabel,
|
|
23293
23747
|
targetId: job.targetId,
|
|
23294
23748
|
targetUiFlavor: job.targetUiFlavor,
|
|
@@ -23335,8 +23789,8 @@ var CursorBridge = class {
|
|
|
23335
23789
|
async status(taskId = "") {
|
|
23336
23790
|
if (taskId) {
|
|
23337
23791
|
const job = this.tasks.get(String(taskId));
|
|
23338
|
-
if (!job) return { found: false, taskId: String(taskId), ...this.workspaceView(), ...this.delegationView(), ...this.runtimeModeView() };
|
|
23339
|
-
return { found: true, ...this.workspaceView(), ...this.delegationView(), ...this.runtimeModeView(), ...this._taskView(job, true) };
|
|
23792
|
+
if (!job) return { found: false, taskId: String(taskId), ...this.workspaceView(), ...this.delegationView(), ...this.runtimeModeView(), ...this.modelPreferencesView() };
|
|
23793
|
+
return { found: true, ...this.workspaceView(), ...this.delegationView(), ...this.runtimeModeView(), ...this.modelPreferencesView(), ...this._taskView(job, true) };
|
|
23340
23794
|
}
|
|
23341
23795
|
const parallelRunning = this.activeParallel.size;
|
|
23342
23796
|
const uiBusy = this.busy;
|
|
@@ -23347,6 +23801,7 @@ var CursorBridge = class {
|
|
|
23347
23801
|
...this.workspaceView(),
|
|
23348
23802
|
...this.delegationView(),
|
|
23349
23803
|
...this.runtimeModeView(),
|
|
23804
|
+
...this.modelPreferencesView(),
|
|
23350
23805
|
busy: uiBusy || parallelRunning > 0 || this.queue.length > 0,
|
|
23351
23806
|
uiBusy,
|
|
23352
23807
|
parallelRunning,
|
|
@@ -23451,9 +23906,23 @@ function buildToolDefinitions(bridgeInstance) {
|
|
|
23451
23906
|
required: ["mode"]
|
|
23452
23907
|
}
|
|
23453
23908
|
},
|
|
23909
|
+
{
|
|
23910
|
+
name: "cursor_model",
|
|
23911
|
+
description: "Show, set, or reset persistent Cursor model defaults for CCE and cursor_do. Settings are independent per target and survive host tasks, MCP restarts, and Cursor Bridge restarts until the user explicitly changes or resets them. When configured, Bridge applies the model and optional effort in every newly created Cursor Agent before sending the prompt, then verifies the visible selection. An unavailable, ambiguous, unsupported, or unconfirmed selection fails before prompt submission instead of silently falling back to Auto. Use set/reset only when the user explicitly asks to change these defaults; use show for read-only inspection.",
|
|
23912
|
+
inputSchema: {
|
|
23913
|
+
type: "object",
|
|
23914
|
+
properties: {
|
|
23915
|
+
action: { type: "string", enum: ["show", "set", "reset"], description: "show reads current defaults; set persists a model and optional effort; reset restores Cursor default selection for the target." },
|
|
23916
|
+
target: { type: "string", enum: ["cce", "cursor_do", "both"], description: "Required for set/reset. CCE and cursor_do keep independent defaults; both changes both targets together." },
|
|
23917
|
+
model: { type: "string", description: "Required for set. Use a model ID or display name currently available in the signed-in Cursor account." },
|
|
23918
|
+
effort: { type: "string", enum: [...CURSOR_MODEL_EFFORTS], description: "Optional reasoning effort for set. Omit it to use that model's Cursor default." }
|
|
23919
|
+
},
|
|
23920
|
+
required: ["action"]
|
|
23921
|
+
}
|
|
23922
|
+
},
|
|
23454
23923
|
{
|
|
23455
23924
|
name: "cursor_status",
|
|
23456
|
-
description: "Read-only snapshot of Cursor connectivity, queued/running work, reservations, execution availability, and normal/minimal runtime presentation. Pass a task ID to read its
|
|
23925
|
+
description: "Read-only snapshot of Cursor connectivity, queued/running work, reservations, execution availability, persistent model/effort defaults, and normal/minimal runtime presentation. Pass a task ID to read its configured and effective model selection plus any result already collected; this tool never switches Agents, reconciles, or stops work.",
|
|
23457
23926
|
inputSchema: { type: "object", properties: { task_id: { type: "string", description: "A task ID returned by cursor_do. Omit it for an overall status view." } } }
|
|
23458
23927
|
}
|
|
23459
23928
|
].filter(Boolean);
|
|
@@ -23461,7 +23930,7 @@ function buildToolDefinitions(bridgeInstance) {
|
|
|
23461
23930
|
var ADAPTER_START_CWD = process.cwd();
|
|
23462
23931
|
var bridge = new CursorBridge({ adapterStartCwd: ADAPTER_START_CWD });
|
|
23463
23932
|
var server = new Server(
|
|
23464
|
-
{ name: "cursor-bridge", version: "5.
|
|
23933
|
+
{ name: "cursor-bridge", version: "5.6.0" },
|
|
23465
23934
|
{ capabilities: { tools: { listChanged: true } } }
|
|
23466
23935
|
);
|
|
23467
23936
|
async function ensureBridgeCursor(targetBridge, reason) {
|
|
@@ -23550,6 +24019,15 @@ server.setRequestHandler(CallToolRequestSchema, async (request2) => {
|
|
|
23550
24019
|
}
|
|
23551
24020
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
23552
24021
|
}
|
|
24022
|
+
if (name === "cursor_model") {
|
|
24023
|
+
const result = bridge.configureModelPreferences({
|
|
24024
|
+
action: args && args.action,
|
|
24025
|
+
target: args && args.target,
|
|
24026
|
+
model: args && args.model,
|
|
24027
|
+
effort: args && args.effort
|
|
24028
|
+
});
|
|
24029
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
24030
|
+
}
|
|
23553
24031
|
if (name === "cursor_status") {
|
|
23554
24032
|
const statusMs = Math.max(1e3, Number(process.env.CURSOR_BRIDGE_STATUS_TIMEOUT || 8e3));
|
|
23555
24033
|
let result;
|
|
@@ -23607,11 +24085,15 @@ if (isMain2) {
|
|
|
23607
24085
|
});
|
|
23608
24086
|
}
|
|
23609
24087
|
export {
|
|
24088
|
+
CURSOR_MODEL_EFFORTS,
|
|
24089
|
+
CURSOR_MODEL_TARGETS,
|
|
23610
24090
|
CURSOR_RUNTIME_MODES,
|
|
23611
24091
|
CursorBridge,
|
|
23612
24092
|
EXPR_CLICK_SEND,
|
|
23613
24093
|
EXPR_FIND_NEWAGENT,
|
|
23614
24094
|
EXPR_HISTORY_ENTRIES,
|
|
24095
|
+
EXPR_MODEL_PICKER_ROWS,
|
|
24096
|
+
EXPR_MODEL_PICKER_TRIGGER,
|
|
23615
24097
|
EXPR_PAGE_CAPABILITIES,
|
|
23616
24098
|
EXPR_PROVIDER_ERROR,
|
|
23617
24099
|
EXPR_VISIBLE,
|
|
@@ -23635,16 +24117,20 @@ export {
|
|
|
23635
24117
|
isTargetedStopConfirmed,
|
|
23636
24118
|
normalizeAllowedPath,
|
|
23637
24119
|
normalizeCceSearchResult,
|
|
24120
|
+
normalizeCursorModelEffort,
|
|
23638
24121
|
normalizeCursorRuntimeMode,
|
|
23639
24122
|
normalizeDelegationMode,
|
|
24123
|
+
normalizeModelPickerText,
|
|
23640
24124
|
pathsOverlap,
|
|
23641
24125
|
promoteAgentsWorkspaceLifecycle,
|
|
23642
24126
|
providerErrorSignature,
|
|
23643
24127
|
releaseAdapterWorkingDirectory,
|
|
23644
24128
|
scoreCursorPageCandidate,
|
|
23645
24129
|
selectCursorPageCandidate,
|
|
24130
|
+
selectModelPickerRow,
|
|
23646
24131
|
selectNewAgentEntry,
|
|
23647
24132
|
selectPageForUiPreference,
|
|
24133
|
+
selectPromotedFifoEntry,
|
|
23648
24134
|
shouldAutoLaunchCursor,
|
|
23649
24135
|
shouldRecoverNormalAgentsPresentation,
|
|
23650
24136
|
summarizeCdpPages,
|