pi-cursor-bridge 0.1.4 → 0.1.6

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.
@@ -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 = resolve6.call(this, root, ref);
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 resolve6(root, ref) {
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 resolve6(baseURI, relativeURI, options) {
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: resolve6,
3909
+ resolve: resolve7,
3910
3910
  resolveComponent,
3911
3911
  equal,
3912
3912
  serialize,
@@ -10786,6 +10786,8 @@ function startMinimalWindowGuard(pid, options = {}) {
10786
10786
  "-EncodedCommand",
10787
10787
  encodePowerShell(script)
10788
10788
  ], { detached: !lifetime, stdio: "ignore", windowsHide: true });
10789
+ if (child && typeof child.once === "function") child.once("error", () => {
10790
+ });
10789
10791
  if (!lifetime && child && typeof child.unref === "function") child.unref();
10790
10792
  return {
10791
10793
  started: true,
@@ -10897,20 +10899,20 @@ public static class CursorBridgeWindowControl {
10897
10899
 
10898
10900
  // lifecycle-paths.mjs
10899
10901
  import { createHash } from "node:crypto";
10900
- import { homedir as homedir2 } from "node:os";
10901
- import { join as join2 } from "node:path";
10902
- import { mkdirSync as mkdirSync2 } from "node:fs";
10902
+ import { homedir as homedir3 } from "node:os";
10903
+ import { join as join3 } from "node:path";
10904
+ import { mkdirSync as mkdirSync3 } from "node:fs";
10903
10905
  function defaultLifecycleDir() {
10904
10906
  if (process.env.CURSOR_BRIDGE_LIFECYCLE_DIR) return process.env.CURSOR_BRIDGE_LIFECYCLE_DIR;
10905
10907
  if (process.platform === "win32") {
10906
- const root2 = process.env.LOCALAPPDATA || join2(homedir2(), "AppData", "Local");
10907
- return join2(root2, "cursor-bridge", "lifecycle");
10908
+ const root2 = process.env.LOCALAPPDATA || join3(homedir3(), "AppData", "Local");
10909
+ return join3(root2, "cursor-bridge", "lifecycle");
10908
10910
  }
10909
- const root = process.env.XDG_RUNTIME_DIR || process.env.XDG_STATE_HOME || join2(homedir2(), ".local", "state");
10910
- return join2(root, "cursor-bridge", "lifecycle");
10911
+ const root = process.env.XDG_RUNTIME_DIR || process.env.XDG_STATE_HOME || join3(homedir3(), ".local", "state");
10912
+ return join3(root, "cursor-bridge", "lifecycle");
10911
10913
  }
10912
10914
  function ensureLifecycleDir(dir = defaultLifecycleDir()) {
10913
- mkdirSync2(dir, { recursive: true });
10915
+ mkdirSync3(dir, { recursive: true });
10914
10916
  return dir;
10915
10917
  }
10916
10918
  function lifecycleEndpointTag(dir) {
@@ -10921,13 +10923,13 @@ function supervisorSockPath(dir = defaultLifecycleDir()) {
10921
10923
  if (process.platform === "win32") {
10922
10924
  return `\\\\.\\pipe\\cursor-bridge-lifecycle-${lifecycleEndpointTag(dir)}`;
10923
10925
  }
10924
- return join2(dir, "supervisor.sock");
10926
+ return join3(dir, "supervisor.sock");
10925
10927
  }
10926
10928
  function supervisorPidPath(dir = defaultLifecycleDir()) {
10927
- return join2(dir, "supervisor.pid");
10929
+ return join3(dir, "supervisor.pid");
10928
10930
  }
10929
10931
  function supervisorLockPath(dir = defaultLifecycleDir()) {
10930
- return join2(dir, "supervisor.lock");
10932
+ return join3(dir, "supervisor.lock");
10931
10933
  }
10932
10934
  var init_lifecycle_paths = __esm({
10933
10935
  "lifecycle-paths.mjs"() {
@@ -10937,15 +10939,15 @@ var init_lifecycle_paths = __esm({
10937
10939
  // workspace-binding.mjs
10938
10940
  import {
10939
10941
  existsSync,
10940
- mkdirSync as mkdirSync3,
10941
- readFileSync as readFileSync2,
10942
- renameSync as renameSync2,
10943
- rmSync as rmSync2,
10942
+ mkdirSync as mkdirSync4,
10943
+ readFileSync as readFileSync3,
10944
+ renameSync as renameSync3,
10945
+ rmSync as rmSync3,
10944
10946
  statSync,
10945
- writeFileSync as writeFileSync2
10947
+ writeFileSync as writeFileSync3
10946
10948
  } from "node:fs";
10947
- import { dirname as dirname2, extname, isAbsolute, join as join3, resolve as resolve2 } from "node:path";
10948
- import { homedir as homedir3 } from "node:os";
10949
+ import { dirname as dirname3, extname, isAbsolute, join as join4, resolve as resolve3 } from "node:path";
10950
+ import { homedir as homedir4 } from "node:os";
10949
10951
  function pluginRuntimePath(candidate) {
10950
10952
  const value = String(candidate || "").replace(/\//g, "\\").toLowerCase();
10951
10953
  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 +10955,11 @@ function pluginRuntimePath(candidate) {
10953
10955
  function normalizeWorkspacePath(value) {
10954
10956
  let raw = String(value || "").trim().replace(/^(["'])(.*)\1$/, "$2").trim();
10955
10957
  if (!raw) return "";
10956
- if (raw === "~") raw = homedir3();
10957
- else if (raw.startsWith("~/") || raw.startsWith("~\\")) raw = join3(homedir3(), raw.slice(2));
10958
- if (/^\\\\\?\\UNC\\/i.test(raw)) return resolve2(`\\\\${raw.slice(8)}`);
10959
- if (/^\\\\\?\\[a-zA-Z]:\\/.test(raw)) return resolve2(raw.slice(4));
10960
- return resolve2(raw);
10958
+ if (raw === "~") raw = homedir4();
10959
+ else if (raw.startsWith("~/") || raw.startsWith("~\\")) raw = join4(homedir4(), raw.slice(2));
10960
+ if (/^\\\\\?\\UNC\\/i.test(raw)) return resolve3(`\\\\${raw.slice(8)}`);
10961
+ if (/^\\\\\?\\[a-zA-Z]:\\/.test(raw)) return resolve3(raw.slice(4));
10962
+ return resolve3(raw);
10961
10963
  }
10962
10964
  function isAbsoluteWorkspacePath(value) {
10963
10965
  const raw = String(value || "").trim().replace(/^(["'])(.*)\1$/, "$2").trim();
@@ -10977,7 +10979,7 @@ function isWorkspaceTarget(projectPath, options = {}) {
10977
10979
  }
10978
10980
  }
10979
10981
  function resolveWorkspaceBindingFile(env = process.env) {
10980
- return resolve2(env.CURSOR_BRIDGE_WORKSPACE_FILE || join3(defaultLifecycleDir(), "workspaces.json"));
10982
+ return resolve3(env.CURSOR_BRIDGE_WORKSPACE_FILE || join4(defaultLifecycleDir(), "workspaces.json"));
10981
10983
  }
10982
10984
  function resolveWorkspaceBindingKey(env = process.env, options = {}) {
10983
10985
  const codexThreadId = String(env.CODEX_THREAD_ID || "").trim();
@@ -11001,7 +11003,7 @@ function resolveWorkspaceBindingKey(env = process.env, options = {}) {
11001
11003
  function readWorkspaceBindings(filePath) {
11002
11004
  if (!filePath) return { version: WORKSPACE_BINDING_VERSION, bindings: {} };
11003
11005
  try {
11004
- const parsed = JSON.parse(readFileSync2(filePath, "utf8"));
11006
+ const parsed = JSON.parse(readFileSync3(filePath, "utf8"));
11005
11007
  if (!parsed || parsed.version !== WORKSPACE_BINDING_VERSION || !parsed.bindings || typeof parsed.bindings !== "object") {
11006
11008
  return { version: WORKSPACE_BINDING_VERSION, bindings: {} };
11007
11009
  }
@@ -11038,13 +11040,13 @@ function writeWorkspaceBinding(filePath, bindingKey, projectPath, options = {})
11038
11040
  const state = readWorkspaceBindings(filePath);
11039
11041
  const updatedAt = options.updatedAt || (/* @__PURE__ */ new Date()).toISOString();
11040
11042
  state.bindings[key] = { projectPath: normalized, updatedAt };
11041
- mkdirSync3(dirname2(filePath), { recursive: true });
11043
+ mkdirSync4(dirname3(filePath), { recursive: true });
11042
11044
  const temporary = `${filePath}.${process.pid}.${Date.now()}.tmp`;
11043
11045
  try {
11044
- writeFileSync2(temporary, JSON.stringify(state, null, 2) + "\n", "utf8");
11045
- renameSync2(temporary, filePath);
11046
+ writeFileSync3(temporary, JSON.stringify(state, null, 2) + "\n", "utf8");
11047
+ renameSync3(temporary, filePath);
11046
11048
  } catch (error2) {
11047
- rmSync2(temporary, { force: true });
11049
+ rmSync3(temporary, { force: true });
11048
11050
  throw new Error(`failed to persist cursor_init at ${filePath}: ${error2 instanceof Error ? error2.message : String(error2)}`);
11049
11051
  }
11050
11052
  return { projectPath: normalized, updatedAt };
@@ -11068,8 +11070,8 @@ var init_workspace_binding = __esm({
11068
11070
  import { spawn as spawn2, execFileSync as execFileSync2 } from "child_process";
11069
11071
  import { existsSync as existsSync2 } from "fs";
11070
11072
  import { createRequire as createNodeRequire } from "node:module";
11071
- import { homedir as homedir4 } from "node:os";
11072
- import { basename as basename2, extname as extname2, join as join4, resolve as resolve3, win32 as winPath, posix as posixPath } from "node:path";
11073
+ import { homedir as homedir5 } from "node:os";
11074
+ import { basename as basename3, extname as extname2, join as join5, resolve as resolve4, win32 as winPath, posix as posixPath } from "node:path";
11073
11075
  import http from "http";
11074
11076
  function resolveCursorLaunchCdpPort(port = process.env.CURSOR_BRIDGE_CDP_PORT) {
11075
11077
  const parsed = Number(port == null || String(port).trim() === "" ? 9223 : port);
@@ -11096,13 +11098,13 @@ function resolveCodexThreadProjectPath(options = {}) {
11096
11098
  try {
11097
11099
  const lookupThreadCwd = options.lookupThreadCwd || ((id) => {
11098
11100
  const { DatabaseSync } = (options.requireImpl || loadModule)("node:sqlite");
11099
- const databasePath = options.databasePath || join4(homedir4(), ".codex", "state_5.sqlite");
11101
+ const databasePath = options.databasePath || join5(homedir5(), ".codex", "state_5.sqlite");
11100
11102
  database = new DatabaseSync(databasePath, { readOnly: true });
11101
11103
  return database.prepare("SELECT cwd FROM threads WHERE id = ?").get(id)?.cwd || null;
11102
11104
  });
11103
11105
  const candidate = normalizeCodexThreadCwd(lookupThreadCwd(threadId));
11104
11106
  const existsImpl = options.existsImpl || existsSync2;
11105
- const resolved = candidate && !looksLikePluginRuntimePath(candidate) && existsImpl(candidate) ? resolve3(candidate) : null;
11107
+ const resolved = candidate && !looksLikePluginRuntimePath(candidate) && existsImpl(candidate) ? resolve4(candidate) : null;
11106
11108
  if (options.useCache !== false) CODEX_THREAD_PROJECTS.set(threadId, resolved);
11107
11109
  return resolved;
11108
11110
  } catch {
@@ -11117,14 +11119,14 @@ function resolveCodexThreadProjectPath(options = {}) {
11117
11119
  }
11118
11120
  function resolveProjectPath(value = process.env.CURSOR_PROJECT_PATH, options = {}) {
11119
11121
  const explicit = String(value || "").trim();
11120
- if (explicit) return resolve3(explicit);
11122
+ if (explicit) return resolve4(explicit);
11121
11123
  const persisted = String(options.persistedProjectPath || "").trim();
11122
- if (persisted) return resolve3(normalizeCodexThreadCwd(persisted));
11124
+ if (persisted) return resolve4(normalizeCodexThreadCwd(persisted));
11123
11125
  const threadProjectPath = options.threadProjectPath === void 0 ? resolveCodexThreadProjectPath(options) : options.threadProjectPath;
11124
- if (threadProjectPath) return resolve3(normalizeCodexThreadCwd(threadProjectPath));
11126
+ if (threadProjectPath) return resolve4(normalizeCodexThreadCwd(threadProjectPath));
11125
11127
  const cwd = options.cwd ?? process.cwd();
11126
11128
  if (!cwd || looksLikePluginRuntimePath(cwd)) return null;
11127
- return resolve3(cwd);
11129
+ return resolve4(cwd);
11128
11130
  }
11129
11131
  function cursorFromRegistry(options = {}) {
11130
11132
  const execFileSyncImpl = options.execFileSyncImpl || execFileSync2;
@@ -11189,7 +11191,7 @@ function findCursorExeDetails(options = {}) {
11189
11191
  existsImpl
11190
11192
  });
11191
11193
  if (fromReg) return { path: fromReg, source: "windows_registry", platform };
11192
- const localAppData = env.LOCALAPPDATA || join4(homedir4(), "AppData", "Local");
11194
+ const localAppData = env.LOCALAPPDATA || join5(homedir5(), "AppData", "Local");
11193
11195
  const programFiles = env.ProgramFiles || env.PROGRAMFILES || "C:\\Program Files";
11194
11196
  const programFilesX86 = env["ProgramFiles(x86)"] || env.PROGRAMFILES_X86 || "";
11195
11197
  const candidates = [
@@ -11206,7 +11208,7 @@ function findCursorExeDetails(options = {}) {
11206
11208
  return null;
11207
11209
  }
11208
11210
  if (platform === "darwin") {
11209
- const userHome = env.HOME || homedir4();
11211
+ const userHome = env.HOME || homedir5();
11210
11212
  const candidates = [
11211
11213
  "/Applications/Cursor.app/Contents/MacOS/Cursor",
11212
11214
  userHome && posixPath.join(userHome, "Applications", "Cursor.app", "Contents", "MacOS", "Cursor")
@@ -11225,42 +11227,42 @@ function findCursorExe(options = {}) {
11225
11227
  return findCursorExeDetails(options)?.path || null;
11226
11228
  }
11227
11229
  function cdpUp(timeoutMs = 1500) {
11228
- return new Promise((resolve6) => {
11230
+ return new Promise((resolve7) => {
11229
11231
  const req = http.get({ host: CDP_HOST, port: CDP_PORT, path: "/json/version" }, (res) => {
11230
11232
  res.resume();
11231
- resolve6(res.statusCode === 200);
11233
+ resolve7(res.statusCode === 200);
11232
11234
  });
11233
- req.on("error", () => resolve6(false));
11235
+ req.on("error", () => resolve7(false));
11234
11236
  req.setTimeout(timeoutMs, () => {
11235
11237
  try {
11236
11238
  req.destroy();
11237
11239
  } catch {
11238
11240
  }
11239
- resolve6(false);
11241
+ resolve7(false);
11240
11242
  });
11241
11243
  });
11242
11244
  }
11243
11245
  function cdpIsCursor(timeoutMs = 1500) {
11244
- return new Promise((resolve6) => {
11246
+ return new Promise((resolve7) => {
11245
11247
  const req = http.get({ host: CDP_HOST, port: CDP_PORT, path: "/json/list" }, (res) => {
11246
11248
  let d = "";
11247
11249
  res.on("data", (c) => d += c);
11248
11250
  res.on("end", () => {
11249
11251
  try {
11250
- if (/[\/\\](windsurf)[\/\\]/i.test(d)) return resolve6(false);
11251
- resolve6(/[\/\\]cursor[\/\\](resources|app)|cursor\.exe|vscode-app[^"]*[\/\\]cursor[\/\\]/i.test(d));
11252
+ if (/[\/\\](windsurf)[\/\\]/i.test(d)) return resolve7(false);
11253
+ resolve7(/[\/\\]cursor[\/\\](resources|app)|cursor\.exe|vscode-app[^"]*[\/\\]cursor[\/\\]/i.test(d));
11252
11254
  } catch {
11253
- resolve6(false);
11255
+ resolve7(false);
11254
11256
  }
11255
11257
  });
11256
11258
  });
11257
- req.on("error", () => resolve6(false));
11259
+ req.on("error", () => resolve7(false));
11258
11260
  req.setTimeout(timeoutMs, () => {
11259
11261
  try {
11260
11262
  req.destroy();
11261
11263
  } catch {
11262
11264
  }
11263
- resolve6(false);
11265
+ resolve7(false);
11264
11266
  });
11265
11267
  });
11266
11268
  }
@@ -11292,6 +11294,58 @@ async function waitForCdp(maxMs = 3e4, stepMs = 1e3) {
11292
11294
  }
11293
11295
  return false;
11294
11296
  }
11297
+ async function spawnDetachedSafely(spawnImpl, file, args, spawnOptions) {
11298
+ let child;
11299
+ try {
11300
+ child = spawnImpl(file, args, spawnOptions);
11301
+ } catch (error2) {
11302
+ return {
11303
+ ok: false,
11304
+ child: null,
11305
+ error: error2,
11306
+ errorCode: error2 && typeof error2 === "object" && error2.code != null ? String(error2.code) : null
11307
+ };
11308
+ }
11309
+ if (child && typeof child.once === "function") {
11310
+ const startup = await new Promise((resolvePromise) => {
11311
+ let settled = false;
11312
+ const finish = (result) => {
11313
+ if (settled) return;
11314
+ settled = true;
11315
+ child.off?.("spawn", onSpawn);
11316
+ child.off?.("error", onError);
11317
+ resolvePromise(result);
11318
+ };
11319
+ const onSpawn = () => finish({ ok: true });
11320
+ const onError = (error2) => finish({ ok: false, error: error2 });
11321
+ child.once("spawn", onSpawn);
11322
+ child.once("error", onError);
11323
+ if (Number.isInteger(child.pid) && child.pid > 0) queueMicrotask(onSpawn);
11324
+ });
11325
+ if (!startup.ok) {
11326
+ return {
11327
+ ok: false,
11328
+ child,
11329
+ error: startup.error,
11330
+ errorCode: startup.error && typeof startup.error === "object" && startup.error.code != null ? String(startup.error.code) : null
11331
+ };
11332
+ }
11333
+ child.once("error", () => {
11334
+ });
11335
+ }
11336
+ if (child && typeof child.unref === "function") child.unref();
11337
+ return { ok: true, child };
11338
+ }
11339
+ function attachedPresentation(runtimeMode, port) {
11340
+ if (runtimeMode !== "minimal") return null;
11341
+ return {
11342
+ supported: true,
11343
+ applied: false,
11344
+ action: "hide",
11345
+ port,
11346
+ reason: "attached lifecycle cannot start the PowerShell window guard under the current process policy"
11347
+ };
11348
+ }
11295
11349
  async function ensureCursorRunningLocal(options = {}) {
11296
11350
  const waitMs = Number(options.waitMs || 3e4);
11297
11351
  const runtimeMode = options.runtimeMode || "normal";
@@ -11300,15 +11354,17 @@ async function ensureCursorRunningLocal(options = {}) {
11300
11354
  const cdpIsCursorImpl = options.cdpIsCursorImpl || cdpIsCursor;
11301
11355
  const cursorRunningImpl = options.cursorRunningImpl || cursorRunning;
11302
11356
  const findCursorExeDetailsImpl = options.findCursorExeDetailsImpl || findCursorExeDetails;
11303
- const projectPath = Object.hasOwn(options, "projectPath") ? options.projectPath ? resolve3(String(options.projectPath)) : null : resolveProjectPath();
11357
+ const projectPath = Object.hasOwn(options, "projectPath") ? options.projectPath ? resolve4(String(options.projectPath)) : null : resolveProjectPath();
11304
11358
  const listCdpPageTargetsImpl = options.listCdpPageTargetsImpl || listCdpPageTargets;
11305
11359
  const spawnImpl = options.spawnImpl || spawn2;
11360
+ const allowSpawn = options.allowSpawn !== false;
11361
+ const allowProcessControl = options.allowProcessControl !== false;
11306
11362
  if (await cdpUpImpl()) {
11307
11363
  const isCursor = await cdpIsCursorImpl();
11308
11364
  if (isCursor) {
11309
- const cursorPid2 = findCursorPidByPort(CDP_PORT);
11310
- const windowGuard2 = effectiveRuntimeMode === "minimal" && cursorPid2 ? startMinimalWindowGuard(cursorPid2) : null;
11311
- const presentation2 = effectiveRuntimeMode === "minimal" ? setCursorWindowPresentation({ action: "hide", port: CDP_PORT, pid: cursorPid2 }) : null;
11365
+ const cursorPid2 = allowProcessControl ? findCursorPidByPort(CDP_PORT) : null;
11366
+ const windowGuard2 = allowProcessControl && effectiveRuntimeMode === "minimal" && cursorPid2 ? startMinimalWindowGuard(cursorPid2) : null;
11367
+ const presentation2 = effectiveRuntimeMode === "minimal" ? allowProcessControl ? setCursorWindowPresentation({ action: "hide", port: CDP_PORT, pid: cursorPid2 }) : attachedPresentation(effectiveRuntimeMode, CDP_PORT) : null;
11312
11368
  const currentTargets = await listCdpPageTargetsImpl();
11313
11369
  const projectKey = normalizeProjectKey(projectPath);
11314
11370
  let targetId2 = projectKey ? PROJECT_TARGETS.get(projectKey) || null : currentTargets[0] && currentTargets[0].id || null;
@@ -11337,6 +11393,22 @@ async function ensureCursorRunningLocal(options = {}) {
11337
11393
  }
11338
11394
  }
11339
11395
  if (projectPath && existsSync2(projectPath) && !targetId2) {
11396
+ if (!allowSpawn) {
11397
+ return {
11398
+ ok: false,
11399
+ status: "workspace-not-ready",
11400
+ port: CDP_PORT,
11401
+ cursorPid: cursorPid2,
11402
+ runtimeMode: effectiveRuntimeMode,
11403
+ projectPath,
11404
+ presentation: presentation2,
11405
+ windowGuard: windowGuard2,
11406
+ needsAction: "open_workspace_in_cursor",
11407
+ retryable: true,
11408
+ nextStep: `Open workspace ${projectPath} in the existing Cursor Agents Window, then retry the same operation.`,
11409
+ message: `CCE connected to Cursor, but the current workspace target for ${projectPath} is not ready and the current lifecycle cannot open a new window.`
11410
+ };
11411
+ }
11340
11412
  const cursorExecutable2 = findCursorExeDetailsImpl();
11341
11413
  const exe2 = cursorExecutable2 && cursorExecutable2.path;
11342
11414
  if (!exe2) {
@@ -11356,12 +11428,28 @@ async function ensureCursorRunningLocal(options = {}) {
11356
11428
  };
11357
11429
  }
11358
11430
  const beforeTargetIds = new Set(currentTargets.map((target2) => target2.id));
11359
- const opener = spawnImpl(exe2, ["--new-window", projectPath], {
11431
+ const opened = await spawnDetachedSafely(spawnImpl, exe2, ["--new-window", projectPath], {
11360
11432
  detached: true,
11361
11433
  stdio: "ignore",
11362
11434
  windowsHide: effectiveRuntimeMode === "minimal"
11363
11435
  });
11364
- opener.unref();
11436
+ if (!opened.ok) {
11437
+ return {
11438
+ ok: false,
11439
+ status: "spawn-blocked",
11440
+ port: CDP_PORT,
11441
+ cursorPid: cursorPid2,
11442
+ runtimeMode: effectiveRuntimeMode,
11443
+ projectPath,
11444
+ presentation: presentation2,
11445
+ windowGuard: windowGuard2,
11446
+ errorCode: opened.errorCode,
11447
+ needsAction: "open_workspace_in_cursor",
11448
+ retryable: true,
11449
+ nextStep: `Open workspace ${projectPath} in Cursor, then retry the same operation.`,
11450
+ message: `Cursor Bridge could not open a new workspace window: ${opened.error instanceof Error ? opened.error.message : String(opened.error)}`
11451
+ };
11452
+ }
11365
11453
  workspaceAction = "opened-new-window";
11366
11454
  const openedTarget2 = await waitForNewCdpTarget(beforeTargetIds, 12e3, projectPath, listCdpPageTargetsImpl);
11367
11455
  if (!openedTarget2) {
@@ -11410,6 +11498,21 @@ async function ensureCursorRunningLocal(options = {}) {
11410
11498
  message: `CCE cannot connect to Cursor because required local port ${CDP_PORT} is occupied by another program.`
11411
11499
  };
11412
11500
  }
11501
+ if (!allowSpawn) {
11502
+ return {
11503
+ ok: false,
11504
+ status: "external-launch-required",
11505
+ port: CDP_PORT,
11506
+ cursorPid: null,
11507
+ runtimeMode: effectiveRuntimeMode,
11508
+ projectPath,
11509
+ presentation: attachedPresentation(effectiveRuntimeMode, CDP_PORT),
11510
+ needsAction: "launch_cursor_with_cdp",
11511
+ retryable: true,
11512
+ nextStep: `Start Cursor with its remote debugging connection on port ${CDP_PORT}, open ${projectPath || "the target workspace"}, then retry the same operation.`,
11513
+ message: `Cursor is not reachable on the configured CDP port ${CDP_PORT}, and the current lifecycle policy cannot launch it.`
11514
+ };
11515
+ }
11413
11516
  if (cursorRunningImpl()) {
11414
11517
  const cursorExecutable2 = findCursorExeDetailsImpl();
11415
11518
  return {
@@ -11447,13 +11550,29 @@ async function ensureCursorRunningLocal(options = {}) {
11447
11550
  );
11448
11551
  }
11449
11552
  if (projectPath && existsSync2(projectPath)) args.push(projectPath);
11450
- const child = spawnImpl(exe, args, {
11553
+ const launched = await spawnDetachedSafely(spawnImpl, exe, args, {
11451
11554
  detached: true,
11452
11555
  stdio: "ignore",
11453
11556
  windowsHide: effectiveRuntimeMode === "minimal"
11454
11557
  });
11455
- child.unref();
11456
- const startupWindowGuard = effectiveRuntimeMode === "minimal" ? startMinimalWindowGuard(child.pid) : null;
11558
+ if (!launched.ok) {
11559
+ return {
11560
+ ok: false,
11561
+ status: "spawn-blocked",
11562
+ exe,
11563
+ port: CDP_PORT,
11564
+ cursorPid: null,
11565
+ runtimeMode: effectiveRuntimeMode,
11566
+ projectPath,
11567
+ errorCode: launched.errorCode,
11568
+ needsAction: "launch_cursor_manually",
11569
+ retryable: true,
11570
+ nextStep: `Start Cursor with its remote debugging connection on port ${CDP_PORT}, then retry the same operation.`,
11571
+ message: `Cursor Bridge could not launch Cursor: ${launched.error instanceof Error ? launched.error.message : String(launched.error)}`
11572
+ };
11573
+ }
11574
+ const child = launched.child;
11575
+ const startupWindowGuard = effectiveRuntimeMode === "minimal" ? startMinimalWindowGuard(child && child.pid) : null;
11457
11576
  const up = await waitForCdp(waitMs);
11458
11577
  if (!up) {
11459
11578
  return {
@@ -11517,10 +11636,10 @@ async function ensureCursorRunningLocal(options = {}) {
11517
11636
  };
11518
11637
  }
11519
11638
  function normalizeProjectKey(projectPath) {
11520
- return projectPath ? resolve3(String(projectPath)).replace(/\\/g, "/").toLowerCase() : "";
11639
+ return projectPath ? resolve4(String(projectPath)).replace(/\\/g, "/").toLowerCase() : "";
11521
11640
  }
11522
11641
  function targetTitleMatchesProject(title, projectPath) {
11523
- const name = basename2(String(projectPath || "")).trim().toLowerCase();
11642
+ const name = basename3(String(projectPath || "")).trim().toLowerCase();
11524
11643
  if (!name) return false;
11525
11644
  const extension2 = extname2(name);
11526
11645
  const candidates = [...new Set([name, extension2 ? name.slice(0, -extension2.length) : name].filter(Boolean))];
@@ -11643,6 +11762,67 @@ function whichNode() {
11643
11762
  }
11644
11763
  return process.execPath;
11645
11764
  }
11765
+ function wmiReturnValueFromError(error2) {
11766
+ const message = error2 instanceof Error ? error2.message : String(error2 || "");
11767
+ const match = message.match(/Win32_Process\.Create failed:\s*(\d+)/i);
11768
+ return match ? Number(match[1]) : null;
11769
+ }
11770
+ function classifyOutsideJobSpawnError(error2) {
11771
+ const code = error2 && typeof error2 === "object" && error2.code != null ? String(error2.code) : null;
11772
+ const returnValue = wmiReturnValueFromError(error2);
11773
+ if (code === "EPERM" || code === "EACCES") {
11774
+ return {
11775
+ errorKind: "policy-blocked",
11776
+ degradedReason: "spawn-policy-blocked",
11777
+ errorCode: code,
11778
+ returnValue,
11779
+ canAttachFallback: true
11780
+ };
11781
+ }
11782
+ if (returnValue === 2 || returnValue === 3) {
11783
+ return {
11784
+ errorKind: "policy-blocked",
11785
+ degradedReason: "wmi-access-denied",
11786
+ errorCode: returnValue,
11787
+ returnValue,
11788
+ canAttachFallback: true
11789
+ };
11790
+ }
11791
+ if (returnValue === 8) {
11792
+ return {
11793
+ errorKind: "wmi-unknown",
11794
+ degradedReason: "wmi-unknown-8",
11795
+ errorCode: returnValue,
11796
+ returnValue,
11797
+ canAttachFallback: true
11798
+ };
11799
+ }
11800
+ if (returnValue === 9 || returnValue === 21) {
11801
+ return {
11802
+ errorKind: "configuration",
11803
+ degradedReason: null,
11804
+ errorCode: returnValue,
11805
+ returnValue,
11806
+ canAttachFallback: false
11807
+ };
11808
+ }
11809
+ if (code === "ETIMEDOUT" || error2 && typeof error2 === "object" && error2.killed === true) {
11810
+ return {
11811
+ errorKind: "timeout",
11812
+ degradedReason: "spawn-timeout",
11813
+ errorCode: code || "ETIMEDOUT",
11814
+ returnValue,
11815
+ canAttachFallback: true
11816
+ };
11817
+ }
11818
+ return {
11819
+ errorKind: "unknown",
11820
+ degradedReason: null,
11821
+ errorCode: code,
11822
+ returnValue,
11823
+ canAttachFallback: false
11824
+ };
11825
+ }
11646
11826
  function spawnOutsideJob(file, args = [], options = {}) {
11647
11827
  const cwd = options.cwd || process.cwd();
11648
11828
  const env = options.env || process.env;
@@ -11663,7 +11843,8 @@ function spawnOutsideJob(file, args = [], options = {}) {
11663
11843
  throw new Error("forced WMI failure for tests");
11664
11844
  }
11665
11845
  const ps = buildHiddenWmiCreateScript(commandLine, cwd);
11666
- const out = execFileSync3("powershell.exe", [
11846
+ const run = options.execFileSyncImpl || execFileSync3;
11847
+ const out = run("powershell.exe", [
11667
11848
  "-NoProfile",
11668
11849
  "-NonInteractive",
11669
11850
  "-ExecutionPolicy",
@@ -11683,10 +11864,14 @@ function spawnOutsideJob(file, args = [], options = {}) {
11683
11864
  return { ok: true, method: "wmi-win32-process-create", pid, commandLine };
11684
11865
  } catch (wmiError) {
11685
11866
  const wmiMsg = wmiError instanceof Error ? wmiError.message : String(wmiError);
11867
+ const classification = classifyOutsideJobSpawnError(wmiError);
11868
+ const stderr = wmiError && typeof wmiError === "object" && wmiError.stderr != null ? String(wmiError.stderr).trim() || null : null;
11686
11869
  return {
11687
11870
  ok: false,
11688
11871
  method: "failed",
11689
11872
  commandLine,
11873
+ ...classification,
11874
+ stderr,
11690
11875
  error: `WMI Win32_Process.Create failed: ${wmiMsg}. Launch stopped without a shell fallback so Cursor Bridge cannot flash a console or create an unreliable orphan.`
11691
11876
  };
11692
11877
  }
@@ -11707,69 +11892,76 @@ import net from "node:net";
11707
11892
  import { createHash as createHash2 } from "node:crypto";
11708
11893
  import {
11709
11894
  existsSync as existsSync4,
11710
- mkdirSync as mkdirSync4,
11711
- readFileSync as readFileSync3,
11895
+ mkdirSync as mkdirSync5,
11896
+ readFileSync as readFileSync4,
11712
11897
  readdirSync,
11713
- renameSync as renameSync3,
11714
- rmSync as rmSync3,
11898
+ renameSync as renameSync4,
11899
+ rmSync as rmSync4,
11715
11900
  unlinkSync,
11716
- writeFileSync as writeFileSync3
11901
+ writeFileSync as writeFileSync4
11717
11902
  } from "node:fs";
11718
11903
  import { fileURLToPath } from "node:url";
11719
- import { dirname as dirname3, join as join5, resolve as resolve4 } from "node:path";
11904
+ import { dirname as dirname4, join as join6, resolve as resolve5 } from "node:path";
11720
11905
  function sleep(ms) {
11721
11906
  return new Promise((r) => setTimeout(r, ms));
11722
11907
  }
11723
11908
  function resolveSupervisorScript() {
11724
11909
  if (process.env.CURSOR_BRIDGE_SUPERVISOR_SCRIPT && existsSync4(process.env.CURSOR_BRIDGE_SUPERVISOR_SCRIPT)) {
11725
- return resolve4(process.env.CURSOR_BRIDGE_SUPERVISOR_SCRIPT);
11910
+ return resolve5(process.env.CURSOR_BRIDGE_SUPERVISOR_SCRIPT);
11726
11911
  }
11727
- const here = dirname3(fileURLToPath(import.meta.url));
11912
+ const here = dirname4(fileURLToPath(import.meta.url));
11728
11913
  const candidates = [];
11729
11914
  if (typeof process.argv[1] === "string") {
11730
- const entryDir = dirname3(resolve4(process.argv[1]));
11731
- candidates.push(join5(entryDir, "dist", "cursor-lifecycle-supervisor.mjs"));
11732
- candidates.push(join5(entryDir, "cursor-lifecycle-supervisor.mjs"));
11915
+ const entryDir = dirname4(resolve5(process.argv[1]));
11916
+ candidates.push(join6(entryDir, "dist", "cursor-lifecycle-supervisor.mjs"));
11917
+ candidates.push(join6(entryDir, "cursor-lifecycle-supervisor.mjs"));
11733
11918
  }
11734
11919
  candidates.push(
11735
- join5(here, "dist", "cursor-lifecycle-supervisor.mjs"),
11736
- join5(here, "cursor-lifecycle-supervisor.mjs")
11920
+ join6(here, "dist", "cursor-lifecycle-supervisor.mjs"),
11921
+ join6(here, "cursor-lifecycle-supervisor.mjs")
11737
11922
  );
11738
11923
  for (const c of candidates) {
11739
11924
  if (existsSync4(c)) return c;
11740
11925
  }
11741
- return join5(here, "cursor-lifecycle-supervisor.mjs");
11926
+ return join6(here, "cursor-lifecycle-supervisor.mjs");
11742
11927
  }
11743
11928
  function writeRuntimeFile(target, content) {
11744
- if (existsSync4(target) && readFileSync3(target).equals(content)) return;
11929
+ if (existsSync4(target) && readFileSync4(target).equals(content)) return;
11745
11930
  const temporary = `${target}.${process.pid}.${Date.now()}.tmp`;
11746
- writeFileSync3(temporary, content);
11931
+ writeFileSync4(temporary, content);
11747
11932
  try {
11748
- renameSync3(temporary, target);
11933
+ renameSync4(temporary, target);
11749
11934
  } catch (error2) {
11750
11935
  if (!existsSync4(target)) {
11751
- rmSync3(temporary, { force: true });
11936
+ rmSync4(temporary, { force: true });
11752
11937
  throw error2;
11753
11938
  }
11754
- if (readFileSync3(target).equals(content)) {
11755
- rmSync3(temporary, { force: true });
11939
+ if (readFileSync4(target).equals(content)) {
11940
+ rmSync4(temporary, { force: true });
11756
11941
  return;
11757
11942
  }
11758
- rmSync3(target, { force: true });
11759
- renameSync3(temporary, target);
11943
+ rmSync4(target, { force: true });
11944
+ renameSync4(temporary, target);
11760
11945
  }
11761
11946
  }
11762
11947
  function materializeLifecycleSupervisorRuntime({ sourceScript, dir = defaultLifecycleDir() } = {}) {
11763
- const source = resolve4(sourceScript || resolveSupervisorScript());
11764
- if (!existsSync4(source)) throw new Error(`lifecycle supervisor script missing: ${source}`);
11765
- const content = readFileSync3(source);
11766
- const fingerprint = createHash2("sha256").update(content).digest("hex");
11767
- const runtimeRoot = join5(ensureLifecycleDir(dir), "runtime", `supervisor-${fingerprint.slice(0, 20)}`);
11768
- mkdirSync4(runtimeRoot, { recursive: true });
11769
- const script = join5(runtimeRoot, "cursor-lifecycle-supervisor.mjs");
11948
+ const described = describeLifecycleSupervisorRuntime({ sourceScript, dir });
11949
+ const { sourceScript: source, content, fingerprint } = described;
11950
+ const runtimeRoot = join6(ensureLifecycleDir(dir), "runtime", `supervisor-${fingerprint.slice(0, 20)}`);
11951
+ mkdirSync5(runtimeRoot, { recursive: true });
11952
+ const script = join6(runtimeRoot, "cursor-lifecycle-supervisor.mjs");
11770
11953
  writeRuntimeFile(script, content);
11771
11954
  return { sourceScript: source, script, runtimeRoot, fingerprint };
11772
11955
  }
11956
+ function describeLifecycleSupervisorRuntime({ sourceScript, dir = defaultLifecycleDir() } = {}) {
11957
+ const source = resolve5(sourceScript || resolveSupervisorScript());
11958
+ if (!existsSync4(source)) throw new Error(`lifecycle supervisor script missing: ${source}`);
11959
+ const content = readFileSync4(source);
11960
+ const fingerprint = createHash2("sha256").update(content).digest("hex");
11961
+ const runtimeRoot = join6(dir, "runtime", `supervisor-${fingerprint.slice(0, 20)}`);
11962
+ const script = join6(runtimeRoot, "cursor-lifecycle-supervisor.mjs");
11963
+ return { sourceScript: source, script, runtimeRoot, fingerprint, content };
11964
+ }
11773
11965
  function isProcessAlive(pid) {
11774
11966
  if (!pid || !Number.isFinite(pid)) return false;
11775
11967
  try {
@@ -11781,7 +11973,7 @@ function isProcessAlive(pid) {
11781
11973
  }
11782
11974
  function readPidFile(pidPath) {
11783
11975
  try {
11784
- const n = Number(String(readFileSync3(pidPath, "utf8")).trim());
11976
+ const n = Number(String(readFileSync4(pidPath, "utf8")).trim());
11785
11977
  return Number.isFinite(n) ? n : null;
11786
11978
  } catch {
11787
11979
  return null;
@@ -11867,6 +12059,28 @@ async function tryConnect(sock) {
11867
12059
  return null;
11868
12060
  }
11869
12061
  }
12062
+ async function tryConnectDetailed(sock, connectImpl = connectSupervisor) {
12063
+ try {
12064
+ return { socket: await connectImpl(sock, 1500), error: null };
12065
+ } catch (error2) {
12066
+ return { socket: null, error: error2 };
12067
+ }
12068
+ }
12069
+ function lifecycleClientError(message, details = {}, cause = null) {
12070
+ const error2 = new Error(message, cause ? { cause } : void 0);
12071
+ Object.assign(error2, details);
12072
+ return error2;
12073
+ }
12074
+ function filesystemFallbackDetails(error2) {
12075
+ const code = error2 && typeof error2 === "object" && error2.code != null ? String(error2.code) : null;
12076
+ const blocked = code === "EPERM" || code === "EACCES" || code === "EROFS";
12077
+ return {
12078
+ errorKind: blocked ? "policy-blocked" : "configuration",
12079
+ degradedReason: blocked ? "fs-policy-blocked" : null,
12080
+ errorCode: code,
12081
+ canAttachFallback: blocked
12082
+ };
12083
+ }
11870
12084
  function tryUnlink(path) {
11871
12085
  try {
11872
12086
  if (path && existsSync4(path)) unlinkSync(path);
@@ -11874,7 +12088,7 @@ function tryUnlink(path) {
11874
12088
  }
11875
12089
  }
11876
12090
  function writeBootEnv(dir, extra = {}) {
11877
- const bootPath = join5(dir, `boot-env-${process.pid}-${Date.now()}.json`);
12091
+ const bootPath = join6(dir, `boot-env-${process.pid}-${Date.now()}.json`);
11878
12092
  const payload = { ...extra };
11879
12093
  for (const [key, value] of Object.entries(process.env)) {
11880
12094
  if (key.startsWith("CURSOR_BRIDGE_") || key === "CURSOR_PROJECT_PATH" || key === "CURSOR_EXE") {
@@ -11885,70 +12099,92 @@ function writeBootEnv(dir, extra = {}) {
11885
12099
  for (const [k, v] of Object.entries(payload)) {
11886
12100
  if (v != null && v !== "") cleaned[k] = String(v);
11887
12101
  }
11888
- writeFileSync3(bootPath, `${JSON.stringify(cleaned, null, 2)}
12102
+ writeFileSync4(bootPath, `${JSON.stringify(cleaned, null, 2)}
11889
12103
  `, { encoding: "utf8" });
11890
12104
  return bootPath;
11891
12105
  }
11892
12106
  async function ensureSupervisorConnected(options = {}) {
11893
- const dir = ensureLifecycleDir(options.dir || defaultLifecycleDir());
12107
+ const dir = options.dir || defaultLifecycleDir();
11894
12108
  const sock = options.sock || supervisorSockPath(dir);
11895
12109
  const pidPath = options.pidPath || supervisorPidPath(dir);
11896
12110
  const lockPath = options.lockPath || supervisorLockPath(dir);
11897
12111
  const createWaitMs = Number(options.createWaitMs || DEFAULT_CREATE_WAIT_MS);
11898
12112
  const sourceScript = options.supervisorScript || resolveSupervisorScript();
11899
- const runtime = options.persistSupervisorRuntime === false ? {
11900
- sourceScript: resolve4(sourceScript),
11901
- script: resolve4(sourceScript),
11902
- runtimeRoot: dirname3(resolve4(sourceScript)),
11903
- fingerprint: null
11904
- } : materializeLifecycleSupervisorRuntime({ sourceScript, dir });
11905
- let socket = await tryConnect(sock);
12113
+ const connectImpl = options.connectSupervisorImpl || connectSupervisor;
12114
+ const initialConnection = await tryConnectDetailed(sock, connectImpl);
12115
+ let socket = initialConnection.socket;
11906
12116
  if (socket) {
11907
12117
  const pid = readPidFile(pidPath);
11908
12118
  let current = null;
11909
12119
  try {
11910
12120
  current = await request(socket, { type: "ping" }, 5e3);
11911
- } catch {
11912
- }
11913
- const mismatch = Boolean(runtime.fingerprint && current?.runtimeFingerprint && current.runtimeFingerprint !== runtime.fingerprint);
11914
- if (mismatch) {
11915
- let upgrade = null;
12121
+ } catch (error2) {
11916
12122
  try {
11917
- upgrade = await request(socket, {
11918
- type: "shutdown_if_idle",
11919
- confirmation: "ROLL_CURSOR_LIFECYCLE_SUPERVISOR",
11920
- targetRuntimeFingerprint: runtime.fingerprint
11921
- }, 5e3);
12123
+ socket.destroy();
11922
12124
  } catch {
11923
12125
  }
11924
- if (upgrade?.restarting === true) {
11925
- try {
11926
- socket.end();
11927
- } catch {
11928
- }
11929
- try {
11930
- socket.destroy();
11931
- } catch {
11932
- }
11933
- socket = null;
11934
- const deadline = Date.now() + 5e3;
11935
- while (Date.now() < deadline && isProcessAlive(pid)) await sleep(50);
11936
- }
12126
+ throw lifecycleClientError(`lifecycle supervisor is reachable but unresponsive: ${error2 instanceof Error ? error2.message : String(error2)}`, {
12127
+ errorKind: "supervisor-unresponsive",
12128
+ degradedReason: "supervisor-unresponsive",
12129
+ errorCode: error2 && typeof error2 === "object" && error2.code != null ? String(error2.code) : null,
12130
+ canAttachFallback: true
12131
+ }, error2);
11937
12132
  }
11938
- if (socket) {
11939
- return {
11940
- socket,
11941
- sock,
11942
- dir,
11943
- supervisorPid: pid,
11944
- reusedSupervisor: true,
11945
- createdSupervisor: false,
11946
- spawnMethod: null,
11947
- runtimeFingerprint: current?.runtimeFingerprint || null,
11948
- runtimeScript: current?.runtimeScript || null,
11949
- targetRuntimeFingerprint: runtime.fingerprint
11950
- };
12133
+ let targetRuntime = null;
12134
+ try {
12135
+ targetRuntime = options.persistSupervisorRuntime === false ? {
12136
+ sourceScript: resolve5(sourceScript),
12137
+ script: resolve5(sourceScript),
12138
+ runtimeRoot: dirname4(resolve5(sourceScript)),
12139
+ fingerprint: null
12140
+ } : describeLifecycleSupervisorRuntime({ sourceScript, dir });
12141
+ } catch {
11951
12142
  }
12143
+ const mismatch = Boolean(targetRuntime?.fingerprint && current?.runtimeFingerprint && current.runtimeFingerprint !== targetRuntime.fingerprint);
12144
+ return {
12145
+ socket,
12146
+ sock,
12147
+ dir,
12148
+ supervisorPid: pid,
12149
+ reusedSupervisor: true,
12150
+ createdSupervisor: false,
12151
+ spawnMethod: null,
12152
+ runtimeFingerprint: current?.runtimeFingerprint || null,
12153
+ runtimeScript: current?.runtimeScript || null,
12154
+ targetRuntimeFingerprint: targetRuntime?.fingerprint || null,
12155
+ runtimeUpgradeDeferred: mismatch
12156
+ };
12157
+ }
12158
+ const connectCode = initialConnection.error && typeof initialConnection.error === "object" ? String(initialConnection.error.code || "") : "";
12159
+ const connectMessage = initialConnection.error instanceof Error ? initialConnection.error.message : String(initialConnection.error || "");
12160
+ if (connectCode === "EPERM" || connectCode === "EACCES") {
12161
+ throw lifecycleClientError(`lifecycle supervisor pipe access was blocked: ${connectMessage || connectCode}`, {
12162
+ errorKind: "policy-blocked",
12163
+ degradedReason: "pipe-policy-blocked",
12164
+ errorCode: connectCode,
12165
+ canAttachFallback: true
12166
+ }, initialConnection.error);
12167
+ }
12168
+ const normalAbsenceCodes = /* @__PURE__ */ new Set(["ENOENT", "ECONNREFUSED", "ECONNRESET", "EPIPE"]);
12169
+ if (initialConnection.error && (!normalAbsenceCodes.has(connectCode) || /connect timeout/i.test(connectMessage))) {
12170
+ throw lifecycleClientError(`lifecycle supervisor pipe is unavailable without a clean absence signal: ${connectMessage || connectCode || "unknown connect error"}`, {
12171
+ errorKind: "supervisor-unresponsive",
12172
+ degradedReason: "supervisor-unresponsive",
12173
+ errorCode: connectCode || null,
12174
+ canAttachFallback: true
12175
+ }, initialConnection.error);
12176
+ }
12177
+ let runtime;
12178
+ try {
12179
+ ensureLifecycleDir(dir);
12180
+ runtime = options.persistSupervisorRuntime === false ? {
12181
+ sourceScript: resolve5(sourceScript),
12182
+ script: resolve5(sourceScript),
12183
+ runtimeRoot: dirname4(resolve5(sourceScript)),
12184
+ fingerprint: null
12185
+ } : (options.materializeRuntimeImpl || materializeLifecycleSupervisorRuntime)({ sourceScript, dir });
12186
+ } catch (error2) {
12187
+ throw lifecycleClientError(`failed to prepare lifecycle supervisor runtime: ${error2 instanceof Error ? error2.message : String(error2)}`, filesystemFallbackDetails(error2), error2);
11952
12188
  }
11953
12189
  const stalePid = readPidFile(pidPath);
11954
12190
  if (stalePid && !isProcessAlive(stalePid)) {
@@ -11984,12 +12220,20 @@ async function ensureSupervisorConnected(options = {}) {
11984
12220
  CURSOR_BRIDGE_LIFECYCLE_DIR: dir,
11985
12221
  CURSOR_BRIDGE_SUPERVISOR_SOCK: sock
11986
12222
  };
11987
- const spawned = spawnNodeOutsideJob(script, scriptArgs, {
12223
+ const spawned = (options.spawnNodeOutsideJobImpl || spawnNodeOutsideJob)(script, scriptArgs, {
11988
12224
  cwd: options.cwd || runtime.runtimeRoot,
11989
12225
  env: childEnv
11990
12226
  });
11991
12227
  if (!spawned.ok) {
11992
- throw new Error(`failed to spawn lifecycle supervisor: ${spawned.error || spawned.method}`);
12228
+ throw lifecycleClientError(`failed to spawn lifecycle supervisor: ${spawned.error || spawned.method}`, {
12229
+ errorKind: spawned.errorKind || "unknown",
12230
+ degradedReason: spawned.degradedReason || null,
12231
+ errorCode: spawned.errorCode ?? null,
12232
+ returnValue: spawned.returnValue ?? null,
12233
+ canAttachFallback: spawned.canAttachFallback === true,
12234
+ commandLine: spawned.commandLine || null,
12235
+ stderr: spawned.stderr || null
12236
+ });
11993
12237
  }
11994
12238
  const deadline = Date.now() + createWaitMs;
11995
12239
  while (Date.now() < deadline) {
@@ -12009,7 +12253,8 @@ async function ensureSupervisorConnected(options = {}) {
12009
12253
  unsafe: !!spawned.unsafe,
12010
12254
  runtimeFingerprint: runtime.fingerprint,
12011
12255
  runtimeScript: script,
12012
- targetRuntimeFingerprint: runtime.fingerprint
12256
+ targetRuntimeFingerprint: runtime.fingerprint,
12257
+ runtimeUpgradeDeferred: false
12013
12258
  };
12014
12259
  }
12015
12260
  await sleep(100);
@@ -12045,7 +12290,8 @@ async function ensureCursorViaSupervisor(options = {}) {
12045
12290
  launchReason: "supervisor-error",
12046
12291
  spawnMethod: conn.spawnMethod,
12047
12292
  runtimeFingerprint: conn.runtimeFingerprint || null,
12048
- runtimeScript: conn.runtimeScript || null
12293
+ runtimeScript: conn.runtimeScript || null,
12294
+ runtimeUpgradeDeferred: conn.runtimeUpgradeDeferred === true
12049
12295
  };
12050
12296
  }
12051
12297
  return {
@@ -12070,7 +12316,8 @@ async function ensureCursorViaSupervisor(options = {}) {
12070
12316
  spawnMethod: conn.spawnMethod,
12071
12317
  ensureCount: response.ensureCount,
12072
12318
  runtimeFingerprint: response.runtimeFingerprint || conn.runtimeFingerprint || null,
12073
- runtimeScript: response.runtimeScript || conn.runtimeScript || null
12319
+ runtimeScript: response.runtimeScript || conn.runtimeScript || null,
12320
+ runtimeUpgradeDeferred: conn.runtimeUpgradeDeferred === true
12074
12321
  };
12075
12322
  } finally {
12076
12323
  try {
@@ -12109,6 +12356,26 @@ __export(launch_cursor_exports, {
12109
12356
  waitForCdp: () => waitForCdp
12110
12357
  });
12111
12358
  import { pathToFileURL } from "url";
12359
+ function lifecycleCapabilities(mode) {
12360
+ if (mode === "supervised") {
12361
+ return { canLaunchCursor: true, canOpenWorkspaceWindow: true, survivesHostExit: "cursor-yes-tasks-no" };
12362
+ }
12363
+ if (mode === "attached") {
12364
+ return { canLaunchCursor: false, canOpenWorkspaceWindow: false, survivesHostExit: "cursor-yes-tasks-no" };
12365
+ }
12366
+ return { canLaunchCursor: true, canOpenWorkspaceWindow: true, survivesHostExit: "not-guaranteed" };
12367
+ }
12368
+ function withLifecycle(result, mode, extra = {}) {
12369
+ return {
12370
+ ...result,
12371
+ lifecycleMode: mode,
12372
+ persistent: mode === "supervised",
12373
+ degradedReason: extra.degradedReason || null,
12374
+ spawnErrorCode: extra.spawnErrorCode ?? null,
12375
+ capabilities: lifecycleCapabilities(mode),
12376
+ ...extra
12377
+ };
12378
+ }
12112
12379
  async function ensureCursorRunning(options = {}) {
12113
12380
  const bindingFile = options.workspaceFile || resolveWorkspaceBindingFile();
12114
12381
  const bindingKey = options.workspaceKey || resolveWorkspaceBindingKey();
@@ -12120,19 +12387,47 @@ async function ensureCursorRunning(options = {}) {
12120
12387
  const ensureOptions = { ...options, projectPath };
12121
12388
  if (process.env.CURSOR_BRIDGE_INLINE_ENSURE === "1" || process.env.CURSOR_BRIDGE_NO_SUPERVISOR === "1") {
12122
12389
  const local = await ensureCursorRunningLocal(ensureOptions);
12123
- return {
12390
+ return withLifecycle({
12124
12391
  ...local,
12125
12392
  adapterPid: process.pid,
12126
12393
  supervisorPid: null,
12127
12394
  reusedSupervisor: false,
12128
12395
  createdSupervisor: false,
12129
12396
  launchReason: local.status === "launched" ? "inline-spawned-cursor" : `inline-${local.status}`
12130
- };
12397
+ }, "inline");
12398
+ }
12399
+ try {
12400
+ const supervised = await ensureCursorViaSupervisor({
12401
+ ...ensureOptions,
12402
+ reason: options.reason || "ensureCursorRunning"
12403
+ });
12404
+ return withLifecycle(supervised, "supervised", {
12405
+ runtimeUpgradeDeferred: supervised.runtimeUpgradeDeferred === true
12406
+ });
12407
+ } catch (error2) {
12408
+ if (error2?.canAttachFallback !== true) throw error2;
12409
+ const local = await ensureCursorRunningLocal({
12410
+ ...ensureOptions,
12411
+ allowSpawn: false,
12412
+ allowProcessControl: false
12413
+ });
12414
+ return withLifecycle({
12415
+ ...local,
12416
+ adapterPid: process.pid,
12417
+ supervisorPid: null,
12418
+ reusedSupervisor: false,
12419
+ createdSupervisor: false,
12420
+ spawnMethod: null,
12421
+ launchReason: local.ok ? "attached-after-supervisor-blocked" : `attached-${local.status}`,
12422
+ supervisorError: error2 instanceof Error ? error2.message : String(error2)
12423
+ }, "attached", {
12424
+ degradedReason: error2.degradedReason || "supervisor-unavailable",
12425
+ spawnErrorCode: error2.errorCode ?? error2.returnValue ?? null,
12426
+ supervisorErrorKind: error2.errorKind || null,
12427
+ supervisorCommandLine: error2.commandLine || null,
12428
+ runtimeUpgradeDeferred: false
12429
+ });
12131
12430
  }
12132
- return ensureCursorViaSupervisor({
12133
- ...ensureOptions,
12134
- reason: options.reason || "ensureCursorRunning"
12135
- });
12136
12431
  }
12137
12432
  var isMain;
12138
12433
  var init_launch_cursor = __esm({
@@ -19478,7 +19773,7 @@ var Protocol = class {
19478
19773
  return;
19479
19774
  }
19480
19775
  const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1e3;
19481
- await new Promise((resolve6) => setTimeout(resolve6, pollInterval));
19776
+ await new Promise((resolve7) => setTimeout(resolve7, pollInterval));
19482
19777
  options?.signal?.throwIfAborted();
19483
19778
  }
19484
19779
  } catch (error2) {
@@ -19495,7 +19790,7 @@ var Protocol = class {
19495
19790
  */
19496
19791
  request(request2, resultSchema, options) {
19497
19792
  const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
19498
- return new Promise((resolve6, reject) => {
19793
+ return new Promise((resolve7, reject) => {
19499
19794
  const earlyReject = (error2) => {
19500
19795
  reject(error2);
19501
19796
  };
@@ -19573,7 +19868,7 @@ var Protocol = class {
19573
19868
  if (!parseResult.success) {
19574
19869
  reject(parseResult.error);
19575
19870
  } else {
19576
- resolve6(parseResult.data);
19871
+ resolve7(parseResult.data);
19577
19872
  }
19578
19873
  } catch (error2) {
19579
19874
  reject(error2);
@@ -19834,12 +20129,12 @@ var Protocol = class {
19834
20129
  }
19835
20130
  } catch {
19836
20131
  }
19837
- return new Promise((resolve6, reject) => {
20132
+ return new Promise((resolve7, reject) => {
19838
20133
  if (signal.aborted) {
19839
20134
  reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
19840
20135
  return;
19841
20136
  }
19842
- const timeoutId = setTimeout(resolve6, interval);
20137
+ const timeoutId = setTimeout(resolve7, interval);
19843
20138
  signal.addEventListener("abort", () => {
19844
20139
  clearTimeout(timeoutId);
19845
20140
  reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
@@ -20709,19 +21004,19 @@ var StdioServerTransport = class {
20709
21004
  this.onclose?.();
20710
21005
  }
20711
21006
  send(message) {
20712
- return new Promise((resolve6) => {
21007
+ return new Promise((resolve7) => {
20713
21008
  const json = serializeMessage(message);
20714
21009
  if (this._stdout.write(json)) {
20715
- resolve6();
21010
+ resolve7();
20716
21011
  } else {
20717
- this._stdout.once("drain", resolve6);
21012
+ this._stdout.once("drain", resolve7);
20718
21013
  }
20719
21014
  });
20720
21015
  }
20721
21016
  };
20722
21017
 
20723
21018
  // server.mjs
20724
- import { basename as basename3, dirname as dirname4, join as join6, resolve as resolve5 } from "node:path";
21019
+ import { basename as basename4, dirname as dirname5, join as join7, resolve as resolve6 } from "node:path";
20725
21020
 
20726
21021
  // node_modules/ws/wrapper.mjs
20727
21022
  var import_stream = __toESM(require_stream(), 1);
@@ -20735,12 +21030,119 @@ var import_websocket_server = __toESM(require_websocket_server(), 1);
20735
21030
 
20736
21031
  // server.mjs
20737
21032
  init_cursor_runtime();
21033
+ import http2 from "http";
21034
+ import { pathToFileURL as pathToFileURL2 } from "url";
21035
+
21036
+ // cursor-model-preferences.mjs
21037
+ import { mkdirSync as mkdirSync2, readFileSync as readFileSync2, renameSync as renameSync2, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "node:fs";
21038
+ import { homedir as homedir2 } from "node:os";
21039
+ import { basename as basename2, dirname as dirname2, join as join2, resolve as resolve2 } from "node:path";
21040
+ var CURSOR_MODEL_TARGETS = Object.freeze(["cce", "cursor_do"]);
21041
+ var CURSOR_MODEL_EFFORTS = Object.freeze(["low", "medium", "high", "xhigh", "max"]);
21042
+ function normalizeCursorModelTarget(value, fallback = "") {
21043
+ const normalized = String(value || "").trim().toLowerCase().replace(/-/g, "_");
21044
+ if (normalized === "context_engine" || normalized === "cursor_context_engine") return "cce";
21045
+ if (normalized === "do" || normalized === "delegate") return "cursor_do";
21046
+ return CURSOR_MODEL_TARGETS.includes(normalized) ? normalized : fallback;
21047
+ }
21048
+ function normalizeCursorModelEffort(value, fallback = "") {
21049
+ const normalized = String(value || "").trim().toLowerCase().replace(/[_\s]+/g, "-");
21050
+ if (normalized === "extra-high" || normalized === "extra-high-thinking") return "xhigh";
21051
+ return CURSOR_MODEL_EFFORTS.includes(normalized) ? normalized : fallback;
21052
+ }
21053
+ function cursorEffortUiValue(value) {
21054
+ const normalized = normalizeCursorModelEffort(value, "");
21055
+ return normalized === "xhigh" ? "extra-high" : normalized;
21056
+ }
21057
+ function normalizeCursorModelPreference(value, options = {}) {
21058
+ if (value == null) return null;
21059
+ const model = String(value.model || "").trim();
21060
+ if (!model) {
21061
+ if (options.allowEmpty) return null;
21062
+ throw new Error("model must not be empty");
21063
+ }
21064
+ if (model.length > 200) throw new Error("model exceeds the 200-character limit");
21065
+ const rawEffort = value.effort == null ? "" : String(value.effort).trim();
21066
+ const effort = rawEffort ? normalizeCursorModelEffort(rawEffort, "") : null;
21067
+ if (rawEffort && !effort) {
21068
+ throw new Error(`unsupported Cursor model effort: ${value.effort}; expected low, medium, high, xhigh, or max`);
21069
+ }
21070
+ return { model, effort };
21071
+ }
21072
+ function resolveCursorModelPreferencesFile(value = process.env.CURSOR_BRIDGE_MODEL_PREFERENCES_FILE) {
21073
+ const configured = String(value || "").trim();
21074
+ if (configured) return resolve2(configured);
21075
+ const configRoot = process.platform === "win32" && process.env.APPDATA ? process.env.APPDATA : process.env.XDG_CONFIG_HOME || join2(homedir2(), ".config");
21076
+ return join2(configRoot, "cursor-bridge", "model-preferences.json");
21077
+ }
21078
+ function emptyPreferences() {
21079
+ return { version: 1, targets: { cce: null, cursor_do: null }, updatedAt: null };
21080
+ }
21081
+ function readCursorModelPreferences(filePath) {
21082
+ const empty = emptyPreferences();
21083
+ if (!filePath) return empty;
21084
+ try {
21085
+ const parsed = JSON.parse(readFileSync2(filePath, "utf8"));
21086
+ const targets = parsed && typeof parsed.targets === "object" ? parsed.targets : {};
21087
+ return {
21088
+ version: 1,
21089
+ targets: {
21090
+ cce: normalizeCursorModelPreference(targets.cce, { allowEmpty: true }),
21091
+ cursor_do: normalizeCursorModelPreference(targets.cursor_do, { allowEmpty: true })
21092
+ },
21093
+ updatedAt: parsed && parsed.updatedAt ? String(parsed.updatedAt) : null
21094
+ };
21095
+ } catch (error2) {
21096
+ if (error2 && error2.code === "ENOENT") return empty;
21097
+ console.error(`[cursor-bridge] ignoring unreadable model preferences file ${filePath}: ${error2 instanceof Error ? error2.message : String(error2)}`);
21098
+ return empty;
21099
+ }
21100
+ }
21101
+ function writeCursorModelPreferences(filePath, preferences) {
21102
+ if (!filePath) throw new Error("persistent cursor_model storage is disabled for this server");
21103
+ const target = resolve2(filePath);
21104
+ const normalized = {
21105
+ version: 1,
21106
+ targets: {
21107
+ cce: normalizeCursorModelPreference(preferences && preferences.targets && preferences.targets.cce, { allowEmpty: true }),
21108
+ cursor_do: normalizeCursorModelPreference(preferences && preferences.targets && preferences.targets.cursor_do, { allowEmpty: true })
21109
+ },
21110
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
21111
+ };
21112
+ mkdirSync2(dirname2(target), { recursive: true });
21113
+ const temporary = join2(dirname2(target), `.${basename2(target)}.${process.pid}.${Date.now()}.tmp`);
21114
+ try {
21115
+ writeFileSync2(temporary, `${JSON.stringify(normalized, null, 2)}
21116
+ `, { encoding: "utf8", mode: 384 });
21117
+ renameSync2(temporary, target);
21118
+ } catch (error2) {
21119
+ rmSync2(temporary, { force: true });
21120
+ throw new Error(`failed to persist cursor_model at ${target}: ${error2 instanceof Error ? error2.message : String(error2)}`);
21121
+ }
21122
+ return normalized;
21123
+ }
21124
+ function updateCursorModelPreferences(filePath, { action, target, model, effort } = {}) {
21125
+ const normalizedAction = String(action || "show").trim().toLowerCase();
21126
+ if (!["show", "set", "reset"].includes(normalizedAction)) {
21127
+ throw new Error(`unsupported cursor_model action: ${action}; expected show, set, or reset`);
21128
+ }
21129
+ const selectedTargets = String(target || "").trim().toLowerCase() === "both" ? [...CURSOR_MODEL_TARGETS] : [normalizeCursorModelTarget(target, "")].filter(Boolean);
21130
+ if (normalizedAction !== "show" && selectedTargets.length === 0) {
21131
+ throw new Error("cursor_model set/reset requires target=cce, cursor_do, or both");
21132
+ }
21133
+ const current = readCursorModelPreferences(filePath);
21134
+ if (normalizedAction === "show") return current;
21135
+ const next = { ...current, targets: { ...current.targets } };
21136
+ const preference = normalizedAction === "set" ? normalizeCursorModelPreference({ model, effort }) : null;
21137
+ for (const selectedTarget of selectedTargets) next.targets[selectedTarget] = preference;
21138
+ return writeCursorModelPreferences(filePath, next);
21139
+ }
21140
+
21141
+ // server.mjs
20738
21142
  init_workspace_binding();
20739
21143
  init_cursor_ensure_core();
20740
21144
  init_lifecycle_paths();
20741
- import http2 from "http";
20742
- import { pathToFileURL as pathToFileURL2 } from "url";
20743
- var PLUGIN_VERSION = "5.5.0";
21145
+ var PLUGIN_VERSION = "5.6.1";
20744
21146
  var CDP_PORT2 = Number(process.env.CURSOR_BRIDGE_CDP_PORT || 9223);
20745
21147
  var ORIGIN = `http://localhost:${CDP_PORT2}`;
20746
21148
  var QUERY_TIMEOUT = Number(process.env.CURSOR_BRIDGE_TIMEOUT || 3e5);
@@ -20797,13 +21199,13 @@ var DO_DEFAULT_CONTRACT = "\n\nCompletion requirements: Work directly in the wor
20797
21199
  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
21200
  var CDP_HOST2 = "127.0.0.1";
20799
21201
  function httpJson(path) {
20800
- return new Promise((resolve6, reject) => {
21202
+ return new Promise((resolve7, reject) => {
20801
21203
  const req = http2.get({ host: CDP_HOST2, port: CDP_PORT2, path }, (res) => {
20802
21204
  let d = "";
20803
21205
  res.on("data", (c) => d += c);
20804
21206
  res.on("end", () => {
20805
21207
  try {
20806
- resolve6(JSON.parse(d));
21208
+ resolve7(JSON.parse(d));
20807
21209
  } catch {
20808
21210
  reject(new Error("CDP returned a non-JSON response"));
20809
21211
  }
@@ -21185,6 +21587,73 @@ function exprClickBoundComposerStop(agentId) {
21185
21587
  })()`;
21186
21588
  }
21187
21589
  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)});})()`;
21590
+ var MODEL_PICKER_VISIBLE_BODY = `
21591
+ const visible=(node)=>!!(node&&(node.offsetParent!==null||(node.getClientRects&&node.getClientRects().length>0)));
21592
+ const composers=[...document.querySelectorAll('.composer-bar[data-composer-id],.composer-bar,.ui-prompt-input-root')].filter(visible);
21593
+ const composer=composers[composers.length-1]||document;
21594
+ `;
21595
+ var EXPR_MODEL_PICKER_TRIGGER = `(function(){
21596
+ ${MODEL_PICKER_VISIBLE_BODY}
21597
+ const triggerSelector='.ui-model-picker__trigger,.vscode-model-picker__trigger';
21598
+ const candidates=[...composer.querySelectorAll(triggerSelector)].filter(visible);
21599
+ const trigger=candidates[candidates.length-1]||[...document.querySelectorAll(triggerSelector)].filter(visible).pop();
21600
+ if(!trigger)return JSON.stringify({found:false,state:'trigger_missing'});
21601
+ const rect=trigger.getBoundingClientRect();
21602
+ const text=String(trigger.querySelector('.ui-model-picker__trigger-text,.vscode-model-picker__trigger-text')?.innerText||trigger.innerText||'').replace(/\\s+/g,' ').trim();
21603
+ const detail=String(trigger.querySelector('.ui-model-picker__trigger-variant-suffix,.vscode-model-picker__trigger-variant-suffix')?.innerText||'').replace(/\\s+/g,' ').trim();
21604
+ 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)});
21605
+ })()`;
21606
+ var EXPR_MODEL_PICKER_ROWS = `(function(){
21607
+ ${MODEL_PICKER_VISIBLE_BODY}
21608
+ 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);
21609
+ const rows=[];
21610
+ const seen=new Set();
21611
+ for(const menu of menus){
21612
+ for(const row of menu.querySelectorAll('[data-component="menu-row"],[data-component="menu-submenu-trigger"],[role="menuitem"],[role="menuitemradio"],[role="menuitemcheckbox"]')){
21613
+ if(!visible(row)||seen.has(row))continue;
21614
+ seen.add(row);
21615
+ const rect=row.getBoundingClientRect();
21616
+ const text=String(row.innerText||row.textContent||'').replace(/\\s+/g,' ').trim();
21617
+ if(!text)continue;
21618
+ const menuTestId=String(menu.getAttribute('data-testid')||'').toLowerCase();
21619
+ let kind='control';
21620
+ if(row.querySelector('.ui-model-picker__item-content-name,.vscode-model-picker__item-content-name'))kind='model';
21621
+ else if(/^model(?:\\s|$)/i.test(text)&&row.getAttribute('aria-haspopup')==='menu')kind='model_control';
21622
+ else if(/^effort(?:\\s|$)/i.test(text)&&row.getAttribute('aria-haspopup')==='menu')kind='effort_control';
21623
+ else if(menuTestId.includes('parameter-submenu')||row.closest('[data-submenu]'))kind='parameter';
21624
+ else if(menuTestId.includes('model-picker-menu')||menuTestId.includes('model-selection'))kind='model';
21625
+ rows.push({
21626
+ text,
21627
+ kind,
21628
+ selected:row.getAttribute('data-selected')==='true'||row.getAttribute('aria-checked')==='true'||!!row.querySelector('.ui-model-picker__item-check,.ui-model-picker__param-check'),
21629
+ disabled:row.getAttribute('data-disabled')==='true'||row.getAttribute('aria-disabled')==='true',
21630
+ hasSubmenu:row.getAttribute('aria-haspopup')==='menu',
21631
+ submenu:!!row.closest('[data-submenu]'),
21632
+ x:Math.round(rect.x+rect.width/2),
21633
+ y:Math.round(rect.y+rect.height/2),
21634
+ });
21635
+ }
21636
+ }
21637
+ return JSON.stringify({open:menus.length>0,rows});
21638
+ })()`;
21639
+ function normalizeModelPickerText(value) {
21640
+ return String(value || "").trim().toLowerCase().replace(/extra[\s_-]*high/g, "xhigh").replace(/[^a-z0-9]+/g, "");
21641
+ }
21642
+ function selectModelPickerRow(rows, requested, kind = "model") {
21643
+ const wanted = normalizeModelPickerText(requested);
21644
+ if (!wanted) return null;
21645
+ const candidates = (Array.isArray(rows) ? rows : []).filter((row) => row && row.disabled !== true && (kind === "any" || row.kind === kind)).map((row) => {
21646
+ const normalized = normalizeModelPickerText(row.text);
21647
+ let score = normalized === wanted ? 1e3 : 0;
21648
+ if (!score && normalized.startsWith(wanted)) score = 800;
21649
+ if (!score && wanted.startsWith(normalized)) score = 700;
21650
+ if (!score && normalized.includes(wanted)) score = 600;
21651
+ return { row, score, distance: Math.abs(normalized.length - wanted.length) };
21652
+ }).filter((entry) => entry.score > 0).sort((a, b) => b.score - a.score || a.distance - b.distance);
21653
+ if (candidates.length === 0) return null;
21654
+ if (candidates.length > 1 && candidates[0].score === candidates[1].score && candidates[0].distance === candidates[1].distance) return null;
21655
+ return candidates[0].row;
21656
+ }
21188
21657
  var WORKSPACE_SECTION_BODY = `
21189
21658
  const headText=(el)=>String(el&&(el.innerText||el.textContent)||'').trim();
21190
21659
  const isNewAgentButton=(node)=>{
@@ -21228,7 +21697,7 @@ var WORKSPACE_SECTION_BODY = `
21228
21697
  };
21229
21698
  `;
21230
21699
  function exprCreateAgentForWorkspace(projectPath) {
21231
- const workspaceLabel = JSON.stringify(basename3(String(projectPath || "")).trim().toLowerCase());
21700
+ const workspaceLabel = JSON.stringify(basename4(String(projectPath || "")).trim().toLowerCase());
21232
21701
  return `(function(){
21233
21702
  ${WORKSPACE_SECTION_BODY}
21234
21703
  const wanted=${workspaceLabel};
@@ -21244,7 +21713,7 @@ function exprCreateAgentForWorkspace(projectPath) {
21244
21713
  })()`;
21245
21714
  }
21246
21715
  function exprInspectWorkspaceRepository(projectPath) {
21247
- const workspaceLabel = JSON.stringify(basename3(String(projectPath || "")).trim().toLowerCase());
21716
+ const workspaceLabel = JSON.stringify(basename4(String(projectPath || "")).trim().toLowerCase());
21248
21717
  return `(function(){
21249
21718
  ${WORKSPACE_SECTION_BODY}
21250
21719
  const wanted=${workspaceLabel};
@@ -21314,6 +21783,8 @@ var REACT_ADAPTER_BODY = `
21314
21783
  };
21315
21784
  const findV2Props=()=>{
21316
21785
  const found=[]; const seen=new Set();
21786
+ let globalSelectAgent=null;
21787
+ let sectionIdByAgentId=null;
21317
21788
  for(const root of document.querySelectorAll('.glass-sidebar-agent-list-container')){
21318
21789
  const nodes=[]; let n=root;
21319
21790
  for(let i=0;n&&i<24;i++,n=n.parentElement)nodes.push(n);
@@ -21324,6 +21795,8 @@ var REACT_ADAPTER_BODY = `
21324
21795
  let f=key.startsWith('__reactFiber$')?seed:{memoizedProps:seed,return:null};
21325
21796
  for(let j=0;f&&j<80;j++,f=f.return){
21326
21797
  for(const p of [f.memoizedProps,f.pendingProps,f.stateNode&&f.stateNode.props]){
21798
+ if(p&&typeof p.onSelectAgent==='function'&&!globalSelectAgent)globalSelectAgent=p.onSelectAgent;
21799
+ if(p&&p.sectionIdByAgentId&&!sectionIdByAgentId)sectionIdByAgentId=p.sectionIdByAgentId;
21327
21800
  const selectAgent=p&&(typeof p.onSelectAgent==='function'
21328
21801
  ?p.onSelectAgent
21329
21802
  :(p.rowHandlers&&typeof p.rowHandlers.onSelect==='function'?p.rowHandlers.onSelect:null));
@@ -21339,6 +21812,8 @@ var REACT_ADAPTER_BODY = `
21339
21812
  }
21340
21813
  }
21341
21814
  }
21815
+ found.globalSelectAgent=globalSelectAgent;
21816
+ found.sectionIdByAgentId=sectionIdByAgentId;
21342
21817
  return found;
21343
21818
  };
21344
21819
  const findAdapter=()=>{
@@ -21368,10 +21843,28 @@ var REACT_ADAPTER_BODY = `
21368
21843
  else if(/needs_attention/.test(status))icon='needs-attention';
21369
21844
  else if(/failed|error/.test(status))icon='warning';
21370
21845
  else if(/cancel/.test(status))icon='circle-slash';
21846
+ seen.add(selectedId);
21371
21847
  entries.push({
21372
21848
  id:selectedId,label:'',searchText:'',timestamp:0,isSelected:true,
21373
21849
  showSpinner:/in_progress|running|generating/.test(status),icon,
21374
- workspaceId:'',workspaceLabel:'',durable:false
21850
+ workspaceId:String(v2.sectionIdByAgentId instanceof Map?v2.sectionIdByAgentId.get(selectedRaw)||'':v2.sectionIdByAgentId&&readScalar(v2.sectionIdByAgentId[selectedRaw])||''),
21851
+ workspaceLabel:'',durable:!!(v2.sectionIdByAgentId&&(v2.sectionIdByAgentId instanceof Map?v2.sectionIdByAgentId.has(selectedRaw):v2.sectionIdByAgentId[selectedRaw]!==undefined)),
21852
+ registeredBySectionMap:true
21853
+ });
21854
+ }
21855
+ }
21856
+ if(v2.sectionIdByAgentId){
21857
+ const registered=v2.sectionIdByAgentId instanceof Map?[...v2.sectionIdByAgentId.entries()]:Object.entries(v2.sectionIdByAgentId);
21858
+ for(const pair of registered){
21859
+ const raw=String(pair&&pair[0]||'').replace(/^local:/,'');
21860
+ if(!raw)continue;
21861
+ const id='local:'+raw;
21862
+ if(seen.has(id))continue;
21863
+ seen.add(id);
21864
+ entries.push({
21865
+ id,label:'',searchText:'',timestamp:0,isSelected:id===selectedId,
21866
+ showSpinner:false,icon:'registered',workspaceId:String(readScalar(pair[1])||''),workspaceLabel:'',
21867
+ durable:true,registeredBySectionMap:true
21375
21868
  });
21376
21869
  }
21377
21870
  }
@@ -21384,6 +21877,8 @@ var REACT_ADAPTER_BODY = `
21384
21877
  const header=p.section.headers.find(h=>String(readScalar(h&&h.id)||'')===raw);
21385
21878
  if(header){p.onSelectAgent(header);return true;}
21386
21879
  }
21880
+ const registered=v2.sectionIdByAgentId&&(v2.sectionIdByAgentId instanceof Map?v2.sectionIdByAgentId.has(raw):v2.sectionIdByAgentId[raw]!==undefined);
21881
+ if(registered&&typeof v2.globalSelectAgent==='function'){v2.globalSelectAgent(raw);return true;}
21387
21882
  return false;
21388
21883
  }
21389
21884
  };
@@ -21481,6 +21976,13 @@ function classifyParallelTerminalIcon(icon) {
21481
21976
  function isDurablyRegisteredParallelEntry(entry) {
21482
21977
  return !!entry && entry.durable !== false && (entry.showSpinner || classifyParallelTerminalIcon(entry.icon) !== "unknown");
21483
21978
  }
21979
+ function selectPromotedFifoEntry(beforeEntries, currentAgentId, afterEntries) {
21980
+ if (!Array.isArray(beforeEntries) || !Array.isArray(afterEntries)) return null;
21981
+ if (currentAgentId && afterEntries.some((entry) => entry && entry.id === currentAgentId)) return null;
21982
+ const candidate = selectNewAgentEntry(beforeEntries, afterEntries);
21983
+ if (!candidate || candidate.id === currentAgentId || candidate.isSelected !== true) return null;
21984
+ return isDurablyRegisteredParallelEntry(candidate) ? candidate : null;
21985
+ }
21484
21986
  function uncertainSubmissionReservationScope(job, error2) {
21485
21987
  if (error2 && error2.requiresGlobalReservation) return "global";
21486
21988
  return job && job.readOnly ? "agent" : "paths";
@@ -21520,6 +22022,40 @@ function promoteAgentsWorkspaceLifecycle(lifecycle, agentsWorkspace) {
21520
22022
  retryable: false
21521
22023
  };
21522
22024
  }
22025
+ function lifecycleFromEnsureResult(result, fallbackRuntimeMode) {
22026
+ return {
22027
+ adapterPid: result.adapterPid ?? process.pid,
22028
+ supervisorPid: result.supervisorPid ?? null,
22029
+ reusedSupervisor: !!result.reusedSupervisor,
22030
+ createdSupervisor: !!result.createdSupervisor,
22031
+ launchReason: result.launchReason || result.status,
22032
+ status: result.status,
22033
+ spawnMethod: result.spawnMethod || null,
22034
+ lifecycleMode: result.lifecycleMode || null,
22035
+ persistent: result.persistent === true,
22036
+ degradedReason: result.degradedReason || null,
22037
+ spawnErrorCode: result.spawnErrorCode ?? null,
22038
+ supervisorErrorKind: result.supervisorErrorKind || null,
22039
+ capabilities: result.capabilities || null,
22040
+ cursorPid: result.cursorPid || null,
22041
+ runtimeMode: result.runtimeMode || fallbackRuntimeMode,
22042
+ projectPath: result.projectPath || null,
22043
+ targetId: result.targetId || null,
22044
+ workspaceAction: result.workspaceAction || null,
22045
+ presentation: result.presentation || null,
22046
+ windowGuard: result.windowGuard || null,
22047
+ startupWindowGuard: result.startupWindowGuard || null,
22048
+ message: result.message || null,
22049
+ needsAction: result.needsAction || null,
22050
+ nextStep: result.nextStep || null,
22051
+ retryable: result.retryable === true,
22052
+ cursorExecutable: result.cursorExecutable || null,
22053
+ cursorExecutableSource: result.cursorExecutableSource || null,
22054
+ runtimeFingerprint: result.runtimeFingerprint || null,
22055
+ runtimeScript: result.runtimeScript || null,
22056
+ runtimeUpgradeDeferred: result.runtimeUpgradeDeferred === true
22057
+ };
22058
+ }
21523
22059
  function releaseAdapterWorkingDirectory({ targetDir = defaultLifecycleDir(), chdir = process.chdir } = {}) {
21524
22060
  const target = ensureLifecycleDir(targetDir);
21525
22061
  chdir(target);
@@ -21527,10 +22063,10 @@ function releaseAdapterWorkingDirectory({ targetDir = defaultLifecycleDir(), chd
21527
22063
  }
21528
22064
  var CursorBridge = class {
21529
22065
  constructor(options = {}) {
21530
- this.adapterStartCwd = resolve5(options.adapterStartCwd || process.cwd());
22066
+ this.adapterStartCwd = resolve6(options.adapterStartCwd || process.cwd());
21531
22067
  this.environmentDelegationMode = normalizeDelegationMode(options.delegationMode || DELEGATION_MODE);
21532
22068
  this._syncDelegationState();
21533
- this.runtimeFile = options.runtimeFile === null ? null : resolve5(options.runtimeFile || resolveCursorRuntimeFile());
22069
+ this.runtimeFile = options.runtimeFile === null ? null : resolve6(options.runtimeFile || resolveCursorRuntimeFile());
21534
22070
  this.runtimeModeDefault = normalizeCursorRuntimeMode(
21535
22071
  options.runtimeModeDefault || process.env.CURSOR_BRIDGE_RUNTIME_MODE,
21536
22072
  "normal"
@@ -21541,12 +22077,14 @@ var CursorBridge = class {
21541
22077
  this.runtimeMode = normalizeCursorRuntimeMode(requestedRuntimeMode);
21542
22078
  this.runtimeModeSource = options.runtimeMode !== void 0 ? "constructor" : persistedRuntimeMode ? "persistent" : process.env.CURSOR_BRIDGE_RUNTIME_MODE ? "environment" : "default";
21543
22079
  this.runtimeModeScope = persistedRuntimeMode ? "persistent" : options.runtimeMode !== void 0 ? "constructor" : process.env.CURSOR_BRIDGE_RUNTIME_MODE ? "environment" : "default";
21544
- this.workspaceFile = options.workspaceFile === null ? null : resolve5(options.workspaceFile || resolveWorkspaceBindingFile());
22080
+ this.workspaceFile = options.workspaceFile === null ? null : resolve6(options.workspaceFile || resolveWorkspaceBindingFile());
21545
22081
  this.workspaceKey = options.workspaceKey || resolveWorkspaceBindingKey();
21546
22082
  const persistedWorkspace = options.projectPath === void 0 ? readWorkspaceBinding(this.workspaceFile, this.workspaceKey) : null;
21547
- this.projectPath = options.projectPath !== void 0 ? resolve5(String(options.projectPath)) : persistedWorkspace && persistedWorkspace.projectPath || null;
22083
+ this.projectPath = options.projectPath !== void 0 ? resolve6(String(options.projectPath)) : persistedWorkspace && persistedWorkspace.projectPath || null;
21548
22084
  this.workspaceSource = options.projectPath !== void 0 ? "constructor" : persistedWorkspace ? "persistent_init" : "auto_detect";
21549
22085
  this.workspaceUpdatedAt = persistedWorkspace && persistedWorkspace.updatedAt || null;
22086
+ this.modelPreferencesFile = options.modelPreferencesFile === null ? null : resolve6(options.modelPreferencesFile || resolveCursorModelPreferencesFile());
22087
+ this.modelPreferences = readCursorModelPreferences(this.modelPreferencesFile);
21550
22088
  this._lastPresentation = null;
21551
22089
  this.busy = false;
21552
22090
  this.queue = [];
@@ -21592,7 +22130,9 @@ var CursorBridge = class {
21592
22130
  "port-not-cursor",
21593
22131
  "no-exe",
21594
22132
  "timeout",
21595
- "workspace-not-ready"
22133
+ "workspace-not-ready",
22134
+ "external-launch-required",
22135
+ "spawn-blocked"
21596
22136
  ]);
21597
22137
  if (!lifecycle || !recoverableStatuses.has(lifecycle.status)) throw error2;
21598
22138
  return {
@@ -21654,6 +22194,36 @@ var CursorBridge = class {
21654
22194
  environmentLockedOff: this.environmentDelegationMode === "off"
21655
22195
  };
21656
22196
  }
22197
+ _refreshModelPreferences() {
22198
+ if (!this.modelPreferencesFile) return false;
22199
+ const next = readCursorModelPreferences(this.modelPreferencesFile);
22200
+ const changed = JSON.stringify(next) !== JSON.stringify(this.modelPreferences);
22201
+ this.modelPreferences = next;
22202
+ return changed;
22203
+ }
22204
+ modelPreferencesView() {
22205
+ this._refreshModelPreferences();
22206
+ return {
22207
+ modelPreferencesFile: this.modelPreferencesFile,
22208
+ modelPreferencesPersistAcrossRestart: !!this.modelPreferencesFile,
22209
+ modelPreferenceTargets: [...CURSOR_MODEL_TARGETS],
22210
+ availableEfforts: [...CURSOR_MODEL_EFFORTS],
22211
+ modelPreferences: {
22212
+ cce: this.modelPreferences.targets.cce,
22213
+ cursor_do: this.modelPreferences.targets.cursor_do
22214
+ },
22215
+ modelPreferencesUpdatedAt: this.modelPreferences.updatedAt
22216
+ };
22217
+ }
22218
+ configureModelPreferences(options = {}) {
22219
+ this.modelPreferences = updateCursorModelPreferences(this.modelPreferencesFile, options);
22220
+ return this.modelPreferencesView();
22221
+ }
22222
+ _modelPreferenceFor(target) {
22223
+ this._refreshModelPreferences();
22224
+ const preference = this.modelPreferences.targets[target];
22225
+ return preference ? { ...preference } : null;
22226
+ }
21657
22227
  _refreshPersistedRuntimeMode() {
21658
22228
  if (!this.runtimeFile || this.runtimeModeScope === "session" || this.runtimeModeScope === "constructor") {
21659
22229
  return false;
@@ -21750,7 +22320,8 @@ var CursorBridge = class {
21750
22320
  newChat: true,
21751
22321
  execution: "fifo",
21752
22322
  readOnly: true,
21753
- allowedPaths: []
22323
+ allowedPaths: [],
22324
+ modelPreference: this._modelPreferenceFor("cce")
21754
22325
  });
21755
22326
  return normalizeCceSearchResult(await job.promise);
21756
22327
  }
@@ -21802,7 +22373,8 @@ var CursorBridge = class {
21802
22373
  execution,
21803
22374
  readOnly,
21804
22375
  allowedPaths,
21805
- preferLegacyUi: options.preferLegacyUi === true
22376
+ preferLegacyUi: options.preferLegacyUi === true,
22377
+ modelPreference: this._modelPreferenceFor("cursor_do")
21806
22378
  });
21807
22379
  if (options.background !== false) return this._taskView(job);
21808
22380
  await job.promise;
@@ -21835,8 +22407,8 @@ var CursorBridge = class {
21835
22407
  const id = `cursor-${Date.now().toString(36)}-${this.nextTaskId++}`;
21836
22408
  let resolvePromise;
21837
22409
  let rejectPromise;
21838
- const promise = new Promise((resolve6, reject) => {
21839
- resolvePromise = resolve6;
22410
+ const promise = new Promise((resolve7, reject) => {
22411
+ resolvePromise = resolve7;
21840
22412
  rejectPromise = reject;
21841
22413
  });
21842
22414
  promise.catch(() => {
@@ -21852,6 +22424,8 @@ var CursorBridge = class {
21852
22424
  effectiveExecution: options.execution || "fifo",
21853
22425
  readOnly: options.readOnly === true,
21854
22426
  allowedPaths: options.allowedPaths || [],
22427
+ modelPreference: options.modelPreference ? { ...options.modelPreference } : null,
22428
+ modelSelection: options.modelPreference ? { configured: true, applied: false, ...options.modelPreference } : null,
21855
22429
  projectPath: options.projectPath || this._lastLifecycle && this._lastLifecycle.projectPath || this.projectPath || null,
21856
22430
  status: "queued",
21857
22431
  phase: "queued",
@@ -22001,42 +22575,35 @@ var CursorBridge = class {
22001
22575
  adapterStartCwd: this.adapterStartCwd,
22002
22576
  ...this.projectPath ? { projectPath: this.projectPath } : {}
22003
22577
  });
22004
- this._lastLifecycle = {
22005
- adapterPid: rr.adapterPid ?? process.pid,
22006
- supervisorPid: rr.supervisorPid ?? null,
22007
- reusedSupervisor: !!rr.reusedSupervisor,
22008
- createdSupervisor: !!rr.createdSupervisor,
22009
- launchReason: rr.launchReason || rr.status,
22010
- status: rr.status,
22011
- spawnMethod: rr.spawnMethod || null,
22012
- cursorPid: rr.cursorPid || null,
22013
- runtimeMode: rr.runtimeMode || this.runtimeMode,
22014
- projectPath: rr.projectPath || null,
22015
- targetId: rr.targetId || null,
22016
- workspaceAction: rr.workspaceAction || null,
22017
- presentation: rr.presentation || null,
22018
- message: rr.message || null,
22019
- needsAction: rr.needsAction || null,
22020
- nextStep: rr.nextStep || null,
22021
- retryable: rr.retryable === true,
22022
- cursorExecutable: rr.cursorExecutable || null,
22023
- cursorExecutableSource: rr.cursorExecutableSource || null,
22024
- runtimeFingerprint: rr.runtimeFingerprint || null,
22025
- runtimeScript: rr.runtimeScript || null
22026
- };
22578
+ this._lastLifecycle = lifecycleFromEnsureResult(rr, this.runtimeMode);
22027
22579
  if (!rr.ok && rr.status === "workspace-not-ready" && rr.projectPath) {
22028
22580
  const agentsWorkspace = await this._findAgentsWorkspace(rr.projectPath);
22029
22581
  if (agentsWorkspace) {
22030
22582
  this._lastLifecycle = promoteAgentsWorkspaceLifecycle(this._lastLifecycle, agentsWorkspace);
22031
22583
  }
22032
22584
  }
22585
+ if (rr.ok && rr.lifecycleMode === "attached" && rr.workspaceAction === "reused-agents-window" && rr.projectPath) {
22586
+ const agentsWorkspace = await this._findAgentsWorkspace(rr.projectPath);
22587
+ if (agentsWorkspace) {
22588
+ this._lastLifecycle = promoteAgentsWorkspaceLifecycle(this._lastLifecycle, agentsWorkspace);
22589
+ } else {
22590
+ this._lastLifecycle = {
22591
+ ...this._lastLifecycle,
22592
+ status: "workspace-not-ready",
22593
+ message: `Cursor is reachable, but Cursor Bridge could not verify workspace ${rr.projectPath} in the attached Agents Window.`,
22594
+ needsAction: "open_workspace_in_cursor",
22595
+ nextStep: `Open workspace ${rr.projectPath} in Cursor, then retry the same operation.`,
22596
+ retryable: true
22597
+ };
22598
+ }
22599
+ }
22033
22600
  if (this.runtimeMode === "minimal") {
22034
22601
  this._lastPresentation = rr.presentation ? { ...rr.presentation, at: (/* @__PURE__ */ new Date()).toISOString() } : await this.applyRuntimePresentation("hide");
22035
22602
  } else {
22036
22603
  await this.recoverNormalAgentsPresentation(this._lastLifecycle);
22037
22604
  }
22038
22605
  const life = "adapterPid=" + this._lastLifecycle.adapterPid + " supervisorPid=" + this._lastLifecycle.supervisorPid + " reused=" + this._lastLifecycle.reusedSupervisor + " reason=" + this._lastLifecycle.launchReason;
22039
- if (!rr.ok && this._lastLifecycle.status !== "agents-workspace-ready") {
22606
+ if ((!rr.ok || this._lastLifecycle.status === "workspace-not-ready") && this._lastLifecycle.status !== "agents-workspace-ready") {
22040
22607
  throw new Error([rr.message || `Cursor lifecycle failed: ${rr.status}`, rr.nextStep].filter(Boolean).join(" "));
22041
22608
  }
22042
22609
  if (this._lastLifecycle.status === "agents-workspace-ready") {
@@ -22202,6 +22769,8 @@ var CursorBridge = class {
22202
22769
  await this._bindFifoAgentAfterComposerReady(c, options, historyBefore);
22203
22770
  await this._bindFifoComposerIdentity(c, options);
22204
22771
  this._throwIfCancelledBeforeSend(options);
22772
+ await this._applyModelPreference(c, options.modelPreference, options);
22773
+ this._throwIfCancelledBeforeSend(options);
22205
22774
  const filled = await evalJS(c, exprFill(prompt));
22206
22775
  if (filled === "NO_INPUT" || filled === "EXEC_FAIL") throw new Error("Failed to enter the query because the input state was invalid");
22207
22776
  await sleep2(450);
@@ -22218,10 +22787,8 @@ var CursorBridge = class {
22218
22787
  await this._confirmSubmission(c, baseline.messageCount || 0, providerErrorBaseline);
22219
22788
  options.sendState = "sent";
22220
22789
  options.sentAt = options.sentAt || (/* @__PURE__ */ new Date()).toISOString();
22221
- if (!options.agentId) {
22222
- await this._bindFifoAgentAfterSend(c, options, historyBefore, providerErrorBaseline);
22223
- await this._bindFifoComposerIdentity(c, options);
22224
- }
22790
+ await this._bindFifoAgentAfterSend(c, options, historyBefore, providerErrorBaseline);
22791
+ await this._bindFifoComposerIdentity(c, options);
22225
22792
  return await this._waitComplete(
22226
22793
  c,
22227
22794
  options.timeoutMs || QUERY_TIMEOUT,
@@ -22250,6 +22817,176 @@ var CursorBridge = class {
22250
22817
  error2.preSend = true;
22251
22818
  throw error2;
22252
22819
  }
22820
+ async _readModelPickerTrigger(c) {
22821
+ try {
22822
+ return JSON.parse(await evalJS(c, EXPR_MODEL_PICKER_TRIGGER) || "{}");
22823
+ } catch {
22824
+ return { found: false, state: "trigger_unreadable" };
22825
+ }
22826
+ }
22827
+ async _readModelPickerRows(c) {
22828
+ try {
22829
+ const snapshot = JSON.parse(await evalJS(c, EXPR_MODEL_PICKER_ROWS) || "{}");
22830
+ return { open: snapshot.open === true, rows: Array.isArray(snapshot.rows) ? snapshot.rows : [] };
22831
+ } catch {
22832
+ return { open: false, rows: [] };
22833
+ }
22834
+ }
22835
+ async _clickModelPickerPoint(c, point) {
22836
+ if (!point || !Number.isFinite(Number(point.x)) || !Number.isFinite(Number(point.y))) {
22837
+ throw new Error("Cursor model picker returned an invalid target");
22838
+ }
22839
+ const x = Number(point.x);
22840
+ const y = Number(point.y);
22841
+ await c.send("Input.dispatchMouseEvent", { type: "mousePressed", x, y, button: "left", clickCount: 1 });
22842
+ await c.send("Input.dispatchMouseEvent", { type: "mouseReleased", x, y, button: "left", clickCount: 1 });
22843
+ }
22844
+ async _hoverModelPickerPoint(c, point) {
22845
+ if (!point || !Number.isFinite(Number(point.x)) || !Number.isFinite(Number(point.y))) return;
22846
+ await c.send("Input.dispatchMouseEvent", { type: "mouseMoved", x: Number(point.x), y: Number(point.y) });
22847
+ }
22848
+ async _openModelPicker(c) {
22849
+ const trigger = await this._readModelPickerTrigger(c);
22850
+ if (!trigger.found) {
22851
+ throw new Error("Cursor model picker is unavailable in the active Agent composer");
22852
+ }
22853
+ let snapshot = await this._readModelPickerRows(c);
22854
+ if (!snapshot.open) {
22855
+ await this._clickModelPickerPoint(c, trigger);
22856
+ await sleep2(450);
22857
+ snapshot = await this._readModelPickerRows(c);
22858
+ }
22859
+ if (!snapshot.open) throw new Error("Cursor model picker did not open");
22860
+ return { trigger, ...snapshot };
22861
+ }
22862
+ async _closeModelPicker(c) {
22863
+ for (let attempt = 0; attempt < 3; attempt++) {
22864
+ const snapshot = await this._readModelPickerRows(c);
22865
+ if (!snapshot.open) return;
22866
+ await c.send("Input.dispatchKeyEvent", { type: "keyDown", key: "Escape", code: "Escape", windowsVirtualKeyCode: 27, nativeVirtualKeyCode: 27 });
22867
+ await c.send("Input.dispatchKeyEvent", { type: "keyUp", key: "Escape", code: "Escape", windowsVirtualKeyCode: 27, nativeVirtualKeyCode: 27 });
22868
+ await sleep2(150);
22869
+ }
22870
+ if ((await this._readModelPickerRows(c)).open) throw new Error("Cursor model picker did not close after selection");
22871
+ }
22872
+ async _openModelPickerControl(c, snapshot, controlKind) {
22873
+ const control = (snapshot && snapshot.rows || []).find((row) => row.kind === controlKind && row.disabled !== true);
22874
+ if (!control) return snapshot;
22875
+ await this._clickModelPickerPoint(c, control);
22876
+ await sleep2(400);
22877
+ let next = await this._readModelPickerRows(c);
22878
+ const expectedKind = controlKind === "model_control" ? "model" : "parameter";
22879
+ if (!next.rows.some((row) => row.kind === expectedKind)) {
22880
+ await this._hoverModelPickerPoint(c, control);
22881
+ await sleep2(350);
22882
+ next = await this._readModelPickerRows(c);
22883
+ }
22884
+ return next;
22885
+ }
22886
+ async _findModelPickerModel(c, snapshot, requestedModel) {
22887
+ let modelRow = selectModelPickerRow(snapshot && snapshot.rows, requestedModel, "model");
22888
+ if (modelRow) return { snapshot, modelRow };
22889
+ const expanded = await this._openModelPickerControl(c, snapshot, "model_control");
22890
+ modelRow = selectModelPickerRow(expanded && expanded.rows, requestedModel, "model");
22891
+ return { snapshot: expanded, modelRow };
22892
+ }
22893
+ async _selectedEffortRow(c, modelRow, effort) {
22894
+ let snapshot = await this._readModelPickerRows(c);
22895
+ let effortRow = selectModelPickerRow(snapshot.rows, cursorEffortUiValue(effort), "parameter");
22896
+ if (!effortRow) {
22897
+ snapshot = await this._openModelPickerControl(c, snapshot, "effort_control");
22898
+ effortRow = selectModelPickerRow(snapshot.rows, cursorEffortUiValue(effort), "parameter");
22899
+ }
22900
+ if (effortRow) return effortRow;
22901
+ await this._hoverModelPickerPoint(c, modelRow);
22902
+ await sleep2(400);
22903
+ snapshot = await this._readModelPickerRows(c);
22904
+ effortRow = selectModelPickerRow(snapshot.rows, cursorEffortUiValue(effort), "parameter");
22905
+ if (!effortRow && modelRow && modelRow.hasSubmenu) {
22906
+ await this._clickModelPickerPoint(c, modelRow);
22907
+ await sleep2(350);
22908
+ snapshot = await this._readModelPickerRows(c);
22909
+ effortRow = selectModelPickerRow(snapshot.rows, cursorEffortUiValue(effort), "parameter");
22910
+ }
22911
+ return effortRow;
22912
+ }
22913
+ async _applyModelPreference(c, preference, job) {
22914
+ if (!preference) {
22915
+ if (job) job.modelSelection = null;
22916
+ return null;
22917
+ }
22918
+ const requestedModel = String(preference.model || "").trim();
22919
+ const requestedEffort = preference.effort ? normalizeCursorModelEffort(preference.effort, "") : null;
22920
+ const opened = await this._openModelPicker(c);
22921
+ let located = await this._findModelPickerModel(c, opened, requestedModel);
22922
+ let modelRow = located.modelRow;
22923
+ if (!modelRow) {
22924
+ throw new Error(`Configured Cursor model is unavailable or ambiguous: ${requestedModel}`);
22925
+ }
22926
+ let selectedEffortRow = null;
22927
+ if (requestedEffort && modelRow.hasSubmenu) {
22928
+ selectedEffortRow = await this._selectedEffortRow(c, modelRow, requestedEffort);
22929
+ if (!selectedEffortRow) {
22930
+ throw new Error(`Cursor model ${requestedModel} does not expose effort ${requestedEffort}`);
22931
+ }
22932
+ if (!selectedEffortRow.selected || !modelRow.selected) {
22933
+ await this._clickModelPickerPoint(c, selectedEffortRow);
22934
+ await sleep2(550);
22935
+ }
22936
+ } else if (!modelRow.selected) {
22937
+ await this._clickModelPickerPoint(c, modelRow);
22938
+ await sleep2(550);
22939
+ }
22940
+ let trigger = await this._readModelPickerTrigger(c);
22941
+ if (!trigger.found || !normalizeModelPickerText(trigger.text).includes(normalizeModelPickerText(requestedModel))) {
22942
+ const reopened = await this._openModelPicker(c);
22943
+ located = await this._findModelPickerModel(c, reopened, requestedModel);
22944
+ const selected = selectModelPickerRow(located.snapshot.rows.filter((row) => row.selected), requestedModel, "model");
22945
+ if (!selected) throw new Error(`Cursor did not confirm configured model ${requestedModel}`);
22946
+ modelRow = selected;
22947
+ }
22948
+ let effectiveEffort = null;
22949
+ if (requestedEffort) {
22950
+ const reopened = await this._openModelPicker(c);
22951
+ located = await this._findModelPickerModel(c, reopened, requestedModel);
22952
+ modelRow = located.modelRow;
22953
+ if (!modelRow) throw new Error(`Cursor model row disappeared while applying effort: ${requestedModel}`);
22954
+ let effortRow = await this._selectedEffortRow(c, modelRow, requestedEffort);
22955
+ if (!effortRow) {
22956
+ throw new Error(`Cursor model ${requestedModel} does not expose effort ${requestedEffort}`);
22957
+ }
22958
+ if (!effortRow.selected) {
22959
+ await this._clickModelPickerPoint(c, effortRow);
22960
+ await sleep2(450);
22961
+ }
22962
+ trigger = await this._readModelPickerTrigger(c);
22963
+ const detailMatches = normalizeModelPickerText(`${trigger.detail || ""} ${trigger.text || ""}`).includes(normalizeModelPickerText(requestedEffort));
22964
+ if (!detailMatches) {
22965
+ const verify = await this._openModelPicker(c);
22966
+ const verifiedModel = await this._findModelPickerModel(c, verify, requestedModel);
22967
+ const selectedModel = verifiedModel.modelRow;
22968
+ effortRow = await this._selectedEffortRow(c, selectedModel, requestedEffort);
22969
+ if (!effortRow || !effortRow.selected) {
22970
+ throw new Error(`Cursor did not confirm effort ${requestedEffort} for model ${requestedModel}`);
22971
+ }
22972
+ }
22973
+ effectiveEffort = requestedEffort;
22974
+ }
22975
+ await this._closeModelPicker(c);
22976
+ trigger = await this._readModelPickerTrigger(c);
22977
+ const result = {
22978
+ configured: true,
22979
+ applied: true,
22980
+ requestedModel,
22981
+ requestedEffort,
22982
+ effectiveModel: trigger.text || modelRow.text,
22983
+ effectiveEffort,
22984
+ pickerDetail: trigger.detail || null,
22985
+ verifiedAt: (/* @__PURE__ */ new Date()).toISOString()
22986
+ };
22987
+ if (job) job.modelSelection = result;
22988
+ return result;
22989
+ }
22253
22990
  async _ensureChatPanel(c) {
22254
22991
  let vis = await evalJS(c, EXPR_VISIBLE);
22255
22992
  if (!vis) {
@@ -22272,7 +23009,7 @@ var CursorBridge = class {
22272
23009
  const created = JSON.parse(await evalJS(c, exprCreateAgentForWorkspace(options.projectPath)) || "{}");
22273
23010
  if (!created.ok) {
22274
23011
  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 || basename3(options.projectPath)}${available}`);
23012
+ throw new Error(`Cursor Agents workspace binding failed: ${created.state || "unknown"}; wanted=${created.wanted || basename4(options.projectPath)}${available}`);
22276
23013
  }
22277
23014
  await sleep2(1100);
22278
23015
  return true;
@@ -22383,12 +23120,31 @@ var CursorBridge = class {
22383
23120
  }
22384
23121
  }
22385
23122
  async _bindFifoAgentAfterSend(c, job, beforeEntries, providerErrorBaseline) {
22386
- if (!this._canBindFifoHistory(job) || !Array.isArray(beforeEntries) || job.agentId) return;
22387
- for (let i = 0; i < 24 && !job.agentId; i++) {
23123
+ if (!this._canBindFifoHistory(job) || !Array.isArray(beforeEntries)) return;
23124
+ for (let i = 0; i < 24; i++) {
22388
23125
  await sleep2(350);
22389
23126
  await this._throwIfNewProviderError(c, providerErrorBaseline);
22390
- const candidate = await this._resolveNewAgent(c, beforeEntries, { requireActive: true });
22391
- if (candidate) this._applyAgentIdentity(job, candidate);
23127
+ let entries = null;
23128
+ try {
23129
+ entries = await this._readAgentEntries(c);
23130
+ } catch {
23131
+ }
23132
+ if (!Array.isArray(entries)) continue;
23133
+ const promoted = selectPromotedFifoEntry(beforeEntries, job.agentId, entries);
23134
+ if (promoted) {
23135
+ job.provisionalAgentId = job.agentId || null;
23136
+ this._applyAgentIdentity(job, promoted);
23137
+ return;
23138
+ }
23139
+ const current = job.agentId ? entries.find((entry) => entry && entry.id === job.agentId) : null;
23140
+ if (current && isDurablyRegisteredParallelEntry(current)) return;
23141
+ if (!job.agentId) {
23142
+ const candidate = selectNewAgentEntry(beforeEntries, entries);
23143
+ if (candidate && isDurablyRegisteredParallelEntry(candidate)) {
23144
+ this._applyAgentIdentity(job, candidate);
23145
+ return;
23146
+ }
23147
+ }
22392
23148
  }
22393
23149
  }
22394
23150
  async _confirmSubmission(c, baselineCount = 0, providerErrorBaseline = "") {
@@ -22481,6 +23237,8 @@ var CursorBridge = class {
22481
23237
  await this._closeHistory(c);
22482
23238
  await this._ensureChatPanel(c);
22483
23239
  this._throwIfCancelledBeforeSend(job);
23240
+ await this._applyModelPreference(c, job.modelPreference, job);
23241
+ this._throwIfCancelledBeforeSend(job);
22484
23242
  const filled = await evalJS(c, exprFill(job.prompt));
22485
23243
  if (filled === "NO_INPUT" || filled === "EXEC_FAIL") throw new Error("Failed to enter the parallel_agent task");
22486
23244
  await sleep2(350);
@@ -22537,8 +23295,25 @@ var CursorBridge = class {
22537
23295
  const c = makeClient(page.webSocketDebuggerUrl);
22538
23296
  await c.ready;
22539
23297
  try {
22540
- const entries = await this._readAgentEntries(c);
22541
- return entries.find((e) => e.id === job.agentId) || null;
23298
+ let entries = await this._readAgentEntries(c);
23299
+ let entry = entries.find((e) => e.id === job.agentId) || null;
23300
+ if (!entry && (job.execution === "fifo" || job.effectiveExecution === "fifo")) {
23301
+ const promoted = selectPromotedFifoEntry(job.historyBeforeEntries, job.agentId, entries);
23302
+ if (promoted) {
23303
+ job.provisionalAgentId = job.agentId || null;
23304
+ this._applyAgentIdentity(job, promoted);
23305
+ entry = promoted;
23306
+ }
23307
+ }
23308
+ if (entry && entry.registeredBySectionMap && classifyParallelTerminalIcon(entry.icon) === "unknown") {
23309
+ const opened = await evalJS(c, exprOpenAgent(job.agentId));
23310
+ if (opened === "OPENED") {
23311
+ await sleep2(350);
23312
+ entries = await this._readAgentEntries(c);
23313
+ entry = entries.find((e) => e.id === job.agentId) || entry;
23314
+ }
23315
+ }
23316
+ return entry;
22542
23317
  } finally {
22543
23318
  c.close();
22544
23319
  }
@@ -23287,8 +24062,11 @@ var CursorBridge = class {
23287
24062
  effectiveExecution: job.effectiveExecution,
23288
24063
  readOnly: job.readOnly,
23289
24064
  allowedPaths: job.allowedPaths,
24065
+ modelPreference: job.modelPreference,
24066
+ modelSelection: job.modelSelection,
23290
24067
  projectPath: job.projectPath,
23291
24068
  agentId: job.agentId,
24069
+ provisionalAgentId: job.provisionalAgentId || null,
23292
24070
  agentLabel: job.agentLabel,
23293
24071
  targetId: job.targetId,
23294
24072
  targetUiFlavor: job.targetUiFlavor,
@@ -23335,8 +24113,8 @@ var CursorBridge = class {
23335
24113
  async status(taskId = "") {
23336
24114
  if (taskId) {
23337
24115
  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) };
24116
+ if (!job) return { found: false, taskId: String(taskId), ...this.workspaceView(), ...this.delegationView(), ...this.runtimeModeView(), ...this.modelPreferencesView() };
24117
+ return { found: true, ...this.workspaceView(), ...this.delegationView(), ...this.runtimeModeView(), ...this.modelPreferencesView(), ...this._taskView(job, true) };
23340
24118
  }
23341
24119
  const parallelRunning = this.activeParallel.size;
23342
24120
  const uiBusy = this.busy;
@@ -23347,6 +24125,7 @@ var CursorBridge = class {
23347
24125
  ...this.workspaceView(),
23348
24126
  ...this.delegationView(),
23349
24127
  ...this.runtimeModeView(),
24128
+ ...this.modelPreferencesView(),
23350
24129
  busy: uiBusy || parallelRunning > 0 || this.queue.length > 0,
23351
24130
  uiBusy,
23352
24131
  parallelRunning,
@@ -23366,6 +24145,11 @@ var CursorBridge = class {
23366
24145
  launchReason: null,
23367
24146
  status: null,
23368
24147
  spawnMethod: null,
24148
+ lifecycleMode: null,
24149
+ persistent: null,
24150
+ degradedReason: null,
24151
+ spawnErrorCode: null,
24152
+ capabilities: null,
23369
24153
  cursorPid: null,
23370
24154
  runtimeMode: this.runtimeMode,
23371
24155
  presentation: null
@@ -23451,9 +24235,23 @@ function buildToolDefinitions(bridgeInstance) {
23451
24235
  required: ["mode"]
23452
24236
  }
23453
24237
  },
24238
+ {
24239
+ name: "cursor_model",
24240
+ 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.",
24241
+ inputSchema: {
24242
+ type: "object",
24243
+ properties: {
24244
+ 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." },
24245
+ 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." },
24246
+ model: { type: "string", description: "Required for set. Use a model ID or display name currently available in the signed-in Cursor account." },
24247
+ effort: { type: "string", enum: [...CURSOR_MODEL_EFFORTS], description: "Optional reasoning effort for set. Omit it to use that model's Cursor default." }
24248
+ },
24249
+ required: ["action"]
24250
+ }
24251
+ },
23454
24252
  {
23455
24253
  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 current in-memory state and any result already collected; this tool never switches Agents, reconciles, or stops work.",
24254
+ 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
24255
  inputSchema: { type: "object", properties: { task_id: { type: "string", description: "A task ID returned by cursor_do. Omit it for an overall status view." } } }
23458
24256
  }
23459
24257
  ].filter(Boolean);
@@ -23461,7 +24259,7 @@ function buildToolDefinitions(bridgeInstance) {
23461
24259
  var ADAPTER_START_CWD = process.cwd();
23462
24260
  var bridge = new CursorBridge({ adapterStartCwd: ADAPTER_START_CWD });
23463
24261
  var server = new Server(
23464
- { name: "cursor-bridge", version: "5.5.0" },
24262
+ { name: "cursor-bridge", version: "5.6.1" },
23465
24263
  { capabilities: { tools: { listChanged: true } } }
23466
24264
  );
23467
24265
  async function ensureBridgeCursor(targetBridge, reason) {
@@ -23473,31 +24271,7 @@ async function ensureBridgeCursor(targetBridge, reason) {
23473
24271
  adapterStartCwd: targetBridge.adapterStartCwd,
23474
24272
  ...targetBridge.projectPath ? { projectPath: targetBridge.projectPath } : {}
23475
24273
  });
23476
- targetBridge._lastLifecycle = {
23477
- adapterPid: r.adapterPid ?? process.pid,
23478
- supervisorPid: r.supervisorPid ?? null,
23479
- reusedSupervisor: !!r.reusedSupervisor,
23480
- createdSupervisor: !!r.createdSupervisor,
23481
- launchReason: r.launchReason || r.status,
23482
- status: r.status,
23483
- spawnMethod: r.spawnMethod || null,
23484
- cursorPid: r.cursorPid || null,
23485
- runtimeMode: r.runtimeMode || targetBridge.runtimeMode,
23486
- projectPath: r.projectPath || null,
23487
- targetId: r.targetId || null,
23488
- workspaceAction: r.workspaceAction || null,
23489
- presentation: r.presentation || null,
23490
- windowGuard: r.windowGuard || null,
23491
- startupWindowGuard: r.startupWindowGuard || null,
23492
- message: r.message || null,
23493
- needsAction: r.needsAction || null,
23494
- nextStep: r.nextStep || null,
23495
- retryable: r.retryable === true,
23496
- cursorExecutable: r.cursorExecutable || null,
23497
- cursorExecutableSource: r.cursorExecutableSource || null,
23498
- runtimeFingerprint: r.runtimeFingerprint || null,
23499
- runtimeScript: r.runtimeScript || null
23500
- };
24274
+ targetBridge._lastLifecycle = lifecycleFromEnsureResult(r, targetBridge.runtimeMode);
23501
24275
  if (targetBridge.runtimeMode === "minimal") {
23502
24276
  targetBridge._lastPresentation = r.presentation ? { ...r.presentation, at: (/* @__PURE__ */ new Date()).toISOString() } : await targetBridge.applyRuntimePresentation("hide");
23503
24277
  }
@@ -23550,6 +24324,15 @@ server.setRequestHandler(CallToolRequestSchema, async (request2) => {
23550
24324
  }
23551
24325
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
23552
24326
  }
24327
+ if (name === "cursor_model") {
24328
+ const result = bridge.configureModelPreferences({
24329
+ action: args && args.action,
24330
+ target: args && args.target,
24331
+ model: args && args.model,
24332
+ effort: args && args.effort
24333
+ });
24334
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
24335
+ }
23553
24336
  if (name === "cursor_status") {
23554
24337
  const statusMs = Math.max(1e3, Number(process.env.CURSOR_BRIDGE_STATUS_TIMEOUT || 8e3));
23555
24338
  let result;
@@ -23607,11 +24390,15 @@ if (isMain2) {
23607
24390
  });
23608
24391
  }
23609
24392
  export {
24393
+ CURSOR_MODEL_EFFORTS,
24394
+ CURSOR_MODEL_TARGETS,
23610
24395
  CURSOR_RUNTIME_MODES,
23611
24396
  CursorBridge,
23612
24397
  EXPR_CLICK_SEND,
23613
24398
  EXPR_FIND_NEWAGENT,
23614
24399
  EXPR_HISTORY_ENTRIES,
24400
+ EXPR_MODEL_PICKER_ROWS,
24401
+ EXPR_MODEL_PICKER_TRIGGER,
23615
24402
  EXPR_PAGE_CAPABILITIES,
23616
24403
  EXPR_PROVIDER_ERROR,
23617
24404
  EXPR_VISIBLE,
@@ -23635,16 +24422,20 @@ export {
23635
24422
  isTargetedStopConfirmed,
23636
24423
  normalizeAllowedPath,
23637
24424
  normalizeCceSearchResult,
24425
+ normalizeCursorModelEffort,
23638
24426
  normalizeCursorRuntimeMode,
23639
24427
  normalizeDelegationMode,
24428
+ normalizeModelPickerText,
23640
24429
  pathsOverlap,
23641
24430
  promoteAgentsWorkspaceLifecycle,
23642
24431
  providerErrorSignature,
23643
24432
  releaseAdapterWorkingDirectory,
23644
24433
  scoreCursorPageCandidate,
23645
24434
  selectCursorPageCandidate,
24435
+ selectModelPickerRow,
23646
24436
  selectNewAgentEntry,
23647
24437
  selectPageForUiPreference,
24438
+ selectPromotedFifoEntry,
23648
24439
  shouldAutoLaunchCursor,
23649
24440
  shouldRecoverNormalAgentsPresentation,
23650
24441
  summarizeCdpPages,