From 59bc52f5278098b494fdefca5c6de0323aa2c282 Mon Sep 17 00:00:00 2001 From: Dotta Date: Thu, 5 Mar 2026 09:27:20 -0600 Subject: [PATCH] cursor adapter: do not default to read-only ask mode --- packages/adapters/cursor-local/src/index.ts | 2 +- .../cursor-local/src/server/execute.ts | 2 +- .../__tests__/cursor-local-execute.test.ts | 62 ++++++++++++++++++- 3 files changed, 62 insertions(+), 4 deletions(-) diff --git a/packages/adapters/cursor-local/src/index.ts b/packages/adapters/cursor-local/src/index.ts index 01eabfbd..15bbb9d5 100644 --- a/packages/adapters/cursor-local/src/index.ts +++ b/packages/adapters/cursor-local/src/index.ts @@ -65,7 +65,7 @@ Core fields: - instructionsFilePath (string, optional): absolute path to a markdown instructions file prepended to the run prompt - promptTemplate (string, optional): run prompt template - model (string, optional): Cursor model id (for example auto or gpt-5.3-codex) -- mode (string, optional): Cursor execution mode passed as --mode (plan|ask). Defaults to ask when omitted. +- mode (string, optional): Cursor execution mode passed as --mode (plan|ask). Leave unset for normal autonomous runs. - command (string, optional): defaults to "agent" - extraArgs (string[], optional): additional CLI args - env (object, optional): KEY=VALUE environment variables diff --git a/packages/adapters/cursor-local/src/server/execute.ts b/packages/adapters/cursor-local/src/server/execute.ts index 39f94d7a..ad2f02e2 100644 --- a/packages/adapters/cursor-local/src/server/execute.ts +++ b/packages/adapters/cursor-local/src/server/execute.ts @@ -157,7 +157,7 @@ export async function execute(ctx: AdapterExecutionContext): Promise { expect(result.errorMessage).toBeNull(); const capture = JSON.parse(await fs.readFile(capturePath, "utf8")) as CapturePayload; - expect(capture.argv).toContain("--mode"); - expect(capture.argv).toContain("ask"); + expect(capture.argv).not.toContain("--mode"); + expect(capture.argv).not.toContain("ask"); expect(capture.paperclipEnvKeys).toEqual( expect.arrayContaining([ "PAPERCLIP_AGENT_ID", @@ -120,4 +120,62 @@ describe("cursor execute", () => { await fs.rm(root, { recursive: true, force: true }); } }); + + it("passes --mode when explicitly configured", async () => { + const root = await fs.mkdtemp(path.join(os.tmpdir(), "paperclip-cursor-execute-mode-")); + const workspace = path.join(root, "workspace"); + const commandPath = path.join(root, "agent"); + const capturePath = path.join(root, "capture.json"); + await fs.mkdir(workspace, { recursive: true }); + await writeFakeCursorCommand(commandPath); + + const previousHome = process.env.HOME; + process.env.HOME = root; + + try { + const result = await execute({ + runId: "run-2", + agent: { + id: "agent-1", + companyId: "company-1", + name: "Cursor Coder", + adapterType: "cursor", + adapterConfig: {}, + }, + runtime: { + sessionId: null, + sessionParams: null, + sessionDisplayId: null, + taskKey: null, + }, + config: { + command: commandPath, + cwd: workspace, + model: "auto", + mode: "ask", + env: { + PAPERCLIP_TEST_CAPTURE_PATH: capturePath, + }, + promptTemplate: "Follow the paperclip heartbeat.", + }, + context: {}, + authToken: "run-jwt-token", + onLog: async () => {}, + }); + + expect(result.exitCode).toBe(0); + expect(result.errorMessage).toBeNull(); + + const capture = JSON.parse(await fs.readFile(capturePath, "utf8")) as CapturePayload; + expect(capture.argv).toContain("--mode"); + expect(capture.argv).toContain("ask"); + } finally { + if (previousHome === undefined) { + delete process.env.HOME; + } else { + process.env.HOME = previousHome; + } + await fs.rm(root, { recursive: true, force: true }); + } + }); });