Compare commits

..

10 Commits

Author SHA1 Message Date
DevelopmentCats 85fe68275c feat(coder/modules/claude-code): testing claude-code path 2025-12-22 11:44:03 -06:00
35C4n0r 36089612ef chore(coder/modules/claude-code): bump agentapi version to 0.11.6 (#619)
## Description
bump agentapi version to 0.11.6. 
This version of agentapi introduces tool_call logging and improved
tool_call parsing

## Type of Change

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

## Module Information

<!-- Delete this section if not applicable -->

**Path:** `registry/coder/modules/claude-code`  
**New version:** `v4.2.8`  
**Breaking change:** [ ] Yes [x] No

## Testing & Validation

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

## Related Issues

<!-- Link related issues or write "None" if not applicable -->
2025-12-19 23:45:25 +05:30
Rowan Smith ac44ad862a chore: update Kubernetes resources to v1 API for provider v3 compatibility (#616)
## Description

As part of
https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/guides/v3-upgrade-guide
various resources change from non versioned to versioned. This PR
changes the Coder authored templates to versioned resources.

- Updated kubernetes_persistent_volume_claim to
kubernetes_persistent_volume_claim_v1
- Updated kubernetes_deployment to kubernetes_deployment_v1
- Updated kubernetes_pod to kubernetes_pod_v1
- Updated kubernetes_secret to kubernetes_secret_v1
- Updated all resource references and dependencies

I also had to fix up a couple of templates, i.e. remove `agent_name` as
it wasn't valid usage, `agent_id` remains. The `source` parameter for
jetbrains module in
[registry/coder/templates/kubernetes-envbox/main.tf](https://github.com/coder/registry/pull/616/changes#diff-83996ad9def3fae3b69981faee7d682964acc8716a4d04edfd7c4374f0a1d15c)
also had to be fixed.

## Type of Change

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

## Template Information

**Path:** 

- registry/coder/templates/kubernetes
- registry/coder/templates/kubernetes-devcontainer
- registry/coder/templates/kubernetes-envbox

## Testing & Validation

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

## Related Issues
2025-12-19 08:11:30 +11:00
Atif Ali ef5a903edf fix(zed): fix settings JSON parsing with base64 encoding (#604)
## Problem

The Zed module's settings parsing was broken. The previous
implementation used quote escaping:

```hcl
SETTINGS_JSON='${replace(var.settings, "\"", "\\\"")}'
```

This produced invalid JSON like `{\"theme\":\"dark\"}` which **jq could
not parse** because the backslash-escaped quotes are not valid JSON
syntax.

## Solution

Changed to use base64 encoding internally:

```hcl
locals {
  settings_b64 = var.settings != "" ? base64encode(var.settings) : ""
}

# In the script:
SETTINGS_B64='${local.settings_b64}'
SETTINGS_JSON="$(echo -n "${SETTINGS_B64}" | base64 -d)"
```

**User interface remains the same** - users still provide plain JSON via
`jsonencode()` or heredoc:

```hcl
module "zed" {
  source   = "..."
  agent_id = coder_agent.main.id
  settings = jsonencode({
    theme    = "dark"
    fontSize = 14
  })
}
```

## Testing

Added comprehensive tests:

**Terraform tests (5):**
- URL generation (default, folder, agent_name)
- Settings base64 encoding verification
- Empty settings edge case

**Container e2e tests (3):**
- Creates settings file with correct JSON (including special chars:
quotes, backslashes, URLs)
- Merges with existing settings via jq
- Exits early with empty settings

Also fixed existing tests to use `override_data` for proper workspace
mocking.

---------

Signed-off-by: Muhammad Atif Ali <me@matifali.dev>
Co-authored-by: DevCats <christofer@coder.com>
2025-12-17 16:17:06 -06:00
Atif Ali 4b7128b17e chore: link vscode-web and code-server comparison docs (#607)
link vscode-web and code-server comparison docs in README. Also fixes a
drive-by version to match expected versioning.

Co-authored-by: DevCats <christofer@coder.com>
2025-12-17 15:46:10 -06:00
DevCats 77a3e74e0b feat: enhance version bump script and CI workflow with ci mode (#615)
## Description

Add CI mode to version bump script to output Pass or Fail with a less
verbose comment when it fails
<!-- Briefly describe what this PR does and why -->

## Type of Change

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

## Testing & Validation

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

## Related Issues

<!-- Link related issues or write "None" if not applicable -->
2025-12-17 15:31:11 -06:00
Danielle Maywood 311de23454 refactor(coder-labs/auggie): support terraform provider coder v2.12.0 (#494)
## Description

Updates the module to use the new version of the agentapi module for
Coder 2.28

## Type of Change

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

## Module Information

**Path:** `registry/coder-labs/modules/auggie`  
**New version:** `v0.3.0`  
**Breaking change:** [x] Yes [ ] No

## Testing & Validation

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

## Related Issues

- https://github.com/coder/internal/issues/1065

## Related PRs

- https://github.com/coder/registry/pull/485

Co-authored-by: DevCats <christofer@coder.com>
2025-12-17 13:16:12 -06:00
Danielle Maywood f66f61d724 refactor(coder-labs/sourcegraph-amp): support terraform provider coder v2.12.0 (#495)
## Description

Updates the module to use the new version of the agentapi module for
Coder 2.28

## Type of Change

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

## Module Information

**Path:** `registry/coder-labs/modules/sourcegraph-amp`  
**New version:** `v3.0.0`  
**Breaking change:** [x] Yes [ ] No

## Testing & Validation

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

## Related Issues

- https://github.com/coder/internal/issues/1065

## Related PRs

- https://github.com/coder/registry/pull/485

---------

Co-authored-by: DevCats <christofer@coder.com>
2025-12-17 11:54:28 -06:00
Danielle Maywood 631bf027c6 refactor(coder-labs/gemini): support terraform provider coder v2.12.0 (#493)
## Description

Updates the module to use the new version of the agentapi module for
Coder 2.28

## Type of Change

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

## Module Information

**Path:** `registry/[namespace]/modules/[module-name]`  
**New version:** `v3.0.0`  
**Breaking change:** [x] Yes [ ] No

## Testing & Validation

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

## Related Issues

- https://github.com/coder/internal/issues/1065

## Related PRs

- https://github.com/coder/registry/pull/485

---------

Co-authored-by: DevCats <christofer@coder.com>
2025-12-17 10:00:44 -06:00
Danielle Maywood eb4c28fc61 refactor(coder-labs/copilot): support terraform provider coder v2.12.0 (#492)
## Description

Updates the module to use the new version of the agentapi module for
Coder 2.28

## Type of Change

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

## Module Information

**Path:** `registry/coder-labs/modules/copilot`  
**New version:** `v0.3.0`  
**Breaking change:** [x] Yes [ ] No

## Testing & Validation

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

## Related Issues

- https://github.com/coder/internal/issues/1065

## Related PRs

- https://github.com/coder/registry/pull/485

Co-authored-by: DevCats <christofer@coder.com>
2025-12-17 15:19:21 +00:00
21 changed files with 337 additions and 182 deletions
+40 -11
View File
@@ -1,14 +1,18 @@
#!/bin/bash
# Version Bump Script
# Usage: ./version-bump.sh <bump_type> [base_ref]
# Usage: ./version-bump.sh [--ci] <bump_type> [base_ref]
# --ci: CI mode - run bump, check for changes, exit 1 if changes needed
# bump_type: patch, minor, or major
# base_ref: base reference for diff (default: origin/main)
set -euo pipefail
CI_MODE=false
usage() {
echo "Usage: $0 <bump_type> [base_ref]"
echo "Usage: $0 [--ci] <bump_type> [base_ref]"
echo " --ci: CI mode - validates versions are already bumped (exits 1 if not)"
echo " bump_type: patch, minor, or major"
echo " base_ref: base reference for diff (default: origin/main)"
echo ""
@@ -16,6 +20,7 @@ usage() {
echo " $0 patch # Update versions with patch bump"
echo " $0 minor # Update versions with minor bump"
echo " $0 major # Update versions with major bump"
echo " $0 --ci patch # CI check: verify patch bump has been applied"
exit 1
}
@@ -85,7 +90,7 @@ update_readme_version() {
in_module_block = 0
if (module_has_target_source) {
num_lines = split(module_content, lines, "\n")
for (i = 1; i <= num_lines; i++) {
for (i = 1; i < num_lines; i++) {
line = lines[i]
if (line ~ /^[[:space:]]*version[[:space:]]*=/) {
match(line, /^[[:space:]]*/)
@@ -115,6 +120,11 @@ update_readme_version() {
}
main() {
if [ "${1:-}" = "--ci" ]; then
CI_MODE=true
shift
fi
if [ $# -lt 1 ] || [ $# -gt 2 ]; then
usage
fi
@@ -152,6 +162,8 @@ main() {
local untagged_modules=""
local has_changes=false
declare -a modified_readme_files=()
while IFS= read -r module_path; do
if [ -z "$module_path" ]; then continue; fi
@@ -202,6 +214,7 @@ main() {
if update_readme_version "$readme_path" "$namespace" "$module_name" "$new_version"; then
updated_readmes="$updated_readmes\n- $namespace/$module_name"
modified_readme_files+=("$readme_path")
has_changes=true
fi
@@ -210,19 +223,22 @@ main() {
done <<< "$modules"
# Always run formatter to ensure consistent formatting
echo "🔧 Running formatter to ensure consistent formatting..."
if command -v bun > /dev/null 2>&1; then
bun fmt > /dev/null 2>&1 || echo "⚠️ Warning: bun fmt failed, but continuing..."
else
echo "⚠️ Warning: bun not found, skipping formatting"
if [ ${#modified_readme_files[@]} -gt 0 ]; then
echo "🔧 Formatting modified README files..."
if command -v bun > /dev/null 2>&1; then
for readme_file in "${modified_readme_files[@]}"; do
bun run prettier --write "$readme_file" 2> /dev/null || true
done
else
echo "⚠️ Warning: bun not found, skipping formatting"
fi
echo ""
fi
echo ""
echo "📋 Summary:"
echo "Bump Type: $bump_type"
echo ""
echo "Modules Updated:"
echo "Modules Processed:"
echo -e "$bumped_modules"
echo ""
@@ -239,6 +255,19 @@ main() {
echo ""
fi
if [ "$CI_MODE" = true ]; then
echo "🔍 Comparing files to committed versions..."
if git diff --quiet; then
echo "✅ PASS: All versions match - no changes needed"
exit 0
else
echo "❌ FAIL: Module versions need to be updated"
echo ""
echo "Run './.github/scripts/version-bump.sh $bump_type' locally and commit the changes"
exit 1
fi
fi
if [ "$has_changes" = true ]; then
echo "✅ Version bump completed successfully!"
echo "📝 README files have been updated with new versions."
+22 -49
View File
@@ -55,62 +55,35 @@ jobs:
;;
esac
- name: Check version bump requirements
id: version-check
run: |
output_file=$(mktemp)
if ./.github/scripts/version-bump.sh "${{ steps.bump-type.outputs.type }}" origin/main > "$output_file" 2>&1; then
echo "Script completed successfully"
else
echo "Script failed"
cat "$output_file"
exit 1
fi
- name: Check version bump
run: ./.github/scripts/version-bump.sh --ci "${{ steps.bump-type.outputs.type }}" origin/main
{
echo "output<<EOF"
cat "$output_file"
echo "EOF"
} >> $GITHUB_OUTPUT
cat "$output_file"
if git diff --quiet; then
echo "versions_up_to_date=true" >> $GITHUB_OUTPUT
echo "✅ All module versions are already up to date"
else
echo "versions_up_to_date=false" >> $GITHUB_OUTPUT
echo "❌ Module versions need to be updated"
echo "Files that would be changed:"
git diff --name-only
echo ""
echo "Diff preview:"
git diff
git checkout .
git clean -fd
exit 1
fi
- name: Comment on PR - Failure
if: failure() && steps.version-check.outputs.versions_up_to_date == 'false'
- name: Comment on PR - Version bump required
if: failure()
uses: actions/github-script@v8
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const output = `${{ steps.version-check.outputs.output }}`;
const bumpType = `${{ steps.bump-type.outputs.type }}`;
let comment = `## ❌ Version Bump Validation Failed\n\n`;
comment += `**Bump Type:** \`${bumpType}\`\n\n`;
comment += `Module versions need to be updated but haven't been bumped yet.\n\n`;
comment += `**Required Actions:**\n`;
comment += `1. Run the version bump script locally: \`./.github/scripts/version-bump.sh ${bumpType}\`\n`;
comment += `2. Commit the changes: \`git add . && git commit -m "chore: bump module versions (${bumpType})"\`\n`;
comment += `3. Push the changes: \`git push\`\n\n`;
comment += `### Script Output:\n\`\`\`\n${output}\n\`\`\`\n\n`;
comment += `> Please update the module versions and push the changes to continue.`;
const comment = [
'## Version Bump Required',
'',
'One or more modules in this PR need their versions updated.',
'',
'**To fix this:**',
'1. Run the version bump script locally:',
' ```bash',
` ./.github/scripts/version-bump.sh ${bumpType}`,
' ```',
'2. Commit the changes:',
' ```bash',
` git add . && git commit -m "chore: bump module versions (${bumpType})"`,
' ```',
'3. Push your changes',
'',
'The CI will automatically re-run once you push the updated versions.'
].join('\n');
github.rest.issues.createComment({
issue_number: context.issue.number,
+3 -3
View File
@@ -13,7 +13,7 @@ Run Auggie CLI in your workspace to access Augment's AI coding assistant with ad
```tf
module "auggie" {
source = "registry.coder.com/coder-labs/auggie/coder"
version = "0.2.2"
version = "0.3.0"
agent_id = coder_agent.example.id
folder = "/home/coder/project"
}
@@ -47,7 +47,7 @@ module "coder-login" {
module "auggie" {
source = "registry.coder.com/coder-labs/auggie/coder"
version = "0.2.2"
version = "0.3.0"
agent_id = coder_agent.example.id
folder = "/home/coder/project"
@@ -103,7 +103,7 @@ EOF
```tf
module "auggie" {
source = "registry.coder.com/coder-labs/auggie/coder"
version = "0.2.2"
version = "0.3.0"
agent_id = coder_agent.example.id
folder = "/home/coder/project"
+7 -3
View File
@@ -4,7 +4,7 @@ terraform {
required_providers {
coder = {
source = "coder/coder"
version = ">= 2.7"
version = ">= 2.12"
}
}
}
@@ -179,7 +179,7 @@ locals {
module "agentapi" {
source = "registry.coder.com/coder/agentapi/coder"
version = "1.2.0"
version = "2.0.0"
agent_id = var.agent_id
folder = local.folder
@@ -229,4 +229,8 @@ module "agentapi" {
ARG_MCP_CONFIG='${var.mcp != null ? base64encode(replace(var.mcp, "'", "'\\''")) : ""}' \
/tmp/install.sh
EOT
}
}
output "task_app_id" {
value = module.agentapi.task_app_id
}
@@ -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.2.3"
version = "0.3.0"
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.2.3"
version = "0.3.0"
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.2.3"
version = "0.3.0"
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.2.3"
version = "0.3.0"
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.2.3"
version = "0.3.0"
agent_id = coder_agent.example.id
workdir = "/home/coder"
report_tasks = false
+9 -5
View File
@@ -3,7 +3,7 @@ terraform {
required_providers {
coder = {
source = "coder/coder"
version = ">= 2.7"
version = ">= 2.12"
}
}
}
@@ -242,7 +242,7 @@ resource "coder_env" "github_token" {
module "agentapi" {
source = "registry.coder.com/coder/agentapi/coder"
version = "1.2.0"
version = "2.0.0"
agent_id = var.agent_id
folder = local.workdir
@@ -268,7 +268,7 @@ module "agentapi" {
set -o pipefail
echo -n '${base64encode(local.start_script)}' | base64 -d > /tmp/start.sh
chmod +x /tmp/start.sh
ARG_WORKDIR='${local.workdir}' \
ARG_AI_PROMPT='${base64encode(var.ai_prompt)}' \
ARG_SYSTEM_PROMPT='${base64encode(local.final_system_prompt)}' \
@@ -288,7 +288,7 @@ module "agentapi" {
set -o pipefail
echo -n '${base64encode(local.install_script)}' | base64 -d > /tmp/install.sh
chmod +x /tmp/install.sh
ARG_MCP_APP_STATUS_SLUG='${local.app_slug}' \
ARG_REPORT_TASKS='${var.report_tasks}' \
ARG_WORKDIR='${local.workdir}' \
@@ -299,4 +299,8 @@ module "agentapi" {
ARG_COPILOT_MODEL='${var.copilot_model}' \
/tmp/install.sh
EOT
}
}
output "task_app_id" {
value = module.agentapi.task_app_id
}
+4 -4
View File
@@ -13,7 +13,7 @@ Run [Gemini CLI](https://github.com/google-gemini/gemini-cli) in your workspace
```tf
module "gemini" {
source = "registry.coder.com/coder-labs/gemini/coder"
version = "2.1.2"
version = "3.0.0"
agent_id = coder_agent.main.id
folder = "/home/coder/project"
}
@@ -46,7 +46,7 @@ variable "gemini_api_key" {
module "gemini" {
source = "registry.coder.com/coder-labs/gemini/coder"
version = "2.1.2"
version = "3.0.0"
agent_id = coder_agent.main.id
gemini_api_key = var.gemini_api_key
folder = "/home/coder/project"
@@ -94,7 +94,7 @@ data "coder_parameter" "ai_prompt" {
module "gemini" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder-labs/gemini/coder"
version = "2.1.2"
version = "3.0.0"
agent_id = coder_agent.main.id
gemini_api_key = var.gemini_api_key
gemini_model = "gemini-2.5-flash"
@@ -118,7 +118,7 @@ For enterprise users who prefer Google's Vertex AI platform:
```tf
module "gemini" {
source = "registry.coder.com/coder-labs/gemini/coder"
version = "2.1.2"
version = "3.0.0"
agent_id = coder_agent.main.id
gemini_api_key = var.gemini_api_key
folder = "/home/coder/project"
+7 -3
View File
@@ -4,7 +4,7 @@ terraform {
required_providers {
coder = {
source = "coder/coder"
version = ">= 2.7"
version = ">= 2.12"
}
}
}
@@ -177,7 +177,7 @@ EOT
module "agentapi" {
source = "registry.coder.com/coder/agentapi/coder"
version = "1.2.0"
version = "2.0.0"
agent_id = var.agent_id
folder = local.folder
@@ -225,4 +225,8 @@ module "agentapi" {
GEMINI_TASK_PROMPT='${var.task_prompt}' \
/tmp/start.sh
EOT
}
}
output "task_app_id" {
value = module.agentapi.task_app_id
}
@@ -13,7 +13,7 @@ Run [Amp CLI](https://ampcode.com/) in your workspace to access Sourcegraph's AI
```tf
module "amp-cli" {
source = "registry.coder.com/coder-labs/sourcegraph-amp/coder"
version = "2.1.0"
version = "3.0.0"
agent_id = coder_agent.example.id
amp_api_key = var.amp_api_key
install_amp = true
@@ -48,7 +48,7 @@ variable "amp_api_key" {
module "amp-cli" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder-labs/sourcegraph-amp/coder"
amp_version = "2.1.0"
amp_version = "3.0.0"
agent_id = coder_agent.example.id
amp_api_key = var.amp_api_key # recommended for tasks usage
workdir = "/home/coder/project"
@@ -110,6 +110,7 @@ describe("amp", async () => {
const { id } = await setup({
skipAmpMock: true,
moduleVariables: {
install_via_npm: "true",
amp_version: "0.0.1755964909-g31e083",
},
});
@@ -4,7 +4,7 @@ terraform {
required_providers {
coder = {
source = "coder/coder"
version = ">= 2.7"
version = ">= 2.12"
}
external = {
source = "hashicorp/external"
@@ -140,7 +140,7 @@ variable "base_amp_config" {
type = string
description = <<-EOT
Base AMP configuration in JSON format. Can be overridden to customize AMP settings.
If empty, defaults enable thinking and todos for autonomous operation. Additional options include:
- "amp.permissions": [] (tool permissions)
- "amp.tools.stopTimeout": 600 (extend timeout for long operations)
@@ -148,7 +148,7 @@ variable "base_amp_config" {
- "amp.tools.disable": ["builtin:open"] (disable tools for containers)
- "amp.git.commit.ampThread.enabled": true (link commits to threads)
- "amp.git.commit.coauthor.enabled": true (add Amp as co-author)
Reference: https://ampcode.com/manual
EOT
default = ""
@@ -220,7 +220,7 @@ locals {
module "agentapi" {
source = "registry.coder.com/coder/agentapi/coder"
version = "1.2.0"
version = "2.0.0"
agent_id = var.agent_id
folder = local.workdir
@@ -268,4 +268,6 @@ module "agentapi" {
EOT
}
output "task_app_id" {
value = module.agentapi.task_app_id
}
+7 -7
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.2.7"
version = "4.2.8"
agent_id = coder_agent.main.id
workdir = "/home/coder/project"
claude_api_key = "xxxx-xxxxx-xxxx"
@@ -45,7 +45,7 @@ This example shows how to configure the Claude Code module to run the agent behi
```tf
module "claude-code" {
source = "dev.registry.coder.com/coder/claude-code/coder"
version = "4.2.7"
version = "4.2.8"
agent_id = coder_agent.main.id
workdir = "/home/coder/project"
enable_boundary = true
@@ -72,7 +72,7 @@ data "coder_parameter" "ai_prompt" {
module "claude-code" {
source = "registry.coder.com/coder/claude-code/coder"
version = "4.2.7"
version = "4.2.8"
agent_id = coder_agent.main.id
workdir = "/home/coder/project"
@@ -108,7 +108,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.2.7"
version = "4.2.8"
agent_id = coder_agent.main.id
workdir = "/home/coder/project"
install_claude_code = true
@@ -130,7 +130,7 @@ variable "claude_code_oauth_token" {
module "claude-code" {
source = "registry.coder.com/coder/claude-code/coder"
version = "4.2.7"
version = "4.2.8"
agent_id = coder_agent.main.id
workdir = "/home/coder/project"
claude_code_oauth_token = var.claude_code_oauth_token
@@ -203,7 +203,7 @@ resource "coder_env" "bedrock_api_key" {
module "claude-code" {
source = "registry.coder.com/coder/claude-code/coder"
version = "4.2.7"
version = "4.2.8"
agent_id = coder_agent.main.id
workdir = "/home/coder/project"
model = "global.anthropic.claude-sonnet-4-5-20250929-v1:0"
@@ -260,7 +260,7 @@ resource "coder_env" "google_application_credentials" {
module "claude-code" {
source = "registry.coder.com/coder/claude-code/coder"
version = "4.2.7"
version = "4.2.8"
agent_id = coder_agent.main.id
workdir = "/home/coder/project"
model = "claude-sonnet-4@20250514"
+8 -2
View File
@@ -86,7 +86,7 @@ variable "install_agentapi" {
variable "agentapi_version" {
type = string
description = "The version of AgentAPI to install."
default = "v0.11.4"
default = "v0.11.6"
}
variable "ai_prompt" {
@@ -252,6 +252,12 @@ variable "compile_boundary_from_source" {
default = false
}
variable "claude_binary_path" {
type = string
description = "The path to add to PATH for the Claude binary."
default = "$HOME/.local/bin"
}
resource "coder_env" "claude_code_md_path" {
count = var.claude_md_path == "" ? 0 : 1
@@ -291,7 +297,7 @@ resource "coder_env" "disable_autoupdater" {
resource "coder_env" "claude_binary_path" {
agent_id = var.agent_id
name = "PATH"
value = "$HOME/.local/bin:$PATH"
value = "${var.claude_binary_path}:$PATH"
}
locals {
+11 -9
View File
@@ -14,7 +14,7 @@ Automatically install [code-server](https://github.com/coder/code-server) in a w
module "code-server" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/code-server/coder"
version = "1.4.1"
version = "1.4.2"
agent_id = coder_agent.example.id
}
```
@@ -29,9 +29,9 @@ module "code-server" {
module "code-server" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/code-server/coder"
version = "1.4.1"
version = "1.4.2"
agent_id = coder_agent.example.id
install_version = "1.4.1"
install_version = "4.106.3"
}
```
@@ -43,7 +43,7 @@ Install the Dracula theme from [OpenVSX](https://open-vsx.org/):
module "code-server" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/code-server/coder"
version = "1.4.1"
version = "1.4.2"
agent_id = coder_agent.example.id
extensions = [
"dracula-theme.theme-dracula"
@@ -61,7 +61,7 @@ Configure VS Code's [settings.json](https://code.visualstudio.com/docs/getstarte
module "code-server" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/code-server/coder"
version = "1.4.1"
version = "1.4.2"
agent_id = coder_agent.example.id
extensions = ["dracula-theme.theme-dracula"]
settings = {
@@ -78,7 +78,7 @@ Just run code-server in the background, don't fetch it from GitHub:
module "code-server" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/code-server/coder"
version = "1.4.1"
version = "1.4.2"
agent_id = coder_agent.example.id
extensions = ["dracula-theme.theme-dracula", "ms-azuretools.vscode-docker"]
}
@@ -92,7 +92,7 @@ You can pass additional command-line arguments to code-server using the `additio
module "code-server" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/code-server/coder"
version = "1.4.1"
version = "1.4.2"
agent_id = coder_agent.example.id
additional_args = "--disable-workspace-trust"
}
@@ -108,7 +108,7 @@ Run an existing copy of code-server if found, otherwise download from GitHub:
module "code-server" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/code-server/coder"
version = "1.4.1"
version = "1.4.2"
agent_id = coder_agent.example.id
use_cached = true
extensions = ["dracula-theme.theme-dracula", "ms-azuretools.vscode-docker"]
@@ -121,8 +121,10 @@ Just run code-server in the background, don't fetch it from GitHub:
module "code-server" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/code-server/coder"
version = "1.4.1"
version = "1.4.2"
agent_id = coder_agent.example.id
offline = true
}
```
Some of the key differences between code-server and [VS Code Web](https://registry.coder.com/modules/coder/vscode-web) are listed in [docs](https://coder.com/docs/user-guides/workspace-access/code-server#differences-between-code-server-and-vs-code-web).
+6 -5
View File
@@ -19,7 +19,7 @@ Zed is a high-performance, multiplayer code editor from the creators of Atom and
module "zed" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/zed/coder"
version = "1.1.3"
version = "1.1.4"
agent_id = coder_agent.main.id
}
```
@@ -32,7 +32,7 @@ module "zed" {
module "zed" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/zed/coder"
version = "1.1.3"
version = "1.1.4"
agent_id = coder_agent.main.id
folder = "/home/coder/project"
}
@@ -44,7 +44,7 @@ module "zed" {
module "zed" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/zed/coder"
version = "1.1.3"
version = "1.1.4"
agent_id = coder_agent.main.id
display_name = "Zed Editor"
order = 1
@@ -57,7 +57,7 @@ module "zed" {
module "zed" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/zed/coder"
version = "1.1.3"
version = "1.1.4"
agent_id = coder_agent.main.id
agent_name = coder_agent.example.name
}
@@ -73,7 +73,7 @@ You can declaratively set/merge settings with the `settings` input. Provide a JS
module "zed" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/zed/coder"
version = "1.1.3"
version = "1.1.4"
agent_id = coder_agent.main.id
settings = jsonencode({
@@ -85,6 +85,7 @@ module "zed" {
env = {}
}
}
})
}
+98 -46
View File
@@ -1,5 +1,9 @@
import { describe, expect, it } from "bun:test";
import {
execContainer,
findResourceInstance,
removeContainer,
runContainer,
runTerraformApply,
runTerraformInit,
testRequiredVariables,
@@ -12,66 +16,114 @@ describe("zed", async () => {
agent_id: "foo",
});
it("default output", async () => {
it("creates settings file with correct JSON", async () => {
const settings = {
theme: "One Dark",
buffer_font_size: 14,
vim_mode: true,
telemetry: {
diagnostics: false,
metrics: false,
},
// Test special characters: single quotes, backslashes, URLs
message: "it's working",
path: "C:\\Users\\test",
api_url: "https://api.example.com/v1?token=abc&user=test",
};
const state = await runTerraformApply(import.meta.dir, {
agent_id: "foo",
settings: JSON.stringify(settings),
});
expect(state.outputs.zed_url.value).toBe("zed://ssh/default.coder");
const coder_app = state.resources.find(
(res) => res.type === "coder_app" && res.name === "zed",
);
const instance = findResourceInstance(state, "coder_script");
const id = await runContainer("alpine:latest");
expect(coder_app).not.toBeNull();
expect(coder_app?.instances.length).toBe(1);
expect(coder_app?.instances[0].attributes.order).toBeNull();
});
try {
const result = await execContainer(id, ["sh", "-c", instance.script]);
expect(result.exitCode).toBe(0);
const catResult = await execContainer(id, [
"cat",
"/root/.config/zed/settings.json",
]);
expect(catResult.exitCode).toBe(0);
const written = JSON.parse(catResult.stdout.trim());
expect(written).toEqual(settings);
} finally {
await removeContainer(id);
}
}, 30000);
it("merges settings with existing file when jq available", async () => {
const existingSettings = {
theme: "Solarized Dark",
vim_mode: true,
};
const newSettings = {
theme: "One Dark",
buffer_font_size: 14,
};
it("adds folder", async () => {
const state = await runTerraformApply(import.meta.dir, {
agent_id: "foo",
folder: "/foo/bar",
settings: JSON.stringify(newSettings),
});
expect(state.outputs.zed_url.value).toBe("zed://ssh/default.coder/foo/bar");
});
it("expect order to be set", async () => {
const instance = findResourceInstance(state, "coder_script");
const id = await runContainer("alpine:latest");
try {
// Install jq and create existing settings file
await execContainer(id, ["apk", "add", "--no-cache", "jq"]);
await execContainer(id, ["mkdir", "-p", "/root/.config/zed"]);
await execContainer(id, [
"sh",
"-c",
`echo '${JSON.stringify(existingSettings)}' > /root/.config/zed/settings.json`,
]);
const result = await execContainer(id, ["sh", "-c", instance.script]);
expect(result.exitCode).toBe(0);
const catResult = await execContainer(id, [
"cat",
"/root/.config/zed/settings.json",
]);
expect(catResult.exitCode).toBe(0);
const merged = JSON.parse(catResult.stdout.trim());
expect(merged.theme).toBe("One Dark"); // overwritten
expect(merged.buffer_font_size).toBe(14); // added
expect(merged.vim_mode).toBe(true); // preserved
} finally {
await removeContainer(id);
}
}, 30000);
it("exits early with empty settings", async () => {
const state = await runTerraformApply(import.meta.dir, {
agent_id: "foo",
order: "22",
settings: "",
});
const coder_app = state.resources.find(
(res) => res.type === "coder_app" && res.name === "zed",
);
const instance = findResourceInstance(state, "coder_script");
const id = await runContainer("alpine:latest");
expect(coder_app).not.toBeNull();
expect(coder_app?.instances.length).toBe(1);
expect(coder_app?.instances[0].attributes.order).toBe(22);
});
try {
const result = await execContainer(id, ["sh", "-c", instance.script]);
expect(result.exitCode).toBe(0);
it("expect display_name to be set", async () => {
const state = await runTerraformApply(import.meta.dir, {
agent_id: "foo",
display_name: "Custom Zed",
});
const coder_app = state.resources.find(
(res) => res.type === "coder_app" && res.name === "zed",
);
expect(coder_app).not.toBeNull();
expect(coder_app?.instances.length).toBe(1);
expect(coder_app?.instances[0].attributes.display_name).toBe("Custom Zed");
});
it("adds agent_name to hostname", async () => {
const state = await runTerraformApply(import.meta.dir, {
agent_id: "foo",
agent_name: "myagent",
});
expect(state.outputs.zed_url.value).toBe(
"zed://ssh/myagent.default.default.coder",
);
});
// Settings file should not be created
const catResult = await execContainer(id, [
"cat",
"/root/.config/zed/settings.json",
]);
expect(catResult.exitCode).not.toBe(0);
} finally {
await removeContainer(id);
}
}, 30000);
});
+6 -1
View File
@@ -65,6 +65,7 @@ locals {
owner_name = lower(data.coder_workspace_owner.me.name)
agent_name = lower(var.agent_name)
hostname = var.agent_name != "" ? "${local.agent_name}.${local.workspace_name}.${local.owner_name}.coder" : "${local.workspace_name}.coder"
settings_b64 = var.settings != "" ? base64encode(var.settings) : ""
}
resource "coder_script" "zed_settings" {
@@ -75,7 +76,11 @@ resource "coder_script" "zed_settings" {
script = <<-EOT
#!/usr/bin/env bash
set -eu
SETTINGS_JSON='${replace(var.settings, "\"", "\\\"")}'
SETTINGS_B64='${local.settings_b64}'
if [ -z "$${SETTINGS_B64}" ]; then
exit 0
fi
SETTINGS_JSON="$(echo -n "$${SETTINGS_B64}" | base64 -d)"
if [ -z "$${SETTINGS_JSON}" ] || [ "$${SETTINGS_JSON}" = "{}" ]; then
exit 0
fi
+74
View File
@@ -5,6 +5,20 @@ run "default_output" {
agent_id = "foo"
}
override_data {
target = data.coder_workspace.me
values = {
name = "default"
}
}
override_data {
target = data.coder_workspace_owner.me
values = {
name = "default"
}
}
assert {
condition = output.zed_url == "zed://ssh/default.coder"
error_message = "zed_url did not match expected default URL"
@@ -19,6 +33,20 @@ run "adds_folder" {
folder = "/foo/bar"
}
override_data {
target = data.coder_workspace.me
values = {
name = "default"
}
}
override_data {
target = data.coder_workspace_owner.me
values = {
name = "default"
}
}
assert {
condition = output.zed_url == "zed://ssh/default.coder/foo/bar"
error_message = "zed_url did not include provided folder path"
@@ -33,8 +61,54 @@ run "adds_agent_name" {
agent_name = "myagent"
}
override_data {
target = data.coder_workspace.me
values = {
name = "default"
}
}
override_data {
target = data.coder_workspace_owner.me
values = {
name = "default"
}
}
assert {
condition = output.zed_url == "zed://ssh/myagent.default.default.coder"
error_message = "zed_url did not include agent_name in hostname"
}
}
run "settings_base64_encoding" {
command = apply
variables {
agent_id = "foo"
settings = jsonencode({
theme = "dark"
fontSize = 14
})
}
# Verify settings are base64 encoded (eyJ = base64 prefix for JSON starting with {")
assert {
condition = can(regex("SETTINGS_B64='eyJ", coder_script.zed_settings.script))
error_message = "settings should be base64 encoded in the script"
}
}
run "empty_settings" {
command = apply
variables {
agent_id = "foo"
settings = ""
}
assert {
condition = can(regex("SETTINGS_B64=''", coder_script.zed_settings.script))
error_message = "empty settings should result in empty SETTINGS_B64"
}
}
@@ -139,7 +139,7 @@ variable "cache_repo_secret_name" {
type = string
}
data "kubernetes_secret" "cache_repo_dockerconfig_secret" {
data "kubernetes_secret_v1" "cache_repo_dockerconfig_secret" {
count = var.cache_repo_secret_name == "" ? 0 : 1
metadata {
name = var.cache_repo_secret_name
@@ -166,7 +166,7 @@ locals {
# Use the docker gateway if the access URL is 127.0.0.1
"ENVBUILDER_INIT_SCRIPT" : replace(coder_agent.main.init_script, "/localhost|127\\.0\\.0\\.1/", "host.docker.internal"),
"ENVBUILDER_FALLBACK_IMAGE" : data.coder_parameter.fallback_image.value,
"ENVBUILDER_DOCKER_CONFIG_BASE64" : base64encode(try(data.kubernetes_secret.cache_repo_dockerconfig_secret[0].data[".dockerconfigjson"], "")),
"ENVBUILDER_DOCKER_CONFIG_BASE64" : base64encode(try(data.kubernetes_secret_v1.cache_repo_dockerconfig_secret[0].data[".dockerconfigjson"], "")),
"ENVBUILDER_PUSH_IMAGE" : var.cache_repo == "" ? "" : "true"
# You may need to adjust this if you get an error regarding deleting files when building the workspace.
# For example, when testing in KinD, it was necessary to set `/product_name` and `/product_uuid` in
@@ -186,7 +186,7 @@ resource "envbuilder_cached_image" "cached" {
insecure = var.insecure_cache_repo
}
resource "kubernetes_persistent_volume_claim" "workspaces" {
resource "kubernetes_persistent_volume_claim_v1" "workspaces" {
metadata {
name = "coder-${lower(data.coder_workspace.me.id)}-workspaces"
namespace = var.namespace
@@ -217,10 +217,10 @@ resource "kubernetes_persistent_volume_claim" "workspaces" {
}
}
resource "kubernetes_deployment" "main" {
resource "kubernetes_deployment_v1" "main" {
count = data.coder_workspace.me.start_count
depends_on = [
kubernetes_persistent_volume_claim.workspaces
kubernetes_persistent_volume_claim_v1.workspaces
]
wait_for_rollout = false
metadata {
@@ -300,7 +300,7 @@ resource "kubernetes_deployment" "main" {
volume {
name = "workspaces"
persistent_volume_claim {
claim_name = kubernetes_persistent_volume_claim.workspaces.metadata.0.name
claim_name = kubernetes_persistent_volume_claim_v1.workspaces.metadata.0.name
read_only = false
}
}
@@ -106,22 +106,20 @@ module "code-server" {
# This ensures that the latest non-breaking version of the module gets downloaded, you can also pin the module version to prevent breaking changes in production.
version = "~> 1.0"
agent_id = coder_agent.main.id
agent_name = "main"
order = 1
agent_id = coder_agent.main.id
order = 1
}
# See https://registry.coder.com/modules/coder/jetbrains
module "jetbrains" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/coder/jetbrains/coder"
version = "~> 1.0"
agent_id = coder_agent.main.id
agent_name = "main"
folder = "/home/coder"
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/jetbrains/coder"
version = "~> 1.0"
agent_id = coder_agent.main.id
folder = "/home/coder"
}
resource "kubernetes_persistent_volume_claim" "home" {
resource "kubernetes_persistent_volume_claim_v1" "home" {
metadata {
name = "coder-${lower(data.coder_workspace_owner.me.name)}-${lower(data.coder_workspace.me.name)}-home"
namespace = var.namespace
@@ -137,7 +135,7 @@ resource "kubernetes_persistent_volume_claim" "home" {
}
}
resource "kubernetes_pod" "main" {
resource "kubernetes_pod_v1" "main" {
count = data.coder_workspace.me.start_count
metadata {
@@ -284,7 +282,7 @@ resource "kubernetes_pod" "main" {
volume {
name = "home"
persistent_volume_claim {
claim_name = kubernetes_persistent_volume_claim.home.metadata.0.name
claim_name = kubernetes_persistent_volume_claim_v1.home.metadata.0.name
read_only = false
}
}
+4 -4
View File
@@ -192,7 +192,7 @@ resource "coder_app" "code-server" {
}
}
resource "kubernetes_persistent_volume_claim" "home" {
resource "kubernetes_persistent_volume_claim_v1" "home" {
metadata {
name = "coder-${data.coder_workspace.me.id}-home"
namespace = var.namespace
@@ -222,10 +222,10 @@ resource "kubernetes_persistent_volume_claim" "home" {
}
}
resource "kubernetes_deployment" "main" {
resource "kubernetes_deployment_v1" "main" {
count = data.coder_workspace.me.start_count
depends_on = [
kubernetes_persistent_volume_claim.home
kubernetes_persistent_volume_claim_v1.home
]
wait_for_rollout = false
metadata {
@@ -316,7 +316,7 @@ resource "kubernetes_deployment" "main" {
volume {
name = "home"
persistent_volume_claim {
claim_name = kubernetes_persistent_volume_claim.home.metadata.0.name
claim_name = kubernetes_persistent_volume_claim_v1.home.metadata.0.name
read_only = false
}
}