diff --git a/registry/coder/modules/agent-relay-cursor/README.md b/registry/coder/modules/agent-relay-cursor/README.md index 08f2c9a43..7ea7331dd 100644 --- a/registry/coder/modules/agent-relay-cursor/README.md +++ b/registry/coder/modules/agent-relay-cursor/README.md @@ -16,7 +16,7 @@ parameters the relay stamps on each build and runs the Cursor CLI worker. ```tf module "cursor_worker" { source = "registry.coder.com/coder/agent-relay-cursor/coder" - version = "0.3.0" + version = "0.4.0" agent_id = coder_agent.main.id # Downloads the Cursor CLI at start when it is not in the image. Bake @@ -58,6 +58,12 @@ created. - Repo-scoped pools: the template must clone `agent_relay_cursor_repo_url` and provide SCM credentials before this module's script runs. - `computer_use = true` needs the computer-use packages in the image. + `share_desktop = true` (requires `computer_use`) lets people watch or take + control of the agent's desktop from the Desktop tab in Cursor. It needs + TigerVNC and Xfce in the image, as in + `ghcr.io/coder/agent-relay-workspace:desktop`, and `DISPLAY` must be unset + so the worker starts its own managed desktop. Run `agent worker debug` in + the image to check. - Builds must finish inside the pool's `dispatch_deadline` (default 10m, max 15m): pre-pulled images, no persistent volumes. diff --git a/registry/coder/modules/agent-relay-cursor/main.test.ts b/registry/coder/modules/agent-relay-cursor/main.test.ts index dda52b7a7..29bdcf565 100644 --- a/registry/coder/modules/agent-relay-cursor/main.test.ts +++ b/registry/coder/modules/agent-relay-cursor/main.test.ts @@ -408,6 +408,21 @@ describe("agent-relay-cursor", () => { expect(args).toContain("--computer-use"); }); + it("passes an explicit desktop share mode so it cannot swallow start", async () => { + // --share-desktop takes an optional mode; bare, it consumes the + // next argument and the CLI rejects "start" as a mode. + const { id, scripts } = await setup({ + computer_use: "true", + share_desktop: "true", + }); + await stubAgent(id, 'printf "%s\\n" "$@" >/tmp/agent-args; sleep 30'); + const { start } = await runDispatched(id, scripts); + expect(start.exitCode).toBe(0); + const args = (await readFileContainer(id, "/tmp/agent-args")).split("\n"); + expect(args).toContain("--share-desktop=view_and_control"); + expect(args).toContain("start"); + }); + it("records the exit code when the worker exits", async () => { const { id, scripts } = await setup(); await stubAgent(id, "exit 3"); diff --git a/registry/coder/modules/agent-relay-cursor/main.tf b/registry/coder/modules/agent-relay-cursor/main.tf index 528f8589a..2b654e373 100644 --- a/registry/coder/modules/agent-relay-cursor/main.tf +++ b/registry/coder/modules/agent-relay-cursor/main.tf @@ -69,6 +69,17 @@ variable "computer_use" { description = "Start the worker with --computer-use. Requires the computer-use packages in the workspace image." } +variable "share_desktop" { + type = bool + default = false + description = "Start the worker with --share-desktop so viewers in Cursor can watch or control the agent's managed desktop. Linux only; requires computer_use and the TigerVNC and Xfce packages in the workspace image." + + validation { + condition = !var.share_desktop || var.computer_use + error_message = "share_desktop requires computer_use = true." + } +} + variable "state_file" { type = string default = "$HOME/.coder-modules/coder/agent-relay-cursor/worker-state" @@ -273,6 +284,7 @@ locals { cli_binary = var.cli_binary install_cli = var.install_cli computer_use = var.computer_use + share_desktop = var.share_desktop state_file = var.state_file log_file = var.log_file }) diff --git a/registry/coder/modules/agent-relay-cursor/main.tftest.hcl b/registry/coder/modules/agent-relay-cursor/main.tftest.hcl index 354a86165..1bd9097aa 100644 --- a/registry/coder/modules/agent-relay-cursor/main.tftest.hcl +++ b/registry/coder/modules/agent-relay-cursor/main.tftest.hcl @@ -211,6 +211,35 @@ run "computer_use_enabled" { condition = can(regex("--computer-use", local.start_script)) error_message = "computer_use = true must pass the flag to the worker" } + + assert { + condition = !can(regex("--share-desktop", local.start_script)) + error_message = "desktop sharing must stay opt in" + } +} + +run "share_desktop_enabled" { + command = plan + + variables { + computer_use = true + share_desktop = true + } + + assert { + condition = can(regex("--share-desktop=view_and_control", local.start_script)) + error_message = "share_desktop must pass an explicit mode, or the optional argument swallows start" + } +} + +run "share_desktop_requires_computer_use" { + command = plan + + variables { + share_desktop = true + } + + expect_failures = [var.share_desktop] } run "install_cli_enabled_by_default" { diff --git a/registry/coder/modules/agent-relay-cursor/start.sh.tftpl b/registry/coder/modules/agent-relay-cursor/start.sh.tftpl index 5e70a712f..bfaf5fc1f 100644 --- a/registry/coder/modules/agent-relay-cursor/start.sh.tftpl +++ b/registry/coder/modules/agent-relay-cursor/start.sh.tftpl @@ -125,6 +125,9 @@ ${cli_binary} worker \\ \$${auth_args[@]+"\$${auth_args[@]}"} \\ %{ if computer_use ~} --computer-use \\ +%{ endif ~} +%{ if share_desktop ~} + --share-desktop=view_and_control \\ %{ endif ~} start >"$log_file" 2>&1 & worker_pid=\$!