chore(claude-code): use $HOME variable instead of hardcoded path and remove symlink (#592)

## Description

- Remove hardcoded `/home/coder` path.
- Remove symlink in favour of coder_env "PATH".

## Type of Change

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

## Module Information

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

## Testing & Validation

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

## Related Issues

<!-- Link related issues or write "None" if not applicable -->

---------

Signed-off-by: 35C4n0r <work.jaykumar@gmail.com>
Co-authored-by: DevelopmentCats <christofer@coder.com>
This commit is contained in:
35C4n0r 2025-12-16 02:37:14 +05:30 committed by GitHub
parent aa4890fe62
commit a85436fdf4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 25 additions and 35 deletions

View File

@ -13,7 +13,7 @@ Run the [Claude Code](https://docs.anthropic.com/en/docs/agents-and-tools/claude
```tf ```tf
module "claude-code" { module "claude-code" {
source = "registry.coder.com/coder/claude-code/coder" source = "registry.coder.com/coder/claude-code/coder"
version = "4.2.6" version = "4.2.7"
agent_id = coder_agent.main.id agent_id = coder_agent.main.id
workdir = "/home/coder/project" workdir = "/home/coder/project"
claude_api_key = "xxxx-xxxxx-xxxx" 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 ```tf
module "claude-code" { module "claude-code" {
source = "dev.registry.coder.com/coder/claude-code/coder" source = "dev.registry.coder.com/coder/claude-code/coder"
version = "4.2.6" version = "4.2.7"
agent_id = coder_agent.main.id agent_id = coder_agent.main.id
workdir = "/home/coder/project" workdir = "/home/coder/project"
enable_boundary = true enable_boundary = true
@ -72,7 +72,7 @@ data "coder_parameter" "ai_prompt" {
module "claude-code" { module "claude-code" {
source = "registry.coder.com/coder/claude-code/coder" source = "registry.coder.com/coder/claude-code/coder"
version = "4.2.6" version = "4.2.7"
agent_id = coder_agent.main.id agent_id = coder_agent.main.id
workdir = "/home/coder/project" workdir = "/home/coder/project"
@ -92,10 +92,9 @@ module "claude-code" {
{ {
"mcpServers": { "mcpServers": {
"my-custom-tool": { "my-custom-tool": {
"command": "my-tool-server" "command": "my-tool-server",
"args": ["--port", "8080"] "args": ["--port", "8080"]
} }
} }
} }
EOF EOF
@ -109,7 +108,7 @@ Run and configure Claude Code as a standalone CLI in your workspace.
```tf ```tf
module "claude-code" { module "claude-code" {
source = "registry.coder.com/coder/claude-code/coder" source = "registry.coder.com/coder/claude-code/coder"
version = "4.2.6" version = "4.2.7"
agent_id = coder_agent.main.id agent_id = coder_agent.main.id
workdir = "/home/coder/project" workdir = "/home/coder/project"
install_claude_code = true install_claude_code = true
@ -131,7 +130,7 @@ variable "claude_code_oauth_token" {
module "claude-code" { module "claude-code" {
source = "registry.coder.com/coder/claude-code/coder" source = "registry.coder.com/coder/claude-code/coder"
version = "4.2.6" version = "4.2.7"
agent_id = coder_agent.main.id agent_id = coder_agent.main.id
workdir = "/home/coder/project" workdir = "/home/coder/project"
claude_code_oauth_token = var.claude_code_oauth_token claude_code_oauth_token = var.claude_code_oauth_token
@ -204,7 +203,7 @@ resource "coder_env" "bedrock_api_key" {
module "claude-code" { module "claude-code" {
source = "registry.coder.com/coder/claude-code/coder" source = "registry.coder.com/coder/claude-code/coder"
version = "4.2.6" version = "4.2.7"
agent_id = coder_agent.main.id agent_id = coder_agent.main.id
workdir = "/home/coder/project" workdir = "/home/coder/project"
model = "global.anthropic.claude-sonnet-4-5-20250929-v1:0" model = "global.anthropic.claude-sonnet-4-5-20250929-v1:0"
@ -261,7 +260,7 @@ resource "coder_env" "google_application_credentials" {
module "claude-code" { module "claude-code" {
source = "registry.coder.com/coder/claude-code/coder" source = "registry.coder.com/coder/claude-code/coder"
version = "4.2.6" version = "4.2.7"
agent_id = coder_agent.main.id agent_id = coder_agent.main.id
workdir = "/home/coder/project" workdir = "/home/coder/project"
model = "claude-sonnet-4@20250514" model = "claude-sonnet-4@20250514"

View File

@ -39,9 +39,11 @@ interface SetupProps {
agentapiMockScript?: string; agentapiMockScript?: string;
} }
const setup = async (props?: SetupProps): Promise<{ id: string }> => { const setup = async (
props?: SetupProps,
): Promise<{ id: string; coderEnvVars: Record<string, string> }> => {
const projectDir = "/home/coder/project"; const projectDir = "/home/coder/project";
const { id } = await setupUtil({ const { id, coderEnvVars } = await setupUtil({
moduleDir: import.meta.dir, moduleDir: import.meta.dir,
moduleVariables: { moduleVariables: {
install_claude_code: props?.skipClaudeMock ? "true" : "false", install_claude_code: props?.skipClaudeMock ? "true" : "false",
@ -61,7 +63,7 @@ const setup = async (props?: SetupProps): Promise<{ id: string }> => {
content: await loadTestFile(import.meta.dir, "claude-mock.sh"), content: await loadTestFile(import.meta.dir, "claude-mock.sh"),
}); });
} }
return { id }; return { id, coderEnvVars };
}; };
setDefaultTimeout(60 * 1000); setDefaultTimeout(60 * 1000);
@ -79,14 +81,14 @@ describe("claude-code", async () => {
test("install-claude-code-version", async () => { test("install-claude-code-version", async () => {
const version_to_install = "1.0.40"; const version_to_install = "1.0.40";
const { id } = await setup({ const { id, coderEnvVars } = await setup({
skipClaudeMock: true, skipClaudeMock: true,
moduleVariables: { moduleVariables: {
install_claude_code: "true", install_claude_code: "true",
claude_code_version: version_to_install, claude_code_version: version_to_install,
}, },
}); });
await execModuleScript(id); await execModuleScript(id, coderEnvVars);
const resp = await execContainer(id, [ const resp = await execContainer(id, [
"bash", "bash",
"-c", "-c",
@ -96,14 +98,14 @@ describe("claude-code", async () => {
}); });
test("check-latest-claude-code-version-works", async () => { test("check-latest-claude-code-version-works", async () => {
const { id } = await setup({ const { id, coderEnvVars } = await setup({
skipClaudeMock: true, skipClaudeMock: true,
skipAgentAPIMock: true, skipAgentAPIMock: true,
moduleVariables: { moduleVariables: {
install_claude_code: "true", install_claude_code: "true",
}, },
}); });
await execModuleScript(id); await execModuleScript(id, coderEnvVars);
await expectAgentAPIStarted(id); await expectAgentAPIStarted(id);
}); });
@ -133,13 +135,13 @@ describe("claude-code", async () => {
}, },
}, },
}); });
const { id } = await setup({ const { id, coderEnvVars } = await setup({
skipClaudeMock: true, skipClaudeMock: true,
moduleVariables: { moduleVariables: {
mcp: mcpConfig, mcp: mcpConfig,
}, },
}); });
await execModuleScript(id); await execModuleScript(id, coderEnvVars);
const resp = await readFileContainer(id, "/home/coder/.claude.json"); const resp = await readFileContainer(id, "/home/coder/.claude.json");
expect(resp).toContain("test-cmd"); expect(resp).toContain("test-cmd");

View File

@ -288,6 +288,12 @@ resource "coder_env" "disable_autoupdater" {
value = "1" value = "1"
} }
resource "coder_env" "claude_binary_path" {
agent_id = var.agent_id
name = "PATH"
value = "$HOME/.local/bin:$PATH"
}
locals { locals {
# we have to trim the slash because otherwise coder exp mcp will # we have to trim the slash because otherwise coder exp mcp will
# set up an invalid claude config # set up an invalid claude config

View File

@ -1,10 +1,5 @@
#!/bin/bash #!/bin/bash
if [ -f "$HOME/.bashrc" ]; then
source "$HOME"/.bashrc
fi
# Set strict error handling AFTER sourcing bashrc to avoid unbound variable errors from user dotfiles
set -euo pipefail set -euo pipefail
BOLD='\033[0;1m' BOLD='\033[0;1m'
@ -45,11 +40,6 @@ function install_claude_code_cli() {
if [ $CURL_EXIT -ne 0 ]; then 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 fi
# Ensure binaries are discoverable.
echo "Creating a symlink for claude"
sudo ln -s /home/coder/.local/bin/claude /usr/local/bin/claude
echo "Installed Claude Code successfully. Version: $(claude --version || echo 'unknown')" echo "Installed Claude Code successfully. Version: $(claude --version || echo 'unknown')"
else else
echo "Skipping Claude Code installation as per configuration." echo "Skipping Claude Code installation as per configuration."

View File

@ -1,14 +1,7 @@
#!/bin/bash #!/bin/bash
if [ -f "$HOME/.bashrc" ]; then
source "$HOME"/.bashrc
fi
# Set strict error handling AFTER sourcing bashrc to avoid unbound variable errors from user dotfiles
set -euo pipefail set -euo pipefail
export PATH="$HOME/.local/bin:$PATH"
command_exists() { command_exists() {
command -v "$1" > /dev/null 2>&1 command -v "$1" > /dev/null 2>&1
} }