From bc5b28b8ad1b538a868549c50818d570f1db589f Mon Sep 17 00:00:00 2001 From: DevelopmentCats Date: Fri, 19 Dec 2025 09:11:42 -0600 Subject: [PATCH 01/10] feat: add variable for custom Claude binary path in main.tf --- registry/coder/modules/claude-code/main.tf | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/registry/coder/modules/claude-code/main.tf b/registry/coder/modules/claude-code/main.tf index 8531a9f9a..0e73af552 100644 --- a/registry/coder/modules/claude-code/main.tf +++ b/registry/coder/modules/claude-code/main.tf @@ -288,10 +288,16 @@ resource "coder_env" "disable_autoupdater" { value = "1" } +variable "claude_path" { + type = string + description = "Path to prepend to PATH for Claude Code binary. Defaults to $HOME/.local/bin" + default = "" +} + resource "coder_env" "claude_binary_path" { agent_id = var.agent_id name = "PATH" - value = "$HOME/.local/bin:$PATH" + value = var.claude_path != "" ? "${var.claude_path}:$PATH" : "$HOME/.local/bin:$PATH" } locals { From ad297b475dbc9112a78c1eeab336c8a122346865 Mon Sep 17 00:00:00 2001 From: DevelopmentCats Date: Fri, 19 Dec 2025 09:26:32 -0600 Subject: [PATCH 02/10] chore: model uses env and path accepts input override --- registry/coder/modules/claude-code/main.test.ts | 16 ++++++++-------- registry/coder/modules/claude-code/main.tf | 11 +++++++++-- .../coder/modules/claude-code/scripts/start.sh | 6 ------ 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/registry/coder/modules/claude-code/main.test.ts b/registry/coder/modules/claude-code/main.test.ts index c62493cf8..7cb169a13 100644 --- a/registry/coder/modules/claude-code/main.test.ts +++ b/registry/coder/modules/claude-code/main.test.ts @@ -184,20 +184,20 @@ describe("claude-code", async () => { test("claude-model", async () => { const model = "opus"; - const { id } = await setup({ + const { id, state } = 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 + const envResources = state.resources.filter( + (r) => r.type === "coder_env" && r.name === "anthropic_model", + ); + expect(envResources.length).toBe(1); + expect(envResources[0].instances[0].attributes.name).toBe("ANTHROPIC_MODEL"); + expect(envResources[0].instances[0].attributes.value).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 0e73af552..a6091daa1 100644 --- a/registry/coder/modules/claude-code/main.tf +++ b/registry/coder/modules/claude-code/main.tf @@ -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 (Sonnet 4.5). Supports aliases (sonnet, opus) or full model names." default = "" } @@ -300,6 +300,14 @@ resource "coder_env" "claude_binary_path" { value = var.claude_path != "" ? "${var.claude_path}:$PATH" : "$HOME/.local/bin:$PATH" } +resource "coder_env" "anthropic_model" { + count = var.model != "" ? 1 : 0 + + agent_id = var.agent_id + name = "ANTHROPIC_MODEL" + value = var.model +} + locals { # we have to trim the slash because otherwise coder exp mcp will # set up an invalid claude config @@ -370,7 +378,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}' \ diff --git a/registry/coder/modules/claude-code/scripts/start.sh b/registry/coder/modules/claude-code/scripts/start.sh index ebca736cc..56c9eff62 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:-} @@ -26,7 +25,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" @@ -171,10 +169,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 From 1fbc028e7bc583319ac8d35695f0aae36d6a1cef Mon Sep 17 00:00:00 2001 From: DevelopmentCats Date: Fri, 19 Dec 2025 09:30:04 -0600 Subject: [PATCH 03/10] chore: update Claude Code module version to 4.3.0 --- registry/coder/modules/claude-code/README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/registry/coder/modules/claude-code/README.md b/registry/coder/modules/claude-code/README.md index 11172010f..222618c8f 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.2.7" + version = "4.3.0" 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.3.0" 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.3.0" 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.3.0" 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.3.0" 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.3.0" 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.3.0" agent_id = coder_agent.main.id workdir = "/home/coder/project" model = "claude-sonnet-4@20250514" From 83e4b7fbbfae78f1a536f7ba4942405e81d9f231 Mon Sep 17 00:00:00 2001 From: DevelopmentCats Date: Fri, 19 Dec 2025 09:40:46 -0600 Subject: [PATCH 04/10] chore: bun fmt --- registry/coder/modules/claude-code/main.test.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/registry/coder/modules/claude-code/main.test.ts b/registry/coder/modules/claude-code/main.test.ts index 7cb169a13..a0298338f 100644 --- a/registry/coder/modules/claude-code/main.test.ts +++ b/registry/coder/modules/claude-code/main.test.ts @@ -196,7 +196,9 @@ describe("claude-code", async () => { (r) => r.type === "coder_env" && r.name === "anthropic_model", ); expect(envResources.length).toBe(1); - expect(envResources[0].instances[0].attributes.name).toBe("ANTHROPIC_MODEL"); + expect(envResources[0].instances[0].attributes.name).toBe( + "ANTHROPIC_MODEL", + ); expect(envResources[0].instances[0].attributes.value).toBe(model); }); From 5c4b05c5932e7d57c029efeb3f72836738600f0e Mon Sep 17 00:00:00 2001 From: DevelopmentCats Date: Fri, 19 Dec 2025 09:48:20 -0600 Subject: [PATCH 05/10] refactor: update test to use coderEnvVars for environment variable verification --- registry/coder/modules/claude-code/main.test.ts | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/registry/coder/modules/claude-code/main.test.ts b/registry/coder/modules/claude-code/main.test.ts index a0298338f..d59b6a8f4 100644 --- a/registry/coder/modules/claude-code/main.test.ts +++ b/registry/coder/modules/claude-code/main.test.ts @@ -184,7 +184,7 @@ describe("claude-code", async () => { test("claude-model", async () => { const model = "opus"; - const { id, state } = await setup({ + const { coderEnvVars } = await setup({ moduleVariables: { model: model, ai_prompt: "test prompt", @@ -192,14 +192,7 @@ describe("claude-code", async () => { }); // Verify ANTHROPIC_MODEL env var is set via coder_env - const envResources = state.resources.filter( - (r) => r.type === "coder_env" && r.name === "anthropic_model", - ); - expect(envResources.length).toBe(1); - expect(envResources[0].instances[0].attributes.name).toBe( - "ANTHROPIC_MODEL", - ); - expect(envResources[0].instances[0].attributes.value).toBe(model); + expect(coderEnvVars["ANTHROPIC_MODEL"]).toBe(model); }); test("claude-continue-resume-task-session", async () => { From 466f61acc385ecc554a2a8c4a2ecefee642f2453 Mon Sep 17 00:00:00 2001 From: DevelopmentCats Date: Fri, 19 Dec 2025 09:53:38 -0600 Subject: [PATCH 06/10] chore: address nitpick comments --- registry/coder/modules/claude-code/main.tf | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/registry/coder/modules/claude-code/main.tf b/registry/coder/modules/claude-code/main.tf index a6091daa1..187690632 100644 --- a/registry/coder/modules/claude-code/main.tf +++ b/registry/coder/modules/claude-code/main.tf @@ -128,7 +128,7 @@ variable "claude_api_key" { variable "model" { type = string - description = "Sets the default model for Claude Code via ANTHROPIC_MODEL env var. If empty, Claude Code uses its default (Sonnet 4.5). Supports aliases (sonnet, opus) or full model names." + 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 = "" } @@ -253,8 +253,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 @@ -273,16 +272,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" @@ -301,8 +298,7 @@ resource "coder_env" "claude_binary_path" { } resource "coder_env" "anthropic_model" { - count = var.model != "" ? 1 : 0 - + count = var.model != "" ? 1 : 0 agent_id = var.agent_id name = "ANTHROPIC_MODEL" value = var.model From 1f446eee939e897954b17a3faca9b7ff924a91ff Mon Sep 17 00:00:00 2001 From: DevelopmentCats Date: Fri, 19 Dec 2025 09:59:21 -0600 Subject: [PATCH 07/10] chore: cleanup claude_path variable for custom binary path configuration --- registry/coder/modules/claude-code/main.tf | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/registry/coder/modules/claude-code/main.tf b/registry/coder/modules/claude-code/main.tf index 187690632..d46e68ddf 100644 --- a/registry/coder/modules/claude-code/main.tf +++ b/registry/coder/modules/claude-code/main.tf @@ -198,6 +198,12 @@ variable "claude_md_path" { default = "$HOME/.claude/CLAUDE.md" } +variable "claude_path" { + type = string + description = "Path to prepend to PATH for Claude Code binary." + default = "$HOME/.local/bin" +} + variable "enable_boundary" { type = bool description = "Whether to enable coder boundary for network filtering" @@ -285,16 +291,10 @@ resource "coder_env" "disable_autoupdater" { value = "1" } -variable "claude_path" { - type = string - description = "Path to prepend to PATH for Claude Code binary. Defaults to $HOME/.local/bin" - default = "" -} - resource "coder_env" "claude_binary_path" { agent_id = var.agent_id name = "PATH" - value = var.claude_path != "" ? "${var.claude_path}:$PATH" : "$HOME/.local/bin:$PATH" + value = "${var.claude_path}:$PATH" } resource "coder_env" "anthropic_model" { From 74c6c0a5db8f3f0a3718630763f2b9788b9b777c Mon Sep 17 00:00:00 2001 From: DevelopmentCats Date: Fri, 19 Dec 2025 10:17:44 -0600 Subject: [PATCH 08/10] chore: rename claude_path variable to claude_binary_path for clarity --- registry/coder/modules/claude-code/main.tf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/registry/coder/modules/claude-code/main.tf b/registry/coder/modules/claude-code/main.tf index d46e68ddf..2dba4cf70 100644 --- a/registry/coder/modules/claude-code/main.tf +++ b/registry/coder/modules/claude-code/main.tf @@ -198,7 +198,7 @@ variable "claude_md_path" { default = "$HOME/.claude/CLAUDE.md" } -variable "claude_path" { +variable "claude_binary_path" { type = string description = "Path to prepend to PATH for Claude Code binary." default = "$HOME/.local/bin" @@ -294,7 +294,7 @@ resource "coder_env" "disable_autoupdater" { resource "coder_env" "claude_binary_path" { agent_id = var.agent_id name = "PATH" - value = "${var.claude_path}:$PATH" + value = "${var.claude_binary_path}:$PATH" } resource "coder_env" "anthropic_model" { From 255776c794c5f748ad8ef6beb94e70b6de1397bc Mon Sep 17 00:00:00 2001 From: DevelopmentCats Date: Fri, 19 Dec 2025 11:56:07 -0600 Subject: [PATCH 09/10] fix: add custom binary path to install script, and use npm installation for this since official installer does not support versions or install path flags --- registry/coder/modules/claude-code/README.md | 8 +++- registry/coder/modules/claude-code/main.tf | 3 +- .../modules/claude-code/scripts/install.sh | 40 +++++++++++++++++-- 3 files changed, 44 insertions(+), 7 deletions(-) diff --git a/registry/coder/modules/claude-code/README.md b/registry/coder/modules/claude-code/README.md index 222618c8f..d66c74fc6 100644 --- a/registry/coder/modules/claude-code/README.md +++ b/registry/coder/modules/claude-code/README.md @@ -61,6 +61,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") or a custom `claude_binary_path` is provided, the module will install Claude Code via npm instead of the official installer. This allows for version pinning and custom install locations. + ```tf data "coder_parameter" "ai_prompt" { type = "string" @@ -80,8 +83,9 @@ module "claude-code" { # OR claude_code_oauth_token = "xxxxx-xxxx-xxxx" - claude_code_version = "2.0.62" # Pin to a specific version - agentapi_version = "0.11.4" + claude_code_version = "2.0.62" # Pin to a specific version + claude_binary_path = "/opt/claude/bin" # Custom install location + agentapi_version = "0.11.4" ai_prompt = data.coder_parameter.ai_prompt.value model = "sonnet" diff --git a/registry/coder/modules/claude-code/main.tf b/registry/coder/modules/claude-code/main.tf index 2dba4cf70..b2258695a 100644 --- a/registry/coder/modules/claude-code/main.tf +++ b/registry/coder/modules/claude-code/main.tf @@ -200,7 +200,7 @@ variable "claude_md_path" { variable "claude_binary_path" { type = string - description = "Path to prepend to PATH for Claude Code binary." + description = "Directory where the Claude Code binary is located. If a custom path is specified, Claude Code will be installed via npm to that location instead of using the official installer." default = "$HOME/.local/bin" } @@ -402,6 +402,7 @@ module "agentapi" { echo -n '${base64encode(local.install_script)}' | base64 -d > /tmp/install.sh chmod +x /tmp/install.sh ARG_CLAUDE_CODE_VERSION='${var.claude_code_version}' \ + ARG_CLAUDE_BINARY_PATH='${var.claude_binary_path}' \ ARG_MCP_APP_STATUS_SLUG='${local.app_slug}' \ ARG_INSTALL_CLAUDE_CODE='${var.install_claude_code}' \ ARG_REPORT_TASKS='${var.report_tasks}' \ diff --git a/registry/coder/modules/claude-code/scripts/install.sh b/registry/coder/modules/claude-code/scripts/install.sh index 15981e8b5..0acfc0da2 100644 --- a/registry/coder/modules/claude-code/scripts/install.sh +++ b/registry/coder/modules/claude-code/scripts/install.sh @@ -9,6 +9,7 @@ command_exists() { } ARG_CLAUDE_CODE_VERSION=${ARG_CLAUDE_CODE_VERSION:-} +ARG_CLAUDE_BINARY_PATH=${ARG_CLAUDE_BINARY_PATH:-'$HOME/.local/bin'} ARG_WORKDIR=${ARG_WORKDIR:-"$HOME"} ARG_INSTALL_CLAUDE_CODE=${ARG_INSTALL_CLAUDE_CODE:-} ARG_REPORT_TASKS=${ARG_REPORT_TASKS:-true} @@ -17,9 +18,13 @@ ARG_MCP=$(echo -n "${ARG_MCP:-}" | base64 -d) ARG_ALLOWED_TOOLS=${ARG_ALLOWED_TOOLS:-} ARG_DISALLOWED_TOOLS=${ARG_DISALLOWED_TOOLS:-} +ARG_CLAUDE_BINARY_PATH=$(eval echo "$ARG_CLAUDE_BINARY_PATH") +DEFAULT_BINARY_PATH="$HOME/.local/bin" + echo "--------------------------------" printf "ARG_CLAUDE_CODE_VERSION: %s\n" "$ARG_CLAUDE_CODE_VERSION" +printf "ARG_CLAUDE_BINARY_PATH: %s\n" "$ARG_CLAUDE_BINARY_PATH" printf "ARG_WORKDIR: %s\n" "$ARG_WORKDIR" printf "ARG_INSTALL_CLAUDE_CODE: %s\n" "$ARG_INSTALL_CLAUDE_CODE" printf "ARG_REPORT_TASKS: %s\n" "$ARG_REPORT_TASKS" @@ -31,18 +36,45 @@ printf "ARG_DISALLOWED_TOOLS: %s\n" "$ARG_DISALLOWED_TOOLS" echo "--------------------------------" 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." + return + fi + + local use_npm=false + local specific_version=false + + if [ "$ARG_CLAUDE_BINARY_PATH" != "$DEFAULT_BINARY_PATH" ]; then + use_npm=true + fi + + if [ -n "$ARG_CLAUDE_CODE_VERSION" ] && [ "$ARG_CLAUDE_CODE_VERSION" != "latest" ]; then + use_npm=true + specific_version=true + fi + + if [ "$use_npm" = "true" ]; then + echo "Installing Claude Code via npm (custom path or version specified)" + NPM_PREFIX=$(dirname "$ARG_CLAUDE_BINARY_PATH") + mkdir -p "$NPM_PREFIX" + + local version_arg="" + if [ "$specific_version" = "true" ]; then + version_arg="@$ARG_CLAUDE_CODE_VERSION" + fi + + npm install -g "@anthropic-ai/claude-code${version_arg}" --prefix "$NPM_PREFIX" + echo "Installed Claude Code via npm to $NPM_PREFIX. Version: $($ARG_CLAUDE_BINARY_PATH/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 } From 2ecf6becbd9333e5210b77c9120358891d99bdff Mon Sep 17 00:00:00 2001 From: DevelopmentCats Date: Fri, 19 Dec 2025 13:22:41 -0600 Subject: [PATCH 10/10] feat: remove coder_env and replace with more elegant approach to ensuring claude is in path --- registry/coder/modules/claude-code/main.tf | 5 --- .../modules/claude-code/scripts/install.sh | 34 +++++++++++++++++++ 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/registry/coder/modules/claude-code/main.tf b/registry/coder/modules/claude-code/main.tf index b2258695a..c8c1f1007 100644 --- a/registry/coder/modules/claude-code/main.tf +++ b/registry/coder/modules/claude-code/main.tf @@ -291,11 +291,6 @@ resource "coder_env" "disable_autoupdater" { value = "1" } -resource "coder_env" "claude_binary_path" { - agent_id = var.agent_id - name = "PATH" - value = "${var.claude_binary_path}:$PATH" -} resource "coder_env" "anthropic_model" { count = var.model != "" ? 1 : 0 diff --git a/registry/coder/modules/claude-code/scripts/install.sh b/registry/coder/modules/claude-code/scripts/install.sh index 0acfc0da2..2dc0c46ff 100644 --- a/registry/coder/modules/claude-code/scripts/install.sh +++ b/registry/coder/modules/claude-code/scripts/install.sh @@ -35,6 +35,39 @@ printf "ARG_DISALLOWED_TOOLS: %s\n" "$ARG_DISALLOWED_TOOLS" echo "--------------------------------" +# Ensures claude is accessible in PATH when using a custom binary path +# Creates symlink in ~/.local/bin and adds to shell profiles +function ensure_claude_in_path() { + if [ "$ARG_CLAUDE_BINARY_PATH" = "$DEFAULT_BINARY_PATH" ]; then + # Default path - no action needed, official installer handles this + return + fi + + echo "Setting up PATH for custom claude location: $ARG_CLAUDE_BINARY_PATH" + + # Create symlink in ~/.local/bin so claude is accessible in PATH + mkdir -p "$HOME/.local/bin" + ln -sf "$ARG_CLAUDE_BINARY_PATH/claude" "$HOME/.local/bin/claude" + echo "Created symlink: $HOME/.local/bin/claude -> $ARG_CLAUDE_BINARY_PATH/claude" + + # Ensure ~/.local/bin is in PATH for this session (needed for claude mcp commands below) + export PATH="$HOME/.local/bin:$PATH" + + # Add to shell profiles for future interactive sessions + # Only modifies files that already exist, uses marker to prevent duplicates + local marker="# Added by claude-code module" + local path_export='export PATH="$HOME/.local/bin:$PATH"' + + for profile in "$HOME/.bashrc" "$HOME/.zshrc" "$HOME/.profile"; do + if [ -f "$profile" ] && ! grep -qF "$marker" "$profile" 2>/dev/null; then + echo "" >> "$profile" + echo "$marker" >> "$profile" + echo "$path_export" >> "$profile" + echo "Added ~/.local/bin to PATH in $profile" + fi + done +} + function install_claude_code_cli() { if [ "$ARG_INSTALL_CLAUDE_CODE" != "true" ]; then echo "Skipping Claude Code installation as per configuration." @@ -173,5 +206,6 @@ function report_tasks() { } install_claude_code_cli +ensure_claude_in_path setup_claude_configurations report_tasks