From f76735fc0524add8d109a2b72fca9008f9af66ad Mon Sep 17 00:00:00 2001 From: Claude AI Date: Fri, 28 Mar 2025 19:12:07 +0000 Subject: [PATCH] feat: add Windsurf IDE module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a Terraform module for the Windsurf IDE similar to the Cursor IDE module. This module provides integration with Coder workspaces for Windsurf IDE. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- windsurf/README.md | 35 ++++++++++++++++++++++++ windsurf/main.test.ts | 41 ++++++++++++++++++++++++++++ windsurf/main.tf | 62 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 138 insertions(+) create mode 100644 windsurf/README.md create mode 100644 windsurf/main.test.ts create mode 100644 windsurf/main.tf diff --git a/windsurf/README.md b/windsurf/README.md new file mode 100644 index 00000000..261123af --- /dev/null +++ b/windsurf/README.md @@ -0,0 +1,35 @@ +# Windsurf IDE + +Adds a Windsurf IDE application. + +## Examples + +```hcl +module "windsurf_ide" { + source = "github.com/coder/modules//windsurf" + agent_id = coder_agent.example.id + folder = "/home/coder/project" +} +``` + +Without a folder parameter: + +```hcl +module "windsurf_ide" { + source = "github.com/coder/modules//windsurf" + agent_id = coder_agent.example.id +} +``` + +## Inputs/Outputs + +| Input | Description | Type | Default | +| ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------- | +| agent_id | The ID of a Coder agent. | string | | +| folder | The folder to open in Windsurf IDE. | string | "" | +| open_recent | Open the most recent workspace or folder. Falls back to the folder if there is no recent workspace or folder to open. | bool | false | +| order | The order determines the position of app in the UI presentation. The lowest order is shown first and apps with equal order are sorted by name. | number | null | + +| Output | Description | Type | +| ------------ | ------------------- | ------ | +| windsurf_url | Windsurf IDE URL. | string | \ No newline at end of file diff --git a/windsurf/main.test.ts b/windsurf/main.test.ts new file mode 100644 index 00000000..767d3198 --- /dev/null +++ b/windsurf/main.test.ts @@ -0,0 +1,41 @@ +import { describe, expect, it } from "vitest"; +import { TerraformStack } from "cdktf"; +import { generateTraces } from "@coder/cdktf-traces"; +import { CoderApp } from "../../cdktf/coder/resources"; + +describe("windsurf", async () => { + const traces = await generateTraces(__dirname); + + it("creates an app", () => { + const stack = new TerraformStack(traces.app, "stack"); + const app = CoderApp.fromStack(stack, "coder_app.windsurf"); + expect(app.url).toContain("workspace="); + expect(app.url).toContain("token=$SESSION_TOKEN"); + expect(app.icon).toBe("/icon/windsurf.svg"); + expect(app.slug).toBe("windsurf"); + expect(app.displayName).toBe("Windsurf IDE"); + expect(app.external).toBe(true); + }); + + describe("supports folder spec", () => { + it("folder = '/home/coder'", async () => { + const traces = await generateTraces(__dirname, { + folder: "/home/coder", + }); + const stack = new TerraformStack(traces.app, "stack"); + const app = CoderApp.fromStack(stack, "coder_app.windsurf"); + expect(app.url).toContain("&folder=/home/coder"); + }); + }); + + describe("supports openRecent", () => { + it("open_recent = true", async () => { + const traces = await generateTraces(__dirname, { + open_recent: true, + }); + const stack = new TerraformStack(traces.app, "stack"); + const app = CoderApp.fromStack(stack, "coder_app.windsurf"); + expect(app.url).toContain("&openRecent"); + }); + }); +}); \ No newline at end of file diff --git a/windsurf/main.tf b/windsurf/main.tf new file mode 100644 index 00000000..a028c8f5 --- /dev/null +++ b/windsurf/main.tf @@ -0,0 +1,62 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + coder = { + source = "coder/coder" + version = ">= 0.23" + } + } +} + +variable "agent_id" { + type = string + description = "The ID of a Coder agent." +} + +variable "folder" { + type = string + description = "The folder to open in Windsurf IDE." + default = "" +} + +variable "open_recent" { + type = bool + description = "Open the most recent workspace or folder. Falls back to the folder if there is no recent workspace or folder to open." + default = false +} + +variable "order" { + type = number + description = "The order determines the position of app in the UI presentation. The lowest order is shown first and apps with equal order are sorted by name (ascending order)." + default = null +} + +data "coder_workspace" "me" {} +data "coder_workspace_owner" "me" {} + +resource "coder_app" "windsurf" { + agent_id = var.agent_id + external = true + icon = "/icon/windsurf.svg" + slug = "windsurf" + display_name = "Windsurf IDE" + order = var.order + url = join("", [ + "windsurf://coder.coder-remote/open", + "?owner=", + data.coder_workspace_owner.me.name, + "&workspace=", + data.coder_workspace.me.name, + var.folder != "" ? join("", ["&folder=", var.folder]) : "", + var.open_recent ? "&openRecent" : "", + "&url=", + data.coder_workspace.me.access_url, + "&token=$SESSION_TOKEN", + ]) +} + +output "windsurf_url" { + value = coder_app.windsurf.url + description = "Windsurf IDE Desktop URL." +} \ No newline at end of file