From c29976458a7dbbb61c83b3d06ea894869b718607 Mon Sep 17 00:00:00 2001 From: Yash Singh Date: Sat, 12 Sep 2026 21:19:24 -0500 Subject: [PATCH] fix(server): open Cursor links in classic IDE mode (#11498) --- .../src/process/externalLauncher.test.ts | 89 +++++++++++++++++++ packages/contracts/src/editor.ts | 2 + 2 files changed, 91 insertions(+) diff --git a/apps/server/src/process/externalLauncher.test.ts b/apps/server/src/process/externalLauncher.test.ts index 2ae1684b67d4755ffa7565eec2e17b034675b2d0..b7092d70f0e22570482dd2a8c5ff2f7c29f8cd7e 100644 --- a/apps/server/src/process/externalLauncher.test.ts +++ b/apps/server/src/process/externalLauncher.test.ts @@ -159,6 +159,95 @@ it.effect("launches an installed editor with platform-safe arguments", () => }).pipe(Effect.scoped, Effect.provide(NodeServices.layer)), ); +for (const platform of ["darwin", "linux"] as const) { + it.effect.skipIf(windowsHost)(`launches Cursor in classic IDE mode on ${platform}`, () => + Effect.gen(function* () { + const fileSystem = yield* FileSystem.FileSystem; + const path = yield* Path.Path; + const binDir = yield* fileSystem.makeTempDirectoryScoped({ prefix: "t3-editors-" }); + const cursorPath = path.join(binDir, "cursor"); + yield* fileSystem.writeFileString(cursorPath, "#!/bin/sh\n"); + yield* fileSystem.chmod(cursorPath, 0o755); + + const spawned: ChildProcess.StandardCommand[] = []; + yield* Effect.gen(function* () { + const launcher = yield* ExternalLauncher.ExternalLauncher; + for (const cwd of [ + "/workspace with spaces", + "/workspace with spaces/src/index.ts", + "/workspace with spaces/src/index.ts:12", + "/workspace with spaces/src/index.ts:12:4", + ]) { + yield* launcher.launchEditor({ editor: "cursor", cwd }); + } + }).pipe( + Effect.provide( + testLayer({ + platform, + env: { PATH: binDir }, + onSpawn: (command) => spawned.push(command), + }), + ), + ); + + assert.deepEqual( + spawned.map((command) => ({ command: command.command, args: command.args })), + [ + { command: "cursor", args: ["--classic", "/workspace with spaces"] }, + { command: "cursor", args: ["--classic", "/workspace with spaces/src/index.ts"] }, + { + command: "cursor", + args: ["--classic", "--goto", "/workspace with spaces/src/index.ts:12"], + }, + { + command: "cursor", + args: ["--classic", "--goto", "/workspace with spaces/src/index.ts:12:4"], + }, + ], + ); + }).pipe(Effect.scoped, Effect.provide(NodeServices.layer)), + ); +} + +it.effect("launches Cursor in classic IDE mode through the Windows command shim", () => + Effect.gen(function* () { + const fileSystem = yield* FileSystem.FileSystem; + const path = yield* Path.Path; + const binDir = yield* fileSystem.makeTempDirectoryScoped({ prefix: "t3-editors-" }); + yield* fileSystem.writeFileString(path.join(binDir, "cursor.CMD"), "@echo off\r\n"); + + let spawned: ChildProcess.StandardCommand | undefined; + yield* Effect.gen(function* () { + const launcher = yield* ExternalLauncher.ExternalLauncher; + yield* launcher.launchEditor({ + editor: "cursor", + cwd: "C:\\workspace with spaces\\src\\index.ts:12:4", + }); + }).pipe( + Effect.provide( + testLayer({ + platform: "win32", + env: { PATH: binDir, PATHEXT: ".COM;.EXE;.BAT;.CMD" }, + resolveExecutable: (command) => + command === "cursor" ? "C:\\Program Files\\Cursor\\bin\\cursor.CMD" : command, + onSpawn: (command) => { + spawned = command; + }, + }), + ), + ); + + assert.ok(spawned); + assert.equal(spawned.command, '^"C:\\Program^ Files\\Cursor\\bin\\cursor.CMD^"'); + assert.deepEqual(spawned.args, [ + '^"--classic^"', + '^"--goto^"', + '^"C:\\workspace^ with^ spaces\\src\\index.ts:12:4^"', + ]); + assert.equal(spawned.options.shell, true); + }).pipe(Effect.scoped, Effect.provide(NodeServices.layer)), +); + it.effect.skipIf(windowsHost)("reveals a file in Finder with open -R on macOS", () => Effect.gen(function* () { const fileSystem = yield* FileSystem.FileSystem; diff --git a/packages/contracts/src/editor.ts b/packages/contracts/src/editor.ts index 0680a398879ea79657a62d987b48ec2ed2677bdb..88028b79699116c21791bb16efec343c82a86f8c 100644 --- a/packages/contracts/src/editor.ts +++ b/packages/contracts/src/editor.ts @@ -24,6 +24,8 @@ export const EDITORS = [ id: "cursor", label: "Cursor", commands: ["cursor"], + // File and workspace opens must target the IDE even when the Agents Window is active. + baseArgs: ["--classic"], launchStyle: "goto", remoteScheme: "cursor", }, -- 2.54.0