authorgravatar for saiansh2525@gmail.comYash Singh <saiansh2525@gmail.com> 2026-09-12 21:19:24-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-09-12 21:19:24-05:00
logc29976458a7dbbb61c83b3d06ea894869b718607
treee36cb9be97c6dbc1dfe84df344cde5163a82e3ca
parent0e0ddaeedf30698bec131caf040a8e8d7b2e3f37
signature Signed by PGP key B5690EEEBB952194

fix(server): open Cursor links in classic IDE mode (#11498)


2 files changed, 91 insertions(+), 0 deletions(-)

apps/server/src/process/externalLauncher.test.ts+89
...@@ -159,6 +159,95 @@ it.effect("launches an installed editor with platform-safe arguments", () =>...@@ -159,6 +159,95 @@ it.effect("launches an installed editor with platform-safe arguments", () =>
159 }).pipe(Effect.scoped, Effect.provide(NodeServices.layer)),159 }).pipe(Effect.scoped, Effect.provide(NodeServices.layer)),
160);160);
161161
162for (const platform of ["darwin", "linux"] as const) {
163 it.effect.skipIf(windowsHost)(`launches Cursor in classic IDE mode on ${platform}`, () =>
164 Effect.gen(function* () {
165 const fileSystem = yield* FileSystem.FileSystem;
166 const path = yield* Path.Path;
167 const binDir = yield* fileSystem.makeTempDirectoryScoped({ prefix: "t3-editors-" });
168 const cursorPath = path.join(binDir, "cursor");
169 yield* fileSystem.writeFileString(cursorPath, "#!/bin/sh\n");
170 yield* fileSystem.chmod(cursorPath, 0o755);
171
172 const spawned: ChildProcess.StandardCommand[] = [];
173 yield* Effect.gen(function* () {
174 const launcher = yield* ExternalLauncher.ExternalLauncher;
175 for (const cwd of [
176 "/workspace with spaces",
177 "/workspace with spaces/src/index.ts",
178 "/workspace with spaces/src/index.ts:12",
179 "/workspace with spaces/src/index.ts:12:4",
180 ]) {
181 yield* launcher.launchEditor({ editor: "cursor", cwd });
182 }
183 }).pipe(
184 Effect.provide(
185 testLayer({
186 platform,
187 env: { PATH: binDir },
188 onSpawn: (command) => spawned.push(command),
189 }),
190 ),
191 );
192
193 assert.deepEqual(
194 spawned.map((command) => ({ command: command.command, args: command.args })),
195 [
196 { command: "cursor", args: ["--classic", "/workspace with spaces"] },
197 { command: "cursor", args: ["--classic", "/workspace with spaces/src/index.ts"] },
198 {
199 command: "cursor",
200 args: ["--classic", "--goto", "/workspace with spaces/src/index.ts:12"],
201 },
202 {
203 command: "cursor",
204 args: ["--classic", "--goto", "/workspace with spaces/src/index.ts:12:4"],
205 },
206 ],
207 );
208 }).pipe(Effect.scoped, Effect.provide(NodeServices.layer)),
209 );
210}
211
212it.effect("launches Cursor in classic IDE mode through the Windows command shim", () =>
213 Effect.gen(function* () {
214 const fileSystem = yield* FileSystem.FileSystem;
215 const path = yield* Path.Path;
216 const binDir = yield* fileSystem.makeTempDirectoryScoped({ prefix: "t3-editors-" });
217 yield* fileSystem.writeFileString(path.join(binDir, "cursor.CMD"), "@echo off\r\n");
218
219 let spawned: ChildProcess.StandardCommand | undefined;
220 yield* Effect.gen(function* () {
221 const launcher = yield* ExternalLauncher.ExternalLauncher;
222 yield* launcher.launchEditor({
223 editor: "cursor",
224 cwd: "C:\\workspace with spaces\\src\\index.ts:12:4",
225 });
226 }).pipe(
227 Effect.provide(
228 testLayer({
229 platform: "win32",
230 env: { PATH: binDir, PATHEXT: ".COM;.EXE;.BAT;.CMD" },
231 resolveExecutable: (command) =>
232 command === "cursor" ? "C:\\Program Files\\Cursor\\bin\\cursor.CMD" : command,
233 onSpawn: (command) => {
234 spawned = command;
235 },
236 }),
237 ),
238 );
239
240 assert.ok(spawned);
241 assert.equal(spawned.command, '^"C:\\Program^ Files\\Cursor\\bin\\cursor.CMD^"');
242 assert.deepEqual(spawned.args, [
243 '^"--classic^"',
244 '^"--goto^"',
245 '^"C:\\workspace^ with^ spaces\\src\\index.ts:12:4^"',
246 ]);
247 assert.equal(spawned.options.shell, true);
248 }).pipe(Effect.scoped, Effect.provide(NodeServices.layer)),
249);
250
162it.effect.skipIf(windowsHost)("reveals a file in Finder with open -R on macOS", () =>251it.effect.skipIf(windowsHost)("reveals a file in Finder with open -R on macOS", () =>
163 Effect.gen(function* () {252 Effect.gen(function* () {
164 const fileSystem = yield* FileSystem.FileSystem;253 const fileSystem = yield* FileSystem.FileSystem;
packages/contracts/src/editor.ts+2
...@@ -24,6 +24,8 @@ export const EDITORS = [...@@ -24,6 +24,8 @@ export const EDITORS = [
24 id: "cursor",24 id: "cursor",
25 label: "Cursor",25 label: "Cursor",
26 commands: ["cursor"],26 commands: ["cursor"],
27 // File and workspace opens must target the IDE even when the Agents Window is active.
28 baseArgs: ["--classic"],
27 launchStyle: "goto",29 launchStyle: "goto",
28 remoteScheme: "cursor",30 remoteScheme: "cursor",
29 },31 },