diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index bc16a5b8..37f29dd3 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -93,7 +93,7 @@ jobs: - name: Validate formatting run: bun fmt:ci - name: Check for typos - uses: crate-ci/typos@v1.41.0 + uses: crate-ci/typos@v1.42.0 with: config: .github/typos.toml validate-readme-files: diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 00000000..9881ee77 --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1,2 @@ +# GitHub Actions Workflow Owners +.github/ @jdomeracki-coder diff --git a/registry/coder-labs/modules/codex/README.md b/registry/coder-labs/modules/codex/README.md index 1d778240..f98f9882 100644 --- a/registry/coder-labs/modules/codex/README.md +++ b/registry/coder-labs/modules/codex/README.md @@ -13,7 +13,7 @@ Run Codex CLI in your workspace to access OpenAI's models through the Codex inte ```tf module "codex" { source = "registry.coder.com/coder-labs/codex/coder" - version = "3.1.1" + version = "4.0.0" agent_id = coder_agent.example.id openai_api_key = var.openai_api_key workdir = "/home/coder/project" @@ -22,7 +22,6 @@ module "codex" { ## Prerequisites -- You must add the [Coder Login](https://registry.coder.com/modules/coder/coder-login) module to your template - OpenAI API key for Codex access ## Examples @@ -33,7 +32,7 @@ module "codex" { module "codex" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder-labs/codex/coder" - version = "3.1.1" + version = "4.0.0" agent_id = coder_agent.example.id openai_api_key = "..." workdir = "/home/coder/project" @@ -44,27 +43,19 @@ module "codex" { ### Tasks integration ```tf -data "coder_parameter" "ai_prompt" { - type = "string" - name = "AI Prompt" - default = "" - description = "Initial prompt for the Codex CLI" - mutable = true +resource "coder_ai_task" "task" { + count = data.coder_workspace.me.start_count + app_id = module.codex.task_app_id } -module "coder-login" { - count = data.coder_workspace.me.start_count - source = "registry.coder.com/coder/coder-login/coder" - version = "3.1.1" - agent_id = coder_agent.example.id -} +data "coder_task" "me" {} module "codex" { source = "registry.coder.com/coder-labs/codex/coder" - version = "3.1.1" + version = "4.0.0" agent_id = coder_agent.example.id openai_api_key = "..." - ai_prompt = data.coder_parameter.ai_prompt.value + ai_prompt = data.coder_task.me.prompt workdir = "/home/coder/project" # Custom configuration for full auto mode @@ -108,7 +99,7 @@ For custom Codex configuration, use `base_config_toml` and/or `additional_mcp_se ```tf module "codex" { source = "registry.coder.com/coder-labs/codex/coder" - version = "3.1.1" + version = "4.0.0" # ... other variables ... # Override default configuration @@ -137,7 +128,7 @@ module "codex" { - Ensure your OpenAI API key has access to the specified model > [!IMPORTANT] -> To use tasks with Codex CLI, ensure you have the `openai_api_key` variable set, and **you create a `coder_parameter` named `"AI Prompt"` and pass its value to the codex module's `ai_prompt` variable**. [Tasks Template Example](https://registry.coder.com/templates/coder-labs/tasks-docker). +> To use tasks with Codex CLI, ensure you have the `openai_api_key` variable set. [Tasks Template Example](https://registry.coder.com/templates/coder-labs/tasks-docker). > The module automatically configures Codex with your API key and model preferences. > workdir is a required variable for the module to function correctly. diff --git a/registry/coder-labs/modules/codex/main.tf b/registry/coder-labs/modules/codex/main.tf index a68cd79f..20351839 100644 --- a/registry/coder-labs/modules/codex/main.tf +++ b/registry/coder-labs/modules/codex/main.tf @@ -4,7 +4,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">= 2.7" + version = ">= 2.12" } } } @@ -110,12 +110,12 @@ variable "install_agentapi" { variable "agentapi_version" { type = string description = "The version of AgentAPI to install." - default = "v0.10.0" + default = "v0.11.6" } variable "codex_model" { type = string - description = "The model for Codex to use. Defaults to gpt-5." + description = "The model for Codex to use. Defaults to gpt-5.1-codex-max." default = "" } @@ -165,7 +165,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 @@ -217,4 +217,8 @@ module "agentapi" { ARG_CODEX_INSTRUCTION_PROMPT='${base64encode(var.codex_system_prompt)}' \ /tmp/install.sh EOT -} \ No newline at end of file +} + +output "task_app_id" { + value = module.agentapi.task_app_id +} diff --git a/registry/coder-labs/modules/codex/scripts/install.sh b/registry/coder-labs/modules/codex/scripts/install.sh index 33991ef4..62842165 100644 --- a/registry/coder-labs/modules/codex/scripts/install.sh +++ b/registry/coder-labs/modules/codex/scripts/install.sh @@ -115,7 +115,7 @@ append_mcp_servers_section() { [mcp_servers.Coder] command = "coder" args = ["exp", "mcp", "server"] -env = { "CODER_MCP_APP_STATUS_SLUG" = "${ARG_CODER_MCP_APP_STATUS_SLUG}", "CODER_MCP_AI_AGENTAPI_URL" = "${CODER_MCP_AI_AGENTAPI_URL}" , "CODER_AGENT_URL" = "${CODER_AGENT_URL}", "CODER_AGENT_TOKEN" = "${CODER_AGENT_TOKEN}" } +env = { "CODER_MCP_APP_STATUS_SLUG" = "${ARG_CODER_MCP_APP_STATUS_SLUG}", "CODER_MCP_AI_AGENTAPI_URL" = "${CODER_MCP_AI_AGENTAPI_URL}" , "CODER_AGENT_URL" = "${CODER_AGENT_URL}", "CODER_AGENT_TOKEN" = "${CODER_AGENT_TOKEN}", "CODER_MCP_ALLOWED_TOOLS" = "coder_report_task" } description = "Report ALL tasks and statuses (in progress, done, failed) you are working on." type = "stdio" diff --git a/registry/coder-labs/modules/codex/scripts/start.sh b/registry/coder-labs/modules/codex/scripts/start.sh index 38510fd0..e77436f1 100644 --- a/registry/coder-labs/modules/codex/scripts/start.sh +++ b/registry/coder-labs/modules/codex/scripts/start.sh @@ -182,7 +182,7 @@ build_codex_args() { if [ -n "$ARG_CODEX_TASK_PROMPT" ]; then if [ "${ARG_REPORT_TASKS}" == "true" ]; then - PROMPT="Complete the task at hand in one go. Every step of the way, report your progress using coder_report_task tool with proper summary and statuses. Your task at hand: $ARG_CODEX_TASK_PROMPT" + PROMPT="Complete the task at hand in one go. Every step of the way, report your progress using Coder.coder_report_task tool with proper summary and statuses. Your task at hand: $ARG_CODEX_TASK_PROMPT" else PROMPT="Your task at hand: $ARG_CODEX_TASK_PROMPT" fi diff --git a/registry/coder/modules/claude-code/README.md b/registry/coder/modules/claude-code/README.md index c0004504..ce7810a8 100644 --- a/registry/coder/modules/claude-code/README.md +++ b/registry/coder/modules/claude-code/README.md @@ -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.3.0" + version = "4.4.2" agent_id = coder_agent.main.id workdir = "/home/coder/project" claude_api_key = "xxxx-xxxxx-xxxx" @@ -44,8 +44,8 @@ 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.3.0" + source = "registry.coder.com/coder/claude-code/coder" + version = "4.4.2" agent_id = coder_agent.main.id workdir = "/home/coder/project" enable_boundary = true @@ -57,6 +57,9 @@ module "claude-code" { This example shows how to configure the Claude Code module with an AI prompt, API key shared by all users of the template, and other custom settings. +> [!NOTE] +> When a specific `claude_code_version` (other than "latest") is provided, the module will install Claude Code via npm instead of the official installer. This allows for version pinning. The `claude_binary_path` variable can be used to specify where a pre-installed Claude binary is located. + ```tf data "coder_parameter" "ai_prompt" { type = "string" @@ -68,7 +71,7 @@ data "coder_parameter" "ai_prompt" { module "claude-code" { source = "registry.coder.com/coder/claude-code/coder" - version = "4.3.0" + version = "4.4.2" agent_id = coder_agent.main.id workdir = "/home/coder/project" @@ -76,7 +79,8 @@ module "claude-code" { # OR claude_code_oauth_token = "xxxxx-xxxx-xxxx" - claude_code_version = "2.0.62" # Pin to a specific version + claude_code_version = "2.0.62" # Pin to a specific version (uses npm) + claude_binary_path = "/opt/claude/bin" # Path to pre-installed Claude binary agentapi_version = "0.11.4" ai_prompt = data.coder_parameter.ai_prompt.value @@ -104,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.3.0" + version = "4.4.2" agent_id = coder_agent.main.id workdir = "/home/coder/project" install_claude_code = true @@ -126,7 +130,7 @@ variable "claude_code_oauth_token" { module "claude-code" { source = "registry.coder.com/coder/claude-code/coder" - version = "4.3.0" + version = "4.4.2" agent_id = coder_agent.main.id workdir = "/home/coder/project" claude_code_oauth_token = var.claude_code_oauth_token @@ -199,7 +203,7 @@ resource "coder_env" "bedrock_api_key" { module "claude-code" { source = "registry.coder.com/coder/claude-code/coder" - version = "4.3.0" + version = "4.4.2" agent_id = coder_agent.main.id workdir = "/home/coder/project" model = "global.anthropic.claude-sonnet-4-5-20250929-v1:0" @@ -256,7 +260,7 @@ resource "coder_env" "google_application_credentials" { module "claude-code" { source = "registry.coder.com/coder/claude-code/coder" - version = "4.3.0" + version = "4.4.2" agent_id = coder_agent.main.id workdir = "/home/coder/project" model = "claude-sonnet-4@20250514" diff --git a/registry/coder/modules/claude-code/main.test.ts b/registry/coder/modules/claude-code/main.test.ts index c62493cf..d59b6a8f 100644 --- a/registry/coder/modules/claude-code/main.test.ts +++ b/registry/coder/modules/claude-code/main.test.ts @@ -184,20 +184,15 @@ describe("claude-code", async () => { test("claude-model", async () => { const model = "opus"; - const { id } = await setup({ + const { coderEnvVars } = await setup({ moduleVariables: { model: model, ai_prompt: "test prompt", }, }); - await execModuleScript(id); - const startLog = await execContainer(id, [ - "bash", - "-c", - "cat /home/coder/.claude-module/agentapi-start.log", - ]); - expect(startLog.stdout).toContain(`--model ${model}`); + // Verify ANTHROPIC_MODEL env var is set via coder_env + expect(coderEnvVars["ANTHROPIC_MODEL"]).toBe(model); }); test("claude-continue-resume-task-session", async () => { diff --git a/registry/coder/modules/claude-code/main.tf b/registry/coder/modules/claude-code/main.tf index 7ae5dca5..56a023ce 100644 --- a/registry/coder/modules/claude-code/main.tf +++ b/registry/coder/modules/claude-code/main.tf @@ -86,7 +86,7 @@ variable "install_agentapi" { variable "agentapi_version" { type = string description = "The version of AgentAPI to install." - default = "v0.11.6" + default = "v0.11.8" } variable "ai_prompt" { @@ -128,7 +128,7 @@ variable "claude_api_key" { variable "model" { type = string - description = "Sets the model for the current session with an alias for the latest model (sonnet or opus) or a model’s full name." + description = "Sets the default model for Claude Code via ANTHROPIC_MODEL env var. If empty, Claude Code uses its default. Supports aliases (sonnet, opus) or full model names." default = "" } @@ -198,6 +198,18 @@ variable "claude_md_path" { default = "$HOME/.claude/CLAUDE.md" } +variable "claude_binary_path" { + type = string + description = "Directory where the Claude Code binary is located. Use this if Claude is pre-installed or installed outside the module to a non-default location." + default = "$HOME/.local/bin" +} + +variable "install_via_npm" { + type = bool + description = "Install Claude Code via npm instead of the official installer. Useful if npm is preferred or the official installer fails." + default = false +} + variable "enable_boundary" { type = bool description = "Whether to enable coder boundary for network filtering" @@ -217,8 +229,7 @@ variable "compile_boundary_from_source" { } resource "coder_env" "claude_code_md_path" { - count = var.claude_md_path == "" ? 0 : 1 - + count = var.claude_md_path == "" ? 0 : 1 agent_id = var.agent_id name = "CODER_MCP_CLAUDE_MD_PATH" value = var.claude_md_path @@ -237,16 +248,14 @@ resource "coder_env" "claude_code_oauth_token" { } resource "coder_env" "claude_api_key" { - count = length(var.claude_api_key) > 0 ? 1 : 0 - + count = length(var.claude_api_key) > 0 ? 1 : 0 agent_id = var.agent_id name = "CLAUDE_API_KEY" value = var.claude_api_key } resource "coder_env" "disable_autoupdater" { - count = var.disable_autoupdater ? 1 : 0 - + count = var.disable_autoupdater ? 1 : 0 agent_id = var.agent_id name = "DISABLE_AUTOUPDATER" value = "1" @@ -255,7 +264,21 @@ 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" + + lifecycle { + precondition { + condition = var.claude_binary_path == "$HOME/.local/bin" || !var.install_claude_code + error_message = "Custom claude_binary_path can only be used when install_claude_code is false. The official installer and npm both install to fixed locations." + } + } +} + +resource "coder_env" "anthropic_model" { + count = var.model != "" ? 1 : 0 + agent_id = var.agent_id + name = "ANTHROPIC_MODEL" + value = var.model } locals { @@ -328,7 +351,6 @@ module "agentapi" { echo -n '${base64encode(local.start_script)}' | base64 -d > /tmp/start.sh chmod +x /tmp/start.sh - ARG_MODEL='${var.model}' \ ARG_RESUME_SESSION_ID='${var.resume_session_id}' \ ARG_CONTINUE='${var.continue}' \ ARG_DANGEROUSLY_SKIP_PERMISSIONS='${var.dangerously_skip_permissions}' \ @@ -353,6 +375,8 @@ module "agentapi" { ARG_CLAUDE_CODE_VERSION='${var.claude_code_version}' \ ARG_MCP_APP_STATUS_SLUG='${local.app_slug}' \ ARG_INSTALL_CLAUDE_CODE='${var.install_claude_code}' \ + ARG_CLAUDE_BINARY_PATH='${var.claude_binary_path}' \ + ARG_INSTALL_VIA_NPM='${var.install_via_npm}' \ ARG_REPORT_TASKS='${var.report_tasks}' \ ARG_WORKDIR='${local.workdir}' \ ARG_ALLOWED_TOOLS='${var.allowed_tools}' \ diff --git a/registry/coder/modules/claude-code/scripts/install.sh b/registry/coder/modules/claude-code/scripts/install.sh index 15981e8b..5b9584cb 100644 --- a/registry/coder/modules/claude-code/scripts/install.sh +++ b/registry/coder/modules/claude-code/scripts/install.sh @@ -11,6 +11,8 @@ command_exists() { ARG_CLAUDE_CODE_VERSION=${ARG_CLAUDE_CODE_VERSION:-} ARG_WORKDIR=${ARG_WORKDIR:-"$HOME"} ARG_INSTALL_CLAUDE_CODE=${ARG_INSTALL_CLAUDE_CODE:-} +ARG_CLAUDE_BINARY_PATH=${ARG_CLAUDE_BINARY_PATH:-"$HOME/.local/bin"} +ARG_INSTALL_VIA_NPM=${ARG_INSTALL_VIA_NPM:-false} ARG_REPORT_TASKS=${ARG_REPORT_TASKS:-true} ARG_MCP_APP_STATUS_SLUG=${ARG_MCP_APP_STATUS_SLUG:-} ARG_MCP=$(echo -n "${ARG_MCP:-}" | base64 -d) @@ -22,6 +24,8 @@ echo "--------------------------------" printf "ARG_CLAUDE_CODE_VERSION: %s\n" "$ARG_CLAUDE_CODE_VERSION" printf "ARG_WORKDIR: %s\n" "$ARG_WORKDIR" printf "ARG_INSTALL_CLAUDE_CODE: %s\n" "$ARG_INSTALL_CLAUDE_CODE" +printf "ARG_CLAUDE_BINARY_PATH: %s\n" "$ARG_CLAUDE_BINARY_PATH" +printf "ARG_INSTALL_VIA_NPM: %s\n" "$ARG_INSTALL_VIA_NPM" printf "ARG_REPORT_TASKS: %s\n" "$ARG_REPORT_TASKS" printf "ARG_MCP_APP_STATUS_SLUG: %s\n" "$ARG_MCP_APP_STATUS_SLUG" printf "ARG_MCP: %s\n" "$ARG_MCP" @@ -30,20 +34,66 @@ printf "ARG_DISALLOWED_TOOLS: %s\n" "$ARG_DISALLOWED_TOOLS" echo "--------------------------------" +function ensure_claude_in_path() { + if [ -z "${CODER_SCRIPT_BIN_DIR:-}" ]; then + echo "CODER_SCRIPT_BIN_DIR not set, skipping PATH setup" + return + fi + + if [ ! -e "$CODER_SCRIPT_BIN_DIR/claude" ]; then + local CLAUDE_BIN="" + if command -v claude > /dev/null 2>&1; then + CLAUDE_BIN=$(command -v claude) + elif [ -x "$ARG_CLAUDE_BINARY_PATH/claude" ]; then + CLAUDE_BIN="$ARG_CLAUDE_BINARY_PATH/claude" + elif [ -x "$HOME/.local/bin/claude" ]; then + CLAUDE_BIN="$HOME/.local/bin/claude" + fi + + if [ -n "$CLAUDE_BIN" ] && [ -x "$CLAUDE_BIN" ]; then + ln -s "$CLAUDE_BIN" "$CODER_SCRIPT_BIN_DIR/claude" + echo "Created symlink: $CODER_SCRIPT_BIN_DIR/claude -> $CLAUDE_BIN" + else + echo "Warning: Could not find claude binary to symlink" + fi + else + echo "Claude already available in CODER_SCRIPT_BIN_DIR" + fi + + local marker="# Added by claude-code module" + for profile in "$HOME/.bashrc" "$HOME/.zshrc" "$HOME/.profile"; do + if [ -f "$profile" ] && ! grep -q "$marker" "$profile" 2> /dev/null; then + printf "\n%s\nexport PATH=\"%s:\$PATH\"\n" "$marker" "$CODER_SCRIPT_BIN_DIR" >> "$profile" + echo "Added $CODER_SCRIPT_BIN_DIR to PATH in $profile" + fi + done +} + function install_claude_code_cli() { - if [ "$ARG_INSTALL_CLAUDE_CODE" = "true" ]; then + if [ "$ARG_INSTALL_CLAUDE_CODE" != "true" ]; then + echo "Skipping Claude Code installation as per configuration." + ensure_claude_in_path + return + fi + + # Use npm when install_via_npm is true or for specific version pinning + if [ "$ARG_INSTALL_VIA_NPM" = "true" ] || { [ -n "$ARG_CLAUDE_CODE_VERSION" ] && [ "$ARG_CLAUDE_CODE_VERSION" != "latest" ]; }; then + echo "Installing Claude Code via npm (version: $ARG_CLAUDE_CODE_VERSION)" + npm install -g "@anthropic-ai/claude-code@$ARG_CLAUDE_CODE_VERSION" + echo "Installed Claude Code via npm. Version: $(claude --version || echo 'unknown')" + else echo "Installing Claude Code via official installer" set +e curl -fsSL claude.ai/install.sh | bash -s -- "$ARG_CLAUDE_CODE_VERSION" 2>&1 CURL_EXIT=${PIPESTATUS[0]} set -e if [ $CURL_EXIT -ne 0 ]; then - echo "Claude Code installer failed with exit code $$CURL_EXIT" + echo "Claude Code installer failed with exit code $CURL_EXIT" fi echo "Installed Claude Code successfully. Version: $(claude --version || echo 'unknown')" - else - echo "Skipping Claude Code installation as per configuration." fi + + ensure_claude_in_path } function setup_claude_configurations() { @@ -63,7 +113,7 @@ function setup_claude_configurations() { while IFS= read -r server_name && IFS= read -r server_json; do echo "------------------------" echo "Executing: claude mcp add-json \"$server_name\" '$server_json' (in $ARG_WORKDIR)" - claude mcp add-json "$server_name" "$server_json" + claude mcp add-json "$server_name" "$server_json" || echo "Warning: Failed to add MCP server '$server_name', continuing..." echo "------------------------" echo "" done < <(echo "$ARG_MCP" | jq -r '.mcpServers | to_entries[] | .key, (.value | @json)') diff --git a/registry/coder/modules/claude-code/scripts/start.sh b/registry/coder/modules/claude-code/scripts/start.sh index e14b26a6..c3c32020 100644 --- a/registry/coder/modules/claude-code/scripts/start.sh +++ b/registry/coder/modules/claude-code/scripts/start.sh @@ -6,7 +6,6 @@ command_exists() { command -v "$1" > /dev/null 2>&1 } -ARG_MODEL=${ARG_MODEL:-} ARG_RESUME_SESSION_ID=${ARG_RESUME_SESSION_ID:-} ARG_CONTINUE=${ARG_CONTINUE:-false} ARG_DANGEROUSLY_SKIP_PERMISSIONS=${ARG_DANGEROUSLY_SKIP_PERMISSIONS:-} @@ -21,7 +20,6 @@ ARG_CODER_HOST=${ARG_CODER_HOST:-} echo "--------------------------------" -printf "ARG_MODEL: %s\n" "$ARG_MODEL" printf "ARG_RESUME: %s\n" "$ARG_RESUME_SESSION_ID" printf "ARG_CONTINUE: %s\n" "$ARG_CONTINUE" printf "ARG_DANGEROUSLY_SKIP_PERMISSIONS: %s\n" "$ARG_DANGEROUSLY_SKIP_PERMISSIONS" @@ -170,10 +168,6 @@ function start_agentapi() { mkdir -p "$ARG_WORKDIR" cd "$ARG_WORKDIR" - if [ -n "$ARG_MODEL" ]; then - ARGS+=(--model "$ARG_MODEL") - fi - if [ -n "$ARG_PERMISSION_MODE" ]; then ARGS+=(--permission-mode "$ARG_PERMISSION_MODE") fi @@ -223,8 +217,7 @@ function start_agentapi() { printf "Starting with coder boundary enabled\n" - # Add default allowed URLs - BOUNDARY_ARGS+=(--allow "domain=anthropic.com" --allow "domain=registry.npmjs.org" --allow "domain=sentry.io" --allow "domain=claude.ai" --allow "domain=$ARG_CODER_HOST") + BOUNDARY_ARGS+=() agentapi server --type claude --term-width 67 --term-height 1190 -- \ boundary-run "${BOUNDARY_ARGS[@]}" -- \ diff --git a/registry/coder/modules/code-server/main.test.ts b/registry/coder/modules/code-server/main.test.ts index 01e80883..914ae2f0 100644 --- a/registry/coder/modules/code-server/main.test.ts +++ b/registry/coder/modules/code-server/main.test.ts @@ -1,5 +1,9 @@ import { describe, expect, it } from "bun:test"; import { + execContainer, + findResourceInstance, + removeContainer, + runContainer, runTerraformApply, runTerraformInit, testRequiredVariables, @@ -34,5 +38,47 @@ describe("code-server", async () => { expect(t).toThrow("Offline mode does not allow extensions to be installed"); }); - // More tests depend on shebang refactors + it("installs and runs code-server", async () => { + const state = await runTerraformApply(import.meta.dir, { + agent_id: "foo", + }); + + const id = await runContainer("ubuntu:latest"); + try { + await execContainer(id, [ + "bash", + "-c", + "apt-get update && apt-get install -y curl", + ]); + + const script = findResourceInstance(state, "coder_script").script; + const result = await execContainer(id, ["bash", "-c", script]); + if (result.exitCode !== 0) { + console.log(result.stdout); + console.log(result.stderr); + } + expect(result.exitCode).toBe(0); + + const version = await execContainer(id, [ + "/tmp/code-server/bin/code-server", + "--version", + ]); + expect(version.exitCode).toBe(0); + expect(version.stdout).toMatch(/\d+\.\d+\.\d+/); + + const health = await execContainer(id, [ + "curl", + "--retry", + "10", + "--retry-delay", + "1", + "--retry-all-errors", + "-sf", + "http://localhost:13337/healthz", + ]); + expect(health.exitCode).toBe(0); + } finally { + await removeContainer(id); + } + }, 60000); }); diff --git a/registry/coder/modules/jetbrains-fleet/README.md b/registry/coder/modules/jetbrains-fleet/README.md index c004f95c..b2c194d6 100644 --- a/registry/coder/modules/jetbrains-fleet/README.md +++ b/registry/coder/modules/jetbrains-fleet/README.md @@ -8,6 +8,9 @@ tags: [ide, jetbrains, fleet] # Jetbrains Fleet +> [!WARNING] +> **Deprecation Notice:** JetBrains has announced that Fleet will be discontinued. For more information, see [The Future of Fleet](https://blog.jetbrains.com/fleet/2025/12/the-future-of-fleet). Consider migrating to other JetBrains IDEs such as IntelliJ IDEA, PyCharm, or GoLand with the [JetBrains](https://registry.coder.com/modules/jetbrains) module. + This module adds a Jetbrains Fleet button to your Coder workspace that opens the workspace in JetBrains Fleet using SSH remote development. JetBrains Fleet is a next-generation IDE that supports collaborative development and distributed architectures. It connects to your Coder workspace via SSH, providing a seamless remote development experience. @@ -16,7 +19,7 @@ JetBrains Fleet is a next-generation IDE that supports collaborative development module "jetbrains_fleet" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/jetbrains-fleet/coder" - version = "1.0.2" + version = "1.0.3" agent_id = coder_agent.main.id } ``` @@ -37,7 +40,7 @@ module "jetbrains_fleet" { module "jetbrains_fleet" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/jetbrains-fleet/coder" - version = "1.0.2" + version = "1.0.3" agent_id = coder_agent.main.id } ``` @@ -48,7 +51,7 @@ module "jetbrains_fleet" { module "jetbrains_fleet" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/jetbrains-fleet/coder" - version = "1.0.2" + version = "1.0.3" agent_id = coder_agent.main.id folder = "/home/coder/project" } @@ -60,7 +63,7 @@ module "jetbrains_fleet" { module "jetbrains_fleet" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/jetbrains-fleet/coder" - version = "1.0.2" + version = "1.0.3" agent_id = coder_agent.main.id display_name = "Fleet" group = "JetBrains IDEs" @@ -74,7 +77,7 @@ module "jetbrains_fleet" { module "jetbrains_fleet" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/jetbrains-fleet/coder" - version = "1.0.2" + version = "1.0.3" agent_id = coder_agent.main.id agent_name = coder_agent.example.name }