Compare commits

...

3 Commits

Author SHA1 Message Date
Atif Ali 494ad9bd48 fix(copilot): remove hardcoded model enum to allow any Copilot model (#833)
The `copilot_model` variable was restricted to a hardcoded enum of three
models (`claude-sonnet-4`, `claude-sonnet-4.5`, `gpt-5`). Models change
fast and this validation was blocking users from using newer models.

## Changes

- Remove `validation` block from `copilot_model` variable in `main.tf`
- Update variable description to indicate any Copilot-supported model
can be used
- Replace enum validation test with a test that verifies arbitrary model
strings are accepted
- Bump module version to `0.4.1` in README examples

Closes #832

> 🤖 This PR was created with the help of Coder Agents, and needs a human
review. 🧑‍💻
2026-04-05 00:42:33 +05:00
Phorcys 5ee68d04d1 feat: add mcp_config input variable to vscode-desktop-core module (#753)
## Description

Standardizes handling of `mcp` variables in VSCode Desktop-based
modules.
Made modular enough to pave the way for setting other config files than
`mcp_server.json` and `mcp.json`.

## Type of Change

- [ ] New module
- [ ] New template
- [ ] Bug fix
- [x] Feature/enhancement
- [ ] Documentation
- [ ] Other

## Testing & Validation

- [x] Tests pass (`bun test`)
- [x] Code formatted (`bun fmt`)
- [x] Changes tested locally

---------

Co-authored-by: DevCats <christofer@coder.com>
Co-authored-by: blink-so[bot] <211532188+blink-so[bot]@users.noreply.github.com>
2026-04-03 13:29:46 -05:00
blinkagent[bot] 516a934694 feat(claude-code): wire web_app variable through to agentapi module (#831)
Follow-up to #764.

Now that the `agentapi` module `v2.4.0` is published with `web_app`
support, this PR completes the wiring:

## Changes

### `claude-code/main.tf`
- Bump agentapi dependency from `v2.3.0` → `v2.4.0`
- Replace `# TODO: pass web_app = var.web_app once agentapi module is
published with web_app support` with `web_app = var.web_app`

### `claude-code/README.md`
- Bump version references from `4.9.0` → `4.9.1`

## Result

Setting `web_app = false` on the `claude-code` module now correctly
passes through to the `agentapi` module, hiding the web UI app icon from
the Coder dashboard while still running AgentAPI. The task-safe behavior
(auto-enabling for `coder_ai_task`) is handled by the `agentapi` module.

---------

Co-authored-by: blink-so[bot] <211532188+blink-so[bot]@users.noreply.github.com>
2026-04-03 12:19:05 -05:00
8 changed files with 110 additions and 40 deletions
@@ -13,7 +13,7 @@ Run [GitHub Copilot CLI](https://docs.github.com/copilot/concepts/agents/about-c
```tf
module "copilot" {
source = "registry.coder.com/coder-labs/copilot/coder"
version = "0.4.0"
version = "0.4.1"
agent_id = coder_agent.example.id
workdir = "/home/coder/projects"
}
@@ -51,7 +51,7 @@ data "coder_parameter" "ai_prompt" {
module "copilot" {
source = "registry.coder.com/coder-labs/copilot/coder"
version = "0.4.0"
version = "0.4.1"
agent_id = coder_agent.example.id
workdir = "/home/coder/projects"
@@ -71,7 +71,7 @@ Customize tool permissions, MCP servers, and Copilot settings:
```tf
module "copilot" {
source = "registry.coder.com/coder-labs/copilot/coder"
version = "0.4.0"
version = "0.4.1"
agent_id = coder_agent.example.id
workdir = "/home/coder/projects"
@@ -142,7 +142,7 @@ variable "github_token" {
module "copilot" {
source = "registry.coder.com/coder-labs/copilot/coder"
version = "0.4.0"
version = "0.4.1"
agent_id = coder_agent.example.id
workdir = "/home/coder/projects"
github_token = var.github_token
@@ -156,7 +156,7 @@ Run Copilot as a command-line tool without task reporting or web interface. This
```tf
module "copilot" {
source = "registry.coder.com/coder-labs/copilot/coder"
version = "0.4.0"
version = "0.4.1"
agent_id = coder_agent.example.id
workdir = "/home/coder"
report_tasks = false
@@ -179,7 +179,7 @@ module "aibridge-proxy" {
module "copilot" {
source = "registry.coder.com/coder-labs/copilot/coder"
version = "0.4.0"
version = "0.4.1"
agent_id = coder_agent.main.id
workdir = "/home/coder/projects"
enable_aibridge_proxy = true
@@ -117,18 +117,23 @@ run "copilot_model_not_created_for_default" {
}
}
run "model_validation_accepts_valid_models" {
run "copilot_model_accepts_custom_model" {
command = plan
variables {
agent_id = "test-agent"
workdir = "/home/coder"
copilot_model = "gpt-5"
copilot_model = "o3-pro"
}
assert {
condition = contains(["claude-sonnet-4", "claude-sonnet-4.5", "gpt-5"], var.copilot_model)
error_message = "Model should be one of the valid options"
condition = var.copilot_model == "o3-pro"
error_message = "copilot_model should accept any model string"
}
assert {
condition = length(resource.coder_env.copilot_model) == 1
error_message = "copilot_model env var should be created for non-default model"
}
}
+1 -5
View File
@@ -33,12 +33,8 @@ variable "github_token" {
variable "copilot_model" {
type = string
description = "Model to use. Supported values: claude-sonnet-4, claude-sonnet-4.5 (default), gpt-5."
description = "The model to use for Copilot. Any model supported by GitHub Copilot can be used."
default = "claude-sonnet-4.5"
validation {
condition = contains(["claude-sonnet-4", "claude-sonnet-4.5", "gpt-5"], var.copilot_model)
error_message = "copilot_model must be one of: claude-sonnet-4, claude-sonnet-4.5, gpt-5."
}
}
variable "copilot_config" {
+9 -9
View File
@@ -13,7 +13,7 @@ Run the [Claude Code](https://docs.anthropic.com/en/docs/agents-and-tools/claude
```tf
module "claude-code" {
source = "registry.coder.com/coder/claude-code/coder"
version = "4.9.0"
version = "4.9.1"
agent_id = coder_agent.main.id
workdir = "/home/coder/project"
claude_api_key = "xxxx-xxxxx-xxxx"
@@ -60,7 +60,7 @@ By default, when `enable_boundary = true`, the module uses `coder boundary` subc
```tf
module "claude-code" {
source = "registry.coder.com/coder/claude-code/coder"
version = "4.9.0"
version = "4.9.1"
agent_id = coder_agent.main.id
workdir = "/home/coder/project"
enable_boundary = true
@@ -81,7 +81,7 @@ For tasks integration with AI Bridge, add `enable_aibridge = true` to the [Usage
```tf
module "claude-code" {
source = "registry.coder.com/coder/claude-code/coder"
version = "4.9.0"
version = "4.9.1"
agent_id = coder_agent.main.id
workdir = "/home/coder/project"
enable_aibridge = true
@@ -110,7 +110,7 @@ data "coder_task" "me" {}
module "claude-code" {
source = "registry.coder.com/coder/claude-code/coder"
version = "4.9.0"
version = "4.9.1"
agent_id = coder_agent.main.id
workdir = "/home/coder/project"
ai_prompt = data.coder_task.me.prompt
@@ -133,7 +133,7 @@ This example shows additional configuration options for version pinning, custom
```tf
module "claude-code" {
source = "registry.coder.com/coder/claude-code/coder"
version = "4.9.0"
version = "4.9.1"
agent_id = coder_agent.main.id
workdir = "/home/coder/project"
@@ -189,7 +189,7 @@ Run and configure Claude Code as a standalone CLI in your workspace.
```tf
module "claude-code" {
source = "registry.coder.com/coder/claude-code/coder"
version = "4.9.0"
version = "4.9.1"
agent_id = coder_agent.main.id
workdir = "/home/coder/project"
install_claude_code = true
@@ -211,7 +211,7 @@ variable "claude_code_oauth_token" {
module "claude-code" {
source = "registry.coder.com/coder/claude-code/coder"
version = "4.9.0"
version = "4.9.1"
agent_id = coder_agent.main.id
workdir = "/home/coder/project"
claude_code_oauth_token = var.claude_code_oauth_token
@@ -284,7 +284,7 @@ resource "coder_env" "bedrock_api_key" {
module "claude-code" {
source = "registry.coder.com/coder/claude-code/coder"
version = "4.9.0"
version = "4.9.1"
agent_id = coder_agent.main.id
workdir = "/home/coder/project"
model = "global.anthropic.claude-sonnet-4-5-20250929-v1:0"
@@ -341,7 +341,7 @@ resource "coder_env" "google_application_credentials" {
module "claude-code" {
source = "registry.coder.com/coder/claude-code/coder"
version = "4.9.0"
version = "4.9.1"
agent_id = coder_agent.main.id
workdir = "/home/coder/project"
model = "claude-sonnet-4@20250514"
+3 -3
View File
@@ -368,10 +368,10 @@ locals {
module "agentapi" {
source = "registry.coder.com/coder/agentapi/coder"
version = "2.3.0"
version = "2.4.0"
agent_id = var.agent_id
# TODO: pass web_app = var.web_app once agentapi module is published with web_app support
agent_id = var.agent_id
web_app = var.web_app
web_app_slug = local.app_slug
web_app_order = var.order
web_app_group = var.group
@@ -16,7 +16,7 @@ The VSCode Desktop Core module is a building block for modules that need to expo
```tf
module "vscode-desktop-core" {
source = "registry.coder.com/coder/vscode-desktop-core/coder"
version = "1.0.2"
version = "1.1.0"
agent_id = var.agent_id
@@ -3,6 +3,11 @@ import {
runTerraformApply,
runTerraformInit,
testRequiredVariables,
runContainer,
execContainer,
removeContainer,
findResourceInstance,
readFileContainer,
} from "~test";
// hardcoded coder_app name in main.tf
@@ -16,6 +21,7 @@ const defaultVariables = {
coder_app_display_name: "VS Code Desktop",
protocol: "vscode",
config_dir: "$HOME/.vscode",
};
describe("vscode-desktop-core", async () => {
@@ -134,4 +140,41 @@ describe("vscode-desktop-core", async () => {
expect(coder_app?.instances[0].attributes.group).toBe("web-app-group");
});
});
it("writes mcp_config.json when mcp_config variable provided", async () => {
const id = await runContainer("alpine");
try {
const mcp_config = JSON.stringify({
servers: { demo: { url: "http://localhost:1234" } },
});
const state = await runTerraformApply(import.meta.dir, {
...defaultVariables,
mcp_config,
});
const script = findResourceInstance(
state,
"coder_script",
"vscode-desktop-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,
`${defaultVariables.config_dir.replace("$HOME", "/root")}/mcp_config.json`,
);
expect(content).toBe(mcp_config);
} finally {
await removeContainer(id);
}
}, 10000);
});
@@ -26,11 +26,22 @@ variable "open_recent" {
default = false
}
variable "mcp_config" {
type = map(any)
description = "MCP server configuration for the IDE. When set, writes mcp_config.json in var.config_dir."
default = null
}
variable "protocol" {
type = string
description = "The URI protocol the IDE."
}
variable "config_dir" {
type = string
description = "The path of the IDE's configuration folder."
}
variable "coder_app_icon" {
type = string
description = "The icon of the coder_app."
@@ -85,21 +96,36 @@ resource "coder_app" "vscode-desktop" {
data.coder_workspace.me.access_url,
"&token=$SESSION_TOKEN",
])
}
/*
url = join("", [
"vscode://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" "vscode-desktop-mcp" {
agent_id = var.agent_id
count = var.mcp_config != null ? 1 : 0
icon = var.coder_app_icon
display_name = "${var.coder_app_display_name} MCP"
run_on_start = true
start_blocks_login = false
script = <<-EOT
#!/bin/sh
set -euo pipefail
IDE_CONFIG_FOLDER="${var.config_dir}"
IDE_MCP_CONFIG_PATH="$IDE_CONFIG_FOLDER/mcp_config.json"
mkdir -p "$IDE_CONFIG_FOLDER"
echo -n "${base64encode(jsonencode(var.mcp_config))}" | base64 -d > "$IDE_MCP_CONFIG_PATH"
chmod 600 "$IDE_MCP_CONFIG_PATH"
# Cursor/Windsurf use this config instead, no need for chmod as symlinks do not have modes
ln -s "$IDE_MCP_CONFIG_PATH" "$IDE_CONFIG_FOLDER/mcp.json"
EOT
}
output "ide_uri" {
value = coder_app.vscode-desktop.url
description = "IDE URI."
}
}