diff --git a/apps/server/scripts/cursor-acp-model-mismatch-probe.ts b/apps/server/scripts/cursor-acp-model-mismatch-probe.ts index b36c2b2d496..7e4e88aeb2b 100644 --- a/apps/server/scripts/cursor-acp-model-mismatch-probe.ts +++ b/apps/server/scripts/cursor-acp-model-mismatch-probe.ts @@ -62,7 +62,7 @@ const promptText = NodeProcess.argv[4] ?? "helo"; const targetReasoning = NodeProcess.env.CURSOR_REASONING ?? ""; const targetContext = NodeProcess.env.CURSOR_CONTEXT ?? ""; const targetFast = NodeProcess.env.CURSOR_FAST ?? ""; -const agentBin = NodeProcess.env.CURSOR_AGENT_BIN ?? "agent"; +const agentBin = NodeProcess.env.CURSOR_AGENT_BIN ?? "cursor-agent"; const promptWaitMs = Number(NodeProcess.env.CURSOR_PROMPT_WAIT_MS ?? "4000"); const requestTimeoutMs = Number(NodeProcess.env.CURSOR_REQUEST_TIMEOUT_MS ?? "20000"); diff --git a/apps/server/src/provider/Drivers/CursorDriver.ts b/apps/server/src/provider/Drivers/CursorDriver.ts index c394a7d1b43..60a370ea80c 100644 --- a/apps/server/src/provider/Drivers/CursorDriver.ts +++ b/apps/server/src/provider/Drivers/CursorDriver.ts @@ -58,7 +58,7 @@ const UPDATE = makeStaticProviderMaintenanceResolver( makeProviderMaintenanceCapabilities({ provider: DRIVER_KIND, packageName: null, - updateExecutable: "agent", + updateExecutable: "cursor-agent", updateArgs: ["update"], updateLockKey: "cursor-agent", }), diff --git a/apps/server/src/provider/Layers/CursorProvider.test.ts b/apps/server/src/provider/Layers/CursorProvider.test.ts index 60a7312eea3..738871baf08 100644 --- a/apps/server/src/provider/Layers/CursorProvider.test.ts +++ b/apps/server/src/provider/Layers/CursorProvider.test.ts @@ -289,7 +289,7 @@ const parameterizedClaudeModelOptionConfigOptions = [ const baseCursorSettings: CursorSettings = { enabled: true, - binaryPath: "agent", + binaryPath: "cursor-agent", apiEndpoint: "", customModels: [], }; diff --git a/apps/server/src/provider/Layers/ProviderInstanceRegistryLive.test.ts b/apps/server/src/provider/Layers/ProviderInstanceRegistryLive.test.ts index dbfa7faffea..73390450efa 100644 --- a/apps/server/src/provider/Layers/ProviderInstanceRegistryLive.test.ts +++ b/apps/server/src/provider/Layers/ProviderInstanceRegistryLive.test.ts @@ -76,7 +76,7 @@ const makeClaudeConfig = (overrides: Partial): ClaudeSettings => const makeCursorConfig = (overrides: Partial): CursorSettings => ({ enabled: false, - binaryPath: "agent", + binaryPath: "cursor-agent", apiEndpoint: "", customModels: [], ...overrides, diff --git a/apps/server/src/provider/Layers/ProviderRegistry.test.ts b/apps/server/src/provider/Layers/ProviderRegistry.test.ts index b3ab1145495..9a46d8a8056 100644 --- a/apps/server/src/provider/Layers/ProviderRegistry.test.ts +++ b/apps/server/src/provider/Layers/ProviderRegistry.test.ts @@ -1396,7 +1396,7 @@ it.layer(Layer.mergeAll(NodeServices.layer, ServerSettingsModule.layerTest(), Te Layer.provideMerge(OpenCodeRuntime.OpenCodeRuntimeLive), Layer.provideMerge( mockCommandSpawnerLayer((command, args) => { - if (command === "agent") { + if (command === "cursor-agent") { cursorSpawned = true; } const joined = args.join(" "); diff --git a/apps/server/src/provider/acp/CursorAcpCliProbe.test.ts b/apps/server/src/provider/acp/CursorAcpCliProbe.test.ts index eebe5ddd92e..ae2e7231b36 100644 --- a/apps/server/src/provider/acp/CursorAcpCliProbe.test.ts +++ b/apps/server/src/provider/acp/CursorAcpCliProbe.test.ts @@ -21,7 +21,7 @@ describe.runIf(process.env.T3_CURSOR_ACP_PROBE === "1")("Cursor ACP CLI probe", Effect.provide( AcpSessionRuntime.layer({ spawn: { - command: "agent", + command: "cursor-agent", args: ["acp"], cwd: process.cwd(), }, @@ -77,7 +77,7 @@ describe.runIf(process.env.T3_CURSOR_ACP_PROBE === "1")("Cursor ACP CLI probe", AcpSessionRuntime.layer({ authMethodId: "cursor_login", spawn: { - command: "agent", + command: "cursor-agent", args: ["acp"], cwd: process.cwd(), }, @@ -133,7 +133,7 @@ describe.runIf(process.env.T3_CURSOR_ACP_PROBE === "1")("Cursor ACP CLI probe", AcpSessionRuntime.layer({ authMethodId: "cursor_login", spawn: { - command: "agent", + command: "cursor-agent", args: ["acp"], cwd: process.cwd(), }, diff --git a/apps/server/src/provider/acp/CursorAcpSupport.test.ts b/apps/server/src/provider/acp/CursorAcpSupport.test.ts index 78bc16c9f3b..a095fdd679b 100644 --- a/apps/server/src/provider/acp/CursorAcpSupport.test.ts +++ b/apps/server/src/provider/acp/CursorAcpSupport.test.ts @@ -53,7 +53,7 @@ const parameterizedGpt54ConfigOptions: ReadonlyArray { it("builds the default Cursor ACP command", () => { expect(buildCursorAcpSpawnInput(undefined, "/tmp/project")).toEqual({ - command: "agent", + command: "cursor-agent", args: ["acp"], cwd: "/tmp/project", }); diff --git a/apps/server/src/provider/acp/CursorAcpSupport.ts b/apps/server/src/provider/acp/CursorAcpSupport.ts index 169d7c6206d..c5c16b1023e 100644 --- a/apps/server/src/provider/acp/CursorAcpSupport.ts +++ b/apps/server/src/provider/acp/CursorAcpSupport.ts @@ -35,7 +35,7 @@ export function buildCursorAcpSpawnInput( environment?: NodeJS.ProcessEnv, ): AcpSessionRuntime.AcpSpawnInput { return { - command: cursorSettings?.binaryPath || "agent", + command: cursorSettings?.binaryPath || "cursor-agent", args: [ ...(cursorSettings?.apiEndpoint ? (["-e", cursorSettings.apiEndpoint] as const) : []), "acp", diff --git a/apps/server/src/provider/providerMaintenanceRunner.test.ts b/apps/server/src/provider/providerMaintenanceRunner.test.ts index 5ffb69cd5f7..657821f2756 100644 --- a/apps/server/src/provider/providerMaintenanceRunner.test.ts +++ b/apps/server/src/provider/providerMaintenanceRunner.test.ts @@ -40,7 +40,7 @@ function lifecycleFor(provider: ProviderDriverKind): ProviderMaintenanceCapabili return makeProviderMaintenanceCapabilities({ provider, packageName: null, - updateExecutable: "agent", + updateExecutable: "cursor-agent", updateArgs: ["update"], updateLockKey: "cursor-agent", }); @@ -218,7 +218,7 @@ describe("providerMaintenanceRunner", () => { const result = yield* updater.updateProvider(CURSOR_DRIVER); assert.deepStrictEqual(calls, [ { - command: "agent", + command: "cursor-agent", args: ["update"], }, ]); diff --git a/packages/contracts/src/settings.test.ts b/packages/contracts/src/settings.test.ts index aba97cbe205..fd483abf6bf 100644 --- a/packages/contracts/src/settings.test.ts +++ b/packages/contracts/src/settings.test.ts @@ -2,7 +2,12 @@ import { describe, expect, it } from "vite-plus/test"; import * as Schema from "effect/Schema"; import { ProviderInstanceId } from "./providerInstance.ts"; -import { DEFAULT_SERVER_SETTINGS, ServerSettings, ServerSettingsPatch } from "./settings.ts"; +import { + CursorSettings, + DEFAULT_SERVER_SETTINGS, + ServerSettings, + ServerSettingsPatch, +} from "./settings.ts"; const decodeServerSettings = Schema.decodeUnknownSync(ServerSettings); const decodeServerSettingsPatch = Schema.decodeUnknownSync(ServerSettingsPatch); @@ -106,6 +111,24 @@ describe("ServerSettingsPatch.providerInstances", () => { }); }); +describe("CursorSettings binary path", () => { + const decodeCursorSettings = Schema.decodeUnknownSync(CursorSettings); + + it("defaults to cursor-agent", () => { + expect(decodeCursorSettings({}).binaryPath).toBe("cursor-agent"); + }); + + it("maps the legacy agent binary name to cursor-agent", () => { + expect(decodeCursorSettings({ binaryPath: "agent" }).binaryPath).toBe("cursor-agent"); + }); + + it("preserves explicit binary paths", () => { + expect(decodeCursorSettings({ binaryPath: "/usr/local/bin/agent" }).binaryPath).toBe( + "/usr/local/bin/agent", + ); + }); +}); + describe("ServerSettingsPatch string normalization", () => { it("trims string settings while decoding patches", () => { const patch = decodeServerSettingsPatch({ diff --git a/packages/contracts/src/settings.ts b/packages/contracts/src/settings.ts index 7ba267b1e72..0bae190bbfa 100644 --- a/packages/contracts/src/settings.ts +++ b/packages/contracts/src/settings.ts @@ -114,6 +114,25 @@ const makeBinaryPathSetting = (fallback: string) => Schema.withDecodingDefault(Effect.succeed(fallback)), ); +export const LEGACY_CURSOR_BINARY_PATH = "agent"; +export const DEFAULT_CURSOR_BINARY_PATH = "cursor-agent"; + +export const normalizeCursorBinaryPath = (value: string): string => + value === LEGACY_CURSOR_BINARY_PATH ? DEFAULT_CURSOR_BINARY_PATH : value; + +const makeCursorBinaryPathSetting = () => + TrimmedString.pipe( + Schema.decodeTo( + Schema.String, + SchemaTransformation.transformOrFail({ + decode: (value) => + Effect.succeed(normalizeCursorBinaryPath(value || DEFAULT_CURSOR_BINARY_PATH)), + encode: (value) => Effect.succeed(value), + }), + ), + Schema.withDecodingDefault(Effect.succeed(DEFAULT_CURSOR_BINARY_PATH)), + ); + export type ProviderSettingsFormControl = "text" | "password" | "textarea" | "switch"; export interface ProviderSettingsFormAnnotation { @@ -252,11 +271,11 @@ export const CursorSettings = makeProviderSettingsSchema( Schema.withDecodingDefault(Effect.succeed(false)), Schema.annotateKey({ providerSettingsForm: { hidden: true } }), ), - binaryPath: makeBinaryPathSetting("agent").pipe( + binaryPath: makeCursorBinaryPathSetting().pipe( Schema.annotateKey({ title: "Binary path", description: "Path to the Cursor agent binary.", - providerSettingsForm: { placeholder: "agent", clearWhenEmpty: "omit" }, + providerSettingsForm: { placeholder: "cursor-agent", clearWhenEmpty: "omit" }, }), ), apiEndpoint: TrimmedString.pipe(