From 43d848351838cbeb413beb4db1a51854086aff7f Mon Sep 17 00:00:00 2001 From: DevelopmentCats Date: Wed, 19 Nov 2025 11:44:59 -0600 Subject: [PATCH 1/8] feat: add Antigravity IDE module with Terraform configuration and tests --- registry/coder/modules/antigravity/README.md | 67 ++++++++++ .../coder/modules/antigravity/main.test.ts | 124 ++++++++++++++++++ registry/coder/modules/antigravity/main.tf | 109 +++++++++++++++ 3 files changed, 300 insertions(+) create mode 100644 registry/coder/modules/antigravity/README.md create mode 100644 registry/coder/modules/antigravity/main.test.ts create mode 100644 registry/coder/modules/antigravity/main.tf diff --git a/registry/coder/modules/antigravity/README.md b/registry/coder/modules/antigravity/README.md new file mode 100644 index 000000000..62e37ede5 --- /dev/null +++ b/registry/coder/modules/antigravity/README.md @@ -0,0 +1,67 @@ +--- +display_name: Antigravity IDE +description: Add a one-click button to launch Antigravity IDE +icon: ../../../../.icons/antigravity.svg +verified: false +tags: [ide, antigravity, ai] +--- + +# Antigravity IDE + +Add a button to open any workspace with a single click in Antigravity IDE. + +Uses the [Coder Remote VS Code Extension](https://github.com/coder/vscode-coder). + +```tf +module "antigravity" { + count = data.coder_workspace.me.start_count + source = "registry.coder.com/coder/antigravity/coder" + version = "1.0.0" + agent_id = coder_agent.example.id +} +``` + +## Examples + +### Open in a specific directory + +```tf +module "antigravity" { + count = data.coder_workspace.me.start_count + source = "registry.coder.com/coder/antigravity/coder" + version = "1.0.0" + agent_id = coder_agent.example.id + folder = "/home/coder/project" +} +``` + +### Configure MCP servers for Antigravity + +Provide a JSON-encoded string via the `mcp` input. When set, the module writes the value to `~/.antigravity/mcp.json` using a `coder_script` on workspace start. + +The following example configures Antigravity to use the GitHub MCP server with authentication facilitated by the [`coder_external_auth`](https://coder.com/docs/admin/external-auth#configure-a-github-oauth-app) resource. + +```tf +module "antigravity" { + count = data.coder_workspace.me.start_count + source = "registry.coder.com/coder/antigravity/coder" + version = "1.0.0" + agent_id = coder_agent.example.id + folder = "/home/coder/project" + mcp = jsonencode({ + mcpServers = { + "github" : { + "url" : "https://api.githubcopilot.com/mcp/", + "headers" : { + "Authorization" : "Bearer ${data.coder_external_auth.github.access_token}", + }, + "type" : "http" + } + } + }) +} + +data "coder_external_auth" "github" { + id = "github" +} +``` diff --git a/registry/coder/modules/antigravity/main.test.ts b/registry/coder/modules/antigravity/main.test.ts new file mode 100644 index 000000000..23150f9d7 --- /dev/null +++ b/registry/coder/modules/antigravity/main.test.ts @@ -0,0 +1,124 @@ +import { describe, it, expect } from "bun:test"; +import { + runTerraformApply, + runTerraformInit, + testRequiredVariables, + runContainer, + execContainer, + removeContainer, + findResourceInstance, + readFileContainer, +} from "~test"; + +describe("antigravity", async () => { + await runTerraformInit(import.meta.dir); + + testRequiredVariables(import.meta.dir, { + agent_id: "foo", + }); + + it("default output", async () => { + const state = await runTerraformApply(import.meta.dir, { + agent_id: "foo", + }); + expect(state.outputs.antigravity_url.value).toBe( + "antigravity://coder.coder-remote/open?owner=default&workspace=default&url=https://mydeployment.coder.com&token=$SESSION_TOKEN", + ); + + const coder_app = state.resources.find( + (res) => res.type === "coder_app" && res.name === "antigravity", + ); + + expect(coder_app).not.toBeNull(); + expect(coder_app?.instances.length).toBe(1); + expect(coder_app?.instances[0].attributes.order).toBeNull(); + }); + + it("adds folder", async () => { + const state = await runTerraformApply(import.meta.dir, { + agent_id: "foo", + folder: "/foo/bar", + }); + expect(state.outputs.antigravity_url.value).toBe( + "antigravity://coder.coder-remote/open?owner=default&workspace=default&folder=/foo/bar&url=https://mydeployment.coder.com&token=$SESSION_TOKEN", + ); + }); + + it("adds folder and open_recent", async () => { + const state = await runTerraformApply(import.meta.dir, { + agent_id: "foo", + folder: "/foo/bar", + open_recent: "true", + }); + expect(state.outputs.antigravity_url.value).toBe( + "antigravity://coder.coder-remote/open?owner=default&workspace=default&folder=/foo/bar&openRecent&url=https://mydeployment.coder.com&token=$SESSION_TOKEN", + ); + }); + + it("adds folder but not open_recent", async () => { + const state = await runTerraformApply(import.meta.dir, { + agent_id: "foo", + folder: "/foo/bar", + openRecent: "false", + }); + expect(state.outputs.antigravity_url.value).toBe( + "antigravity://coder.coder-remote/open?owner=default&workspace=default&folder=/foo/bar&url=https://mydeployment.coder.com&token=$SESSION_TOKEN", + ); + }); + + it("adds open_recent", async () => { + const state = await runTerraformApply(import.meta.dir, { + agent_id: "foo", + open_recent: "true", + }); + expect(state.outputs.antigravity_url.value).toBe( + "antigravity://coder.coder-remote/open?owner=default&workspace=default&openRecent&url=https://mydeployment.coder.com&token=$SESSION_TOKEN", + ); + }); + + it("expect order to be set", async () => { + const state = await runTerraformApply(import.meta.dir, { + agent_id: "foo", + order: "22", + }); + + const coder_app = state.resources.find( + (res) => res.type === "coder_app" && res.name === "antigravity", + ); + + expect(coder_app).not.toBeNull(); + expect(coder_app?.instances.length).toBe(1); + expect(coder_app?.instances[0].attributes.order).toBe(22); + }); + + it("writes ~/.antigravity/mcp.json when mcp provided", async () => { + const id = await runContainer("alpine"); + try { + const mcp = JSON.stringify({ + servers: { demo: { url: "http://localhost:1234" } }, + }); + const state = await runTerraformApply(import.meta.dir, { + agent_id: "foo", + mcp, + }); + const script = findResourceInstance( + state, + "coder_script", + "antigravity_mcp", + ).script; + const resp = await execContainer(id, ["sh", "-c", script]); + if (resp.exitCode !== 0) { + console.log(resp.stdout); + console.log(resp.stderr); + } + expect(resp.exitCode).toBe(0); + const content = await readFileContainer( + id, + "/root/.antigravity/mcp.json", + ); + expect(content).toBe(mcp); + } finally { + await removeContainer(id); + } + }); +}); diff --git a/registry/coder/modules/antigravity/main.tf b/registry/coder/modules/antigravity/main.tf new file mode 100644 index 000000000..b1c9bdd23 --- /dev/null +++ b/registry/coder/modules/antigravity/main.tf @@ -0,0 +1,109 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + coder = { + source = "coder/coder" + version = ">= 2.5" + } + } +} + +variable "agent_id" { + type = string + description = "The ID of a Coder agent." +} + +variable "folder" { + type = string + description = "The folder to open in Antigravity 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 +} + +variable "group" { + type = string + description = "The name of a group that this app belongs to." + default = null +} + +variable "slug" { + type = string + description = "The slug of the app." + default = "antigravity" +} + +variable "display_name" { + type = string + description = "The display name of the app." + default = "Antigravity IDE" +} + +variable "mcp" { + type = string + description = "JSON-encoded string to configure MCP servers for Antigravity. When set, writes ~/.antigravity/mcp.json." + default = "" +} + +data "coder_workspace" "me" {} + +data "coder_workspace_owner" "me" {} + +locals { + mcp_b64 = var.mcp != "" ? base64encode(var.mcp) : "" +} + +resource "coder_app" "antigravity" { + agent_id = var.agent_id + external = true + icon = "/icon/antigravity.svg" + slug = var.slug + display_name = var.display_name + order = var.order + group = var.group + url = join("", [ + "antigravity://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", + ]) +} + +resource "coder_script" "antigravity_mcp" { + count = var.mcp != "" ? 1 : 0 + agent_id = var.agent_id + display_name = "Antigravity MCP" + icon = "/icon/antigravity.svg" + run_on_start = true + start_blocks_login = false + script = <<-EOT + #!/bin/sh + set -eu + mkdir -p "$HOME/.antigravity" + echo -n "${local.mcp_b64}" | base64 -d > "$HOME/.antigravity/mcp.json" + chmod 600 "$HOME/.antigravity/mcp.json" + EOT +} + +output "antigravity_url" { + value = coder_app.antigravity.url + description = "Antigravity IDE URL." +} + From 7b8f8f7bf6a42bc5dc4190036c7653d7f28bf7e8 Mon Sep 17 00:00:00 2001 From: DevelopmentCats Date: Fri, 21 Nov 2025 15:52:04 -0600 Subject: [PATCH 2/8] fix: update MCP configuration path in Antigravity module --- registry/coder/modules/antigravity/README.md | 4 ++-- registry/coder/modules/antigravity/main.test.ts | 4 ++-- registry/coder/modules/antigravity/main.tf | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/registry/coder/modules/antigravity/README.md b/registry/coder/modules/antigravity/README.md index 62e37ede5..4b2d26287 100644 --- a/registry/coder/modules/antigravity/README.md +++ b/registry/coder/modules/antigravity/README.md @@ -8,7 +8,7 @@ tags: [ide, antigravity, ai] # Antigravity IDE -Add a button to open any workspace with a single click in Antigravity IDE. +Add a button to open any workspace with a single click in [Antigravity IDE](https://antigravity.google). Uses the [Coder Remote VS Code Extension](https://github.com/coder/vscode-coder). @@ -37,7 +37,7 @@ module "antigravity" { ### Configure MCP servers for Antigravity -Provide a JSON-encoded string via the `mcp` input. When set, the module writes the value to `~/.antigravity/mcp.json` using a `coder_script` on workspace start. +Provide a JSON-encoded string via the `mcp` input. When set, the module writes the value to `~/.gemini/antigravity/mcp_config.json` using a `coder_script` on workspace start. The following example configures Antigravity to use the GitHub MCP server with authentication facilitated by the [`coder_external_auth`](https://coder.com/docs/admin/external-auth#configure-a-github-oauth-app) resource. diff --git a/registry/coder/modules/antigravity/main.test.ts b/registry/coder/modules/antigravity/main.test.ts index 23150f9d7..ec3170b43 100644 --- a/registry/coder/modules/antigravity/main.test.ts +++ b/registry/coder/modules/antigravity/main.test.ts @@ -91,7 +91,7 @@ describe("antigravity", async () => { expect(coder_app?.instances[0].attributes.order).toBe(22); }); - it("writes ~/.antigravity/mcp.json when mcp provided", async () => { + it("writes ~/.gemini/antigravity/mcp_config.json when mcp provided", async () => { const id = await runContainer("alpine"); try { const mcp = JSON.stringify({ @@ -114,7 +114,7 @@ describe("antigravity", async () => { expect(resp.exitCode).toBe(0); const content = await readFileContainer( id, - "/root/.antigravity/mcp.json", + "/root/.gemini/antigravity/mcp_config.json", ); expect(content).toBe(mcp); } finally { diff --git a/registry/coder/modules/antigravity/main.tf b/registry/coder/modules/antigravity/main.tf index b1c9bdd23..9273c0a67 100644 --- a/registry/coder/modules/antigravity/main.tf +++ b/registry/coder/modules/antigravity/main.tf @@ -52,7 +52,7 @@ variable "display_name" { variable "mcp" { type = string - description = "JSON-encoded string to configure MCP servers for Antigravity. When set, writes ~/.antigravity/mcp.json." + description = "JSON-encoded string to configure MCP servers for Antigravity. When set, writes ~/.gemini/antigravity/mcp_config.json." default = "" } @@ -96,9 +96,9 @@ resource "coder_script" "antigravity_mcp" { script = <<-EOT #!/bin/sh set -eu - mkdir -p "$HOME/.antigravity" - echo -n "${local.mcp_b64}" | base64 -d > "$HOME/.antigravity/mcp.json" - chmod 600 "$HOME/.antigravity/mcp.json" + mkdir -p "$HOME/.gemini/antigravity" + echo -n "${local.mcp_b64}" | base64 -d > "$HOME/.gemini/antigravity/mcp_config.json" + chmod 600 "$HOME/.gemini/antigravity/mcp_config.json" EOT } From cb4c267480b49a12e5c8710d95375103a1d36f08 Mon Sep 17 00:00:00 2001 From: DevelopmentCats Date: Fri, 21 Nov 2025 15:59:12 -0600 Subject: [PATCH 3/8] fix: increase timeout for antigravity tests to prevent timeouts --- registry/coder/modules/antigravity/main.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/registry/coder/modules/antigravity/main.test.ts b/registry/coder/modules/antigravity/main.test.ts index ec3170b43..359a964a9 100644 --- a/registry/coder/modules/antigravity/main.test.ts +++ b/registry/coder/modules/antigravity/main.test.ts @@ -120,5 +120,5 @@ describe("antigravity", async () => { } finally { await removeContainer(id); } - }); + }, 10000); }); From f1d210964cf95401d00828f6ee5928c511ede866 Mon Sep 17 00:00:00 2001 From: DevelopmentCats Date: Tue, 2 Dec 2025 13:36:00 -0600 Subject: [PATCH 4/8] refactor(antigravity): migrate coder_app to vscode-desktop-core module --- .../coder/modules/antigravity/main.test.ts | 10 ++++- registry/coder/modules/antigravity/main.tf | 37 ++++++++----------- 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/registry/coder/modules/antigravity/main.test.ts b/registry/coder/modules/antigravity/main.test.ts index 359a964a9..74f2f1182 100644 --- a/registry/coder/modules/antigravity/main.test.ts +++ b/registry/coder/modules/antigravity/main.test.ts @@ -26,7 +26,10 @@ describe("antigravity", async () => { ); const coder_app = state.resources.find( - (res) => res.type === "coder_app" && res.name === "antigravity", + (res) => + res.type === "coder_app" && + res.module === "module.vscode-desktop-core" && + res.name === "vscode-desktop", ); expect(coder_app).not.toBeNull(); @@ -83,7 +86,10 @@ describe("antigravity", async () => { }); const coder_app = state.resources.find( - (res) => res.type === "coder_app" && res.name === "antigravity", + (res) => + res.type === "coder_app" && + res.module === "module.vscode-desktop-core" && + res.name === "vscode-desktop", ); expect(coder_app).not.toBeNull(); diff --git a/registry/coder/modules/antigravity/main.tf b/registry/coder/modules/antigravity/main.tf index 9273c0a67..27c6166de 100644 --- a/registry/coder/modules/antigravity/main.tf +++ b/registry/coder/modules/antigravity/main.tf @@ -64,26 +64,21 @@ locals { mcp_b64 = var.mcp != "" ? base64encode(var.mcp) : "" } -resource "coder_app" "antigravity" { - agent_id = var.agent_id - external = true - icon = "/icon/antigravity.svg" - slug = var.slug - display_name = var.display_name - order = var.order - group = var.group - url = join("", [ - "antigravity://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", - ]) +module "vscode-desktop-core" { + source = "registry.coder.com/coder/vscode-desktop-core/coder" + version = "1.0.1" + + agent_id = var.agent_id + + web_app_icon = "/icon/antigravity.svg" + web_app_slug = var.slug + web_app_display_name = var.display_name + web_app_order = var.order + web_app_group = var.group + + folder = var.folder + open_recent = var.open_recent + protocol = "antigravity" } resource "coder_script" "antigravity_mcp" { @@ -103,7 +98,7 @@ resource "coder_script" "antigravity_mcp" { } output "antigravity_url" { - value = coder_app.antigravity.url + value = module.vscode-desktop-core.ide_uri description = "Antigravity IDE URL." } From b1d0d707543a3263fcad11d5b454c1c651c17b44 Mon Sep 17 00:00:00 2001 From: DevCats Date: Tue, 2 Dec 2025 13:47:46 -0600 Subject: [PATCH 5/8] chore: set verified to true Co-authored-by: Atif Ali --- registry/coder/modules/antigravity/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/registry/coder/modules/antigravity/README.md b/registry/coder/modules/antigravity/README.md index 4b2d26287..e5e615050 100644 --- a/registry/coder/modules/antigravity/README.md +++ b/registry/coder/modules/antigravity/README.md @@ -2,7 +2,7 @@ display_name: Antigravity IDE description: Add a one-click button to launch Antigravity IDE icon: ../../../../.icons/antigravity.svg -verified: false +verified: true tags: [ide, antigravity, ai] --- From 3bfb080a75de93cd4f709bcd3b88c330824753e2 Mon Sep 17 00:00:00 2001 From: DevCats Date: Tue, 2 Dec 2025 13:48:12 -0600 Subject: [PATCH 6/8] chore: shorten module display name Co-authored-by: Atif Ali --- registry/coder/modules/antigravity/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/registry/coder/modules/antigravity/README.md b/registry/coder/modules/antigravity/README.md index e5e615050..2c34475b4 100644 --- a/registry/coder/modules/antigravity/README.md +++ b/registry/coder/modules/antigravity/README.md @@ -1,5 +1,5 @@ --- -display_name: Antigravity IDE +display_name: Antigravity description: Add a one-click button to launch Antigravity IDE icon: ../../../../.icons/antigravity.svg verified: true From 36c06b5981030045be61d1b9f7fefdda70a38bcf Mon Sep 17 00:00:00 2001 From: DevCats Date: Tue, 2 Dec 2025 13:48:36 -0600 Subject: [PATCH 7/8] chore: update module description Co-authored-by: Atif Ali --- registry/coder/modules/antigravity/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/registry/coder/modules/antigravity/README.md b/registry/coder/modules/antigravity/README.md index 2c34475b4..7b56f7992 100644 --- a/registry/coder/modules/antigravity/README.md +++ b/registry/coder/modules/antigravity/README.md @@ -1,6 +1,6 @@ --- display_name: Antigravity -description: Add a one-click button to launch Antigravity IDE +description: Add a one-click button to launch Google Antigravity icon: ../../../../.icons/antigravity.svg verified: true tags: [ide, antigravity, ai] From 8feb9a793eaf7ccb48fe9da29404316d9f43dcd1 Mon Sep 17 00:00:00 2001 From: DevCats Date: Tue, 2 Dec 2025 13:48:50 -0600 Subject: [PATCH 8/8] chore: update module tags Co-authored-by: Atif Ali --- registry/coder/modules/antigravity/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/registry/coder/modules/antigravity/README.md b/registry/coder/modules/antigravity/README.md index 7b56f7992..ed5882b2e 100644 --- a/registry/coder/modules/antigravity/README.md +++ b/registry/coder/modules/antigravity/README.md @@ -3,7 +3,7 @@ display_name: Antigravity description: Add a one-click button to launch Google Antigravity icon: ../../../../.icons/antigravity.svg verified: true -tags: [ide, antigravity, ai] +tags: [ide, antigravity, ai, google] --- # Antigravity IDE