Merge branch 'main' into 35C4n0r/feat-agentapi-architecture-improv

This commit is contained in:
DevCats 2026-02-25 12:24:35 -06:00 committed by GitHub
commit f14d174afc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
27 changed files with 291 additions and 86 deletions

View File

@ -10,8 +10,6 @@ tags: [nextflow, workflow, hpc, bioinformatics]
A module that adds Nextflow to your Coder template.
![Nextflow](../../.images/nextflow.png)
```tf
module "nextflow" {
count = data.coder_workspace.me.start_count

View File

@ -3,20 +3,22 @@ set -o errexit
set -o pipefail
port=${1:-3284}
max_attempts=150
# This script waits for the agentapi server to start on port 3284.
# This script waits for the agentapi server to start on the given port.
# Each attempt sleeps 0.1s, so 150 attempts ≈ 15 seconds.
# It considers the server started after 3 consecutive successful responses.
agentapi_started=false
echo "Waiting for agentapi server to start on port $port..."
for i in $(seq 1 150); do
for i in $(seq 1 "$max_attempts"); do
for j in $(seq 1 3); do
sleep 0.1
if curl -fs -o /dev/null "http://localhost:$port/status"; then
echo "agentapi response received ($j/3)"
else
echo "agentapi server not responding ($i/15)"
echo "agentapi server not responding ($i/$max_attempts)"
continue 2
fi
done
@ -25,7 +27,7 @@ for i in $(seq 1 150); do
done
if [ "$agentapi_started" != "true" ]; then
echo "Error: agentapi server did not start on port $port after 15 seconds."
echo "Error: agentapi server did not start on port $port after $max_attempts attempts."
exit 1
fi

View File

@ -16,7 +16,7 @@ Uses the [Coder Remote VS Code Extension](https://github.com/coder/vscode-coder)
module "antigravity" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/antigravity/coder"
version = "1.0.0"
version = "1.0.1"
agent_id = coder_agent.example.id
}
```
@ -29,7 +29,7 @@ module "antigravity" {
module "antigravity" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/antigravity/coder"
version = "1.0.0"
version = "1.0.1"
agent_id = coder_agent.example.id
folder = "/home/coder/project"
}
@ -45,7 +45,7 @@ The following example configures Antigravity to use the GitHub MCP server with a
module "antigravity" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/antigravity/coder"
version = "1.0.0"
version = "1.0.1"
agent_id = coder_agent.example.id
folder = "/home/coder/project"
mcp = jsonencode({

View File

@ -66,15 +66,15 @@ locals {
module "vscode-desktop-core" {
source = "registry.coder.com/coder/vscode-desktop-core/coder"
version = "1.0.1"
version = "1.0.2"
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
coder_app_icon = "/icon/antigravity.svg"
coder_app_slug = var.slug
coder_app_display_name = var.display_name
coder_app_order = var.order
coder_app_group = var.group
folder = var.folder
open_recent = var.open_recent

View File

@ -16,7 +16,7 @@ Uses the [Coder Remote VS Code Extension](https://github.com/coder/vscode-coder)
module "cursor" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/cursor/coder"
version = "1.4.0"
version = "1.4.1"
agent_id = coder_agent.main.id
}
```
@ -29,7 +29,7 @@ module "cursor" {
module "cursor" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/cursor/coder"
version = "1.4.0"
version = "1.4.1"
agent_id = coder_agent.main.id
folder = "/home/coder/project"
}
@ -45,7 +45,7 @@ The following example configures Cursor to use the GitHub MCP server with authen
module "cursor" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/cursor/coder"
version = "1.4.0"
version = "1.4.1"
agent_id = coder_agent.main.id
folder = "/home/coder/project"
mcp = jsonencode({

View File

@ -66,7 +66,7 @@ locals {
module "vscode-desktop-core" {
source = "registry.coder.com/coder/vscode-desktop-core/coder"
version = "1.0.0"
version = "1.0.2"
agent_id = var.agent_id

View File

@ -18,7 +18,7 @@ Under the hood, this module uses the [coder dotfiles](https://coder.com/docs/v2/
module "dotfiles" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/dotfiles/coder"
version = "1.2.4"
version = "1.3.0"
agent_id = coder_agent.example.id
}
```
@ -31,7 +31,7 @@ module "dotfiles" {
module "dotfiles" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/dotfiles/coder"
version = "1.2.4"
version = "1.3.0"
agent_id = coder_agent.example.id
}
```
@ -42,7 +42,7 @@ module "dotfiles" {
module "dotfiles" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/dotfiles/coder"
version = "1.2.4"
version = "1.3.0"
agent_id = coder_agent.example.id
user = "root"
}
@ -54,14 +54,14 @@ module "dotfiles" {
module "dotfiles" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/dotfiles/coder"
version = "1.2.4"
version = "1.3.0"
agent_id = coder_agent.example.id
}
module "dotfiles-root" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/dotfiles/coder"
version = "1.2.4"
version = "1.3.0"
agent_id = coder_agent.example.id
user = "root"
dotfiles_uri = module.dotfiles.dotfiles_uri
@ -76,7 +76,7 @@ You can set a default dotfiles repository for all users by setting the `default_
module "dotfiles" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/dotfiles/coder"
version = "1.2.4"
version = "1.3.0"
agent_id = coder_agent.example.id
default_dotfiles_uri = "https://github.com/coder/dotfiles"
}

View File

@ -84,6 +84,12 @@ variable "manual_update" {
default = false
}
variable "post_clone_script" {
description = "Custom script to run after applying dotfiles. Runs every time, even if dotfiles were already applied."
type = string
default = null
}
data "coder_parameter" "dotfiles_uri" {
count = var.dotfiles_uri == null ? 1 : 0
type = "string"
@ -104,13 +110,15 @@ data "coder_parameter" "dotfiles_uri" {
locals {
dotfiles_uri = var.dotfiles_uri != null ? var.dotfiles_uri : data.coder_parameter.dotfiles_uri[0].value
user = var.user != null ? var.user : ""
encoded_post_clone_script = var.post_clone_script != null ? base64encode(var.post_clone_script) : ""
}
resource "coder_script" "dotfiles" {
agent_id = var.agent_id
script = templatefile("${path.module}/run.sh", {
DOTFILES_URI : local.dotfiles_uri,
DOTFILES_USER : local.user
DOTFILES_USER : local.user,
POST_CLONE_SCRIPT : local.encoded_post_clone_script
})
display_name = "Dotfiles"
icon = "/icon/dotfiles.svg"
@ -127,7 +135,8 @@ resource "coder_app" "dotfiles" {
group = var.group
command = templatefile("${path.module}/run.sh", {
DOTFILES_URI : local.dotfiles_uri,
DOTFILES_USER : local.user
DOTFILES_USER : local.user,
POST_CLONE_SCRIPT : local.encoded_post_clone_script
})
}

View File

@ -43,3 +43,14 @@ if [ -n "$${DOTFILES_URI// }" ]; then
sudo -u "$DOTFILES_USER" "$CODER_BIN" dotfiles "$DOTFILES_URI" -y 2>&1 | tee "$DOTFILES_USER_HOME/.dotfiles.log"
fi
fi
POST_CLONE_SCRIPT="${POST_CLONE_SCRIPT}"
if [ -n "$POST_CLONE_SCRIPT" ]; then
echo "Running post-clone script..."
POST_CLONE_TMP=$(mktemp)
echo "$POST_CLONE_SCRIPT" | base64 -d > "$POST_CLONE_TMP"
chmod +x "$POST_CLONE_TMP"
$POST_CLONE_TMP
rm "$POST_CLONE_TMP"
fi

View File

@ -42,7 +42,7 @@ module "jetbrains" {
version = "1.3.0"
agent_id = coder_agent.main.id
folder = "/home/coder/project"
default = ["PY", "IU"] # Pre-configure GoLand and IntelliJ IDEA
default = ["PY", "IU"] # Pre-configure PyCharm and IntelliJ IDEA
}
```

View File

@ -18,7 +18,7 @@ Uses the [Coder Remote VS Code Extension](https://github.com/coder/vscode-coder)
module "kiro" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/kiro/coder"
version = "1.2.0"
version = "1.2.1"
agent_id = coder_agent.main.id
}
```
@ -31,7 +31,7 @@ module "kiro" {
module "kiro" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/kiro/coder"
version = "1.2.0"
version = "1.2.1"
agent_id = coder_agent.main.id
folder = "/home/coder/project"
}
@ -47,7 +47,7 @@ The following example configures Kiro to use the GitHub MCP server with authenti
module "kiro" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/kiro/coder"
version = "1.2.0"
version = "1.2.1"
agent_id = coder_agent.main.id
folder = "/home/coder/project"
mcp = jsonencode({

View File

@ -53,7 +53,7 @@ locals {
module "vscode-desktop-core" {
source = "registry.coder.com/coder/vscode-desktop-core/coder"
version = "1.0.0"
version = "1.0.2"
agent_id = var.agent_id

View File

@ -14,7 +14,7 @@ Automatically install and run [Mux](https://github.com/coder/mux) in a Coder wor
module "mux" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/mux/coder"
version = "1.0.8"
version = "1.2.0"
agent_id = coder_agent.main.id
}
```
@ -37,7 +37,7 @@ module "mux" {
module "mux" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/mux/coder"
version = "1.0.8"
version = "1.2.0"
agent_id = coder_agent.main.id
}
```
@ -48,7 +48,7 @@ module "mux" {
module "mux" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/mux/coder"
version = "1.0.8"
version = "1.2.0"
agent_id = coder_agent.main.id
# Default is "latest"; set to a specific version to pin
install_version = "0.4.0"
@ -63,19 +63,34 @@ Start Mux with `mux server --add-project /path/to/project`:
module "mux" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/mux/coder"
version = "1.0.8"
version = "1.2.0"
agent_id = coder_agent.main.id
add-project = "/path/to/project"
}
```
### Pass Arbitrary `mux server` Arguments
Use `additional_arguments` to append additional arguments to `mux server`.
The module parses quoted values, so grouped arguments remain intact.
```tf
module "mux" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/mux/coder"
version = "1.2.0"
agent_id = coder_agent.main.id
additional_arguments = "--open-mode pinned --add-project '/workspaces/my repo'"
}
```
### Custom Port
```tf
module "mux" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/mux/coder"
version = "1.0.8"
version = "1.2.0"
agent_id = coder_agent.main.id
port = 8080
}
@ -89,7 +104,7 @@ Run an existing copy of Mux if found, otherwise install from npm:
module "mux" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/mux/coder"
version = "1.0.8"
version = "1.2.0"
agent_id = coder_agent.main.id
use_cached = true
}
@ -103,7 +118,7 @@ Run without installing from the network (requires Mux to be pre-installed):
module "mux" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/mux/coder"
version = "1.0.8"
version = "1.2.0"
agent_id = coder_agent.main.id
install = false
}

View File

@ -1,6 +1,11 @@
import { describe, expect, it } from "bun:test";
import {
executeScriptInContainer,
execContainer,
findResourceInstance,
readFileContainer,
removeContainer,
runContainer,
runTerraformApply,
runTerraformInit,
testRequiredVariables,
@ -40,6 +45,57 @@ describe("mux", async () => {
}
}, 60000);
it("parses custom additional_arguments", async () => {
const state = await runTerraformApply(import.meta.dir, {
agent_id: "foo",
install: false,
log_path: "/tmp/mux.log",
additional_arguments:
"--open-mode pinned --add-project '/workspaces/my repo'",
});
const instance = findResourceInstance(state, "coder_script");
const id = await runContainer("alpine/curl");
try {
const setup = await execContainer(id, [
"sh",
"-c",
`apk add --no-cache bash >/dev/null
mkdir -p /tmp/mux
cat <<'EOF' > /tmp/mux/mux
#!/usr/bin/env sh
i=1
for arg in "$@"; do
echo "arg$i=$arg"
i=$((i + 1))
done
EOF
chmod +x /tmp/mux/mux`,
]);
expect(setup.exitCode).toBe(0);
const output = await execContainer(id, ["sh", "-c", instance.script]);
if (output.exitCode !== 0) {
console.log("STDOUT:\n" + output.stdout);
console.log("STDERR:\n" + output.stderr);
}
expect(output.exitCode).toBe(0);
await execContainer(id, ["sh", "-c", "sleep 1"]);
const log = await readFileContainer(id, "/tmp/mux.log");
expect(log).toContain("arg1=server");
expect(log).toContain("arg2=--port");
expect(log).toContain("arg3=4000");
expect(log).toContain("arg4=--open-mode");
expect(log).toContain("arg5=pinned");
expect(log).toContain("arg6=--add-project");
expect(log).toContain("arg7=/workspaces/my repo");
} finally {
await removeContainer(id);
}
}, 60000);
it("runs with npm present", async () => {
const state = await runTerraformApply(import.meta.dir, {
agent_id: "foo",

View File

@ -7,6 +7,10 @@ terraform {
source = "coder/coder"
version = ">= 2.5"
}
random = {
source = "hashicorp/random"
version = ">= 3.0"
}
}
}
@ -51,6 +55,12 @@ variable "add-project" {
default = null
}
variable "additional_arguments" {
type = string
description = "Additional command-line arguments to pass to `mux server` (for example: `--add-project /path --open-mode pinned`)."
default = ""
}
variable "install_version" {
type = string
description = "The version or dist-tag of Mux to install."
@ -113,6 +123,22 @@ variable "open_in" {
}
}
# Per-module auth token for cross-site request protection.
# We pass this token into each mux process at launch time (process-scoped env)
# and include it in the app URL query string (?token=...).
#
# Why process-scoped env instead of a shared coder_env value:
# multiple mux module instances can target the same agent (different slug/port).
# A single global MUX_SERVER_AUTH_TOKEN env key would cause collisions.
resource "random_password" "mux_auth_token" {
length = 64
special = false
}
locals {
mux_auth_token = random_password.mux_auth_token.result
}
resource "coder_script" "mux" {
agent_id = var.agent_id
display_name = var.display_name
@ -122,9 +148,11 @@ resource "coder_script" "mux" {
PORT : var.port,
LOG_PATH : var.log_path,
ADD_PROJECT : var.add-project == null ? "" : var.add-project,
ADDITIONAL_ARGUMENTS : var.additional_arguments,
INSTALL_PREFIX : var.install_prefix,
OFFLINE : !var.install,
USE_CACHED : var.use_cached,
AUTH_TOKEN : local.mux_auth_token,
})
run_on_start = true
@ -140,7 +168,7 @@ resource "coder_app" "mux" {
agent_id = var.agent_id
slug = var.slug
display_name = var.display_name
url = "http://localhost:${var.port}"
url = "http://localhost:${var.port}?token=${local.mux_auth_token}"
icon = "/icon/mux.svg"
subdomain = var.subdomain
share = var.share
@ -154,5 +182,3 @@ resource "coder_app" "mux" {
threshold = 6
}
}

View File

@ -20,8 +20,10 @@ run "install_false_and_use_cached_conflict" {
]
}
# Needs command = apply because the URL contains random_password.result,
# which is unknown during plan.
run "custom_port" {
command = plan
command = apply
variables {
agent_id = "foo"
@ -29,8 +31,65 @@ run "custom_port" {
}
assert {
condition = resource.coder_app.mux.url == "http://localhost:8080"
error_message = "coder_app URL must use the configured port"
condition = startswith(resource.coder_app.mux.url, "http://localhost:8080?token=")
error_message = "coder_app URL must use the configured port and include auth token"
}
assert {
condition = trimprefix(resource.coder_app.mux.url, "http://localhost:8080?token=") == random_password.mux_auth_token.result
error_message = "URL token must match the generated auth token"
}
}
# Needs command = apply because random_password.result is unknown during plan.
run "auth_token_in_server_script" {
command = apply
variables {
agent_id = "foo"
}
assert {
condition = strcontains(resource.coder_script.mux.script, "MUX_SERVER_AUTH_TOKEN=")
error_message = "mux launch script must set MUX_SERVER_AUTH_TOKEN"
}
assert {
condition = strcontains(resource.coder_script.mux.script, random_password.mux_auth_token.result)
error_message = "mux launch script must use the generated auth token"
}
}
# Needs command = apply because random_password.result is unknown during plan.
run "auth_token_in_url" {
command = apply
variables {
agent_id = "foo"
}
assert {
condition = startswith(resource.coder_app.mux.url, "http://localhost:4000?token=")
error_message = "coder_app URL must include auth token query parameter"
}
assert {
condition = trimprefix(resource.coder_app.mux.url, "http://localhost:4000?token=") == random_password.mux_auth_token.result
error_message = "URL token must match the generated auth token"
}
}
run "custom_additional_arguments" {
command = plan
variables {
agent_id = "foo"
additional_arguments = "--open-mode pinned --add-project '/workspaces/my repo'"
}
assert {
condition = strcontains(resource.coder_script.mux.script, "--open-mode pinned --add-project '/workspaces/my repo'")
error_message = "mux launch script must include the configured additional arguments"
}
}
@ -62,5 +121,3 @@ run "use_cached_only_success" {
use_cached = true
}
}

View File

@ -9,7 +9,9 @@ function run_mux() {
rm -f "$HOME/.mux/server.lock"
local port_value
local auth_token_value
port_value="${PORT}"
auth_token_value="${AUTH_TOKEN}"
if [ -z "$port_value" ]; then
port_value="4000"
fi
@ -18,9 +20,25 @@ function run_mux() {
if [ -n "${ADD_PROJECT}" ]; then
set -- "$@" --add-project "${ADD_PROJECT}"
fi
# Parse additional user-supplied server arguments while preserving quoted groups.
if [ -n "${ADDITIONAL_ARGUMENTS}" ]; then
local parsed_additional_arguments
if ! parsed_additional_arguments="$(printf "%s\n" "${ADDITIONAL_ARGUMENTS}" | xargs -n1 printf "%s\n" 2> /dev/null)"; then
echo "❌ Failed to parse additional_arguments. Ensure quotes are balanced."
exit 1
fi
while IFS= read -r parsed_arg; do
[ -n "$parsed_arg" ] || continue
set -- "$@" "$parsed_arg"
done << EOF
$${parsed_additional_arguments}
EOF
fi
echo "🚀 Starting mux server on port $port_value..."
echo "Check logs at ${LOG_PATH}!"
PORT="$port_value" "$MUX_BINARY" "$@" > "${LOG_PATH}" 2>&1 &
MUX_SERVER_AUTH_TOKEN="$auth_token_value" PORT="$port_value" "$MUX_BINARY" "$@" > "${LOG_PATH}" 2>&1 &
}
# Check if mux is already installed for offline mode

View File

@ -16,15 +16,15 @@ 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.1"
version = "1.0.2"
agent_id = var.agent_id
web_app_icon = "/icon/code.svg"
web_app_slug = "vscode"
web_app_display_name = "VS Code Desktop"
web_app_order = var.order
web_app_group = var.group
coder_app_icon = "/icon/code.svg"
coder_app_slug = "vscode"
coder_app_display_name = "VS Code Desktop"
coder_app_order = var.order
coder_app_group = var.group
folder = var.folder
open_recent = var.open_recent

View File

@ -11,9 +11,9 @@ const appName = "vscode-desktop";
const defaultVariables = {
agent_id: "foo",
web_app_icon: "/icon/code.svg",
web_app_slug: "vscode",
web_app_display_name: "VS Code Desktop",
coder_app_icon: "/icon/code.svg",
coder_app_slug: "vscode",
coder_app_display_name: "VS Code Desktop",
protocol: "vscode",
};
@ -99,16 +99,16 @@ describe("vscode-desktop-core", async () => {
);
expect(coder_app?.instances[0].attributes.slug).toBe(
defaultVariables.web_app_slug,
defaultVariables.coder_app_slug,
);
expect(coder_app?.instances[0].attributes.display_name).toBe(
defaultVariables.web_app_display_name,
defaultVariables.coder_app_display_name,
);
});
it("sets order", async () => {
const state = await runTerraformApply(import.meta.dir, {
web_app_order: "5",
coder_app_order: "5",
...defaultVariables,
});
@ -122,7 +122,7 @@ describe("vscode-desktop-core", async () => {
it("sets group", async () => {
const state = await runTerraformApply(import.meta.dir, {
web_app_group: "web-app-group",
coder_app_group: "web-app-group",
...defaultVariables,
});

View File

@ -31,28 +31,28 @@ variable "protocol" {
description = "The URI protocol the IDE."
}
variable "web_app_icon" {
variable "coder_app_icon" {
type = string
description = "The icon of the coder_app."
}
variable "web_app_slug" {
variable "coder_app_slug" {
type = string
description = "The slug of the coder_app."
}
variable "web_app_display_name" {
variable "coder_app_display_name" {
type = string
description = "The display name of the coder_app."
}
variable "web_app_order" {
variable "coder_app_order" {
type = number
description = "The order of the coder_app."
default = null
}
variable "web_app_group" {
variable "coder_app_group" {
type = string
description = "The group of the coder_app."
default = null
@ -65,12 +65,12 @@ resource "coder_app" "vscode-desktop" {
agent_id = var.agent_id
external = true
icon = var.web_app_icon
slug = var.web_app_slug
display_name = var.web_app_display_name
icon = var.coder_app_icon
slug = var.coder_app_slug
display_name = var.coder_app_display_name
order = var.web_app_order
group = var.web_app_group
order = var.coder_app_order
group = var.coder_app_group
url = join("", [
var.protocol,

View File

@ -16,7 +16,7 @@ Uses the [Coder Remote VS Code Extension](https://github.com/coder/vscode-coder)
module "vscode" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/vscode-desktop/coder"
version = "1.2.0"
version = "1.2.1"
agent_id = coder_agent.main.id
}
```
@ -29,7 +29,7 @@ module "vscode" {
module "vscode" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/vscode-desktop/coder"
version = "1.2.0"
version = "1.2.1"
agent_id = coder_agent.main.id
folder = "/home/coder/project"
}

View File

@ -40,7 +40,7 @@ variable "group" {
module "vscode-desktop-core" {
source = "registry.coder.com/coder/vscode-desktop-core/coder"
version = "1.0.0"
version = "1.0.2"
agent_id = var.agent_id

View File

@ -16,7 +16,7 @@ Uses the [Coder Remote VS Code Extension](https://github.com/coder/vscode-coder)
module "windsurf" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/windsurf/coder"
version = "1.3.0"
version = "1.3.1"
agent_id = coder_agent.main.id
}
```
@ -29,7 +29,7 @@ module "windsurf" {
module "windsurf" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/windsurf/coder"
version = "1.3.0"
version = "1.3.1"
agent_id = coder_agent.main.id
folder = "/home/coder/project"
}
@ -45,7 +45,7 @@ The following example configures Windsurf to use the GitHub MCP server with auth
module "windsurf" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/windsurf/coder"
version = "1.3.0"
version = "1.3.1"
agent_id = coder_agent.main.id
folder = "/home/coder/project"
mcp = jsonencode({

View File

@ -65,7 +65,7 @@ locals {
module "vscode-desktop-core" {
source = "registry.coder.com/coder/vscode-desktop-core/coder"
version = "1.0.0"
version = "1.0.2"
agent_id = var.agent_id

View File

@ -27,8 +27,21 @@ This template provisions the following resources:
- Azure VM (ephemeral, deleted on stop)
- Managed disk (persistent, mounted to `/home/coder`)
- Resource group, virtual network, subnet, and network interface (persistent, required by the managed disk and VM)
This means, when the workspace restarts, any tools or files outside of the home directory are not persisted. To pre-bake tools into the workspace (e.g. `python3`), modify the VM image, or use a [startup script](https://registry.terraform.io/providers/coder/coder/latest/docs/resources/script). Alternatively, individual developers can [personalize](https://coder.com/docs/dotfiles) their workspaces with dotfiles.
### What happens on stop
When a workspace is **stopped**, only the VM is destroyed. The managed disk, resource group, virtual network, subnet, and network interface all persist. This is by design — the managed disk retains your `/home/coder` data across workspace restarts, and the other resources remain because the disk depends on them.
This means you will see these Azure resources in your subscription even when a workspace is stopped. This is expected behavior.
### What happens on delete
When a workspace is **deleted**, all resources are destroyed, including the resource group, networking resources, and managed disk.
### Workspace restarts
Since the VM is ephemeral, any tools or files outside of the home directory are not persisted across restarts. To pre-bake tools into the workspace (e.g. `python3`), modify the VM image, or use a [startup script](https://registry.terraform.io/providers/coder/coder/latest/docs/resources/script). Alternatively, individual developers can [personalize](https://coder.com/docs/dotfiles) their workspaces with dotfiles.
> [!NOTE]
> This template is designed to be a starting point! Edit the Terraform to extend the template to support your use case.

View File

@ -16,7 +16,7 @@ Uses the [Coder Remote VS Code Extension](https://github.com/coder/vscode-coder)
module "positron" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/cytoshahar/positron/coder"
version = "1.0.1"
version = "1.0.2"
agent_id = coder_agent.main.id
}
```
@ -29,7 +29,7 @@ module "positron" {
module "positron" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/cytoshahar/positron/coder"
version = "1.0.1"
version = "1.0.2"
agent_id = coder_agent.main.id
folder = "/home/coder/project"
}

View File

@ -41,13 +41,13 @@ variable "group" {
variable "slug" {
type = string
description = "The slug of the app."
default = "cursor"
default = "positron"
}
variable "display_name" {
type = string
description = "The display name of the app."
default = "Cursor Desktop"
default = "Positron Desktop"
}
data "coder_workspace" "me" {}
@ -55,7 +55,7 @@ data "coder_workspace_owner" "me" {}
module "vscode-desktop-core" {
source = "registry.coder.com/coder/vscode-desktop-core/coder"
version = "1.0.0"
version = "1.0.2"
agent_id = var.agent_id