Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions registry/coder/modules/claude-code/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 = "2.2.0"
version = "2.2.1"
agent_id = coder_agent.example.id
folder = "/home/coder"
install_claude_code = true
Expand Down Expand Up @@ -83,7 +83,7 @@ resource "coder_agent" "main" {
module "claude-code" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/claude-code/coder"
version = "2.2.0"
version = "2.2.1"
agent_id = coder_agent.example.id
folder = "/home/coder"
install_claude_code = true
Expand All @@ -101,7 +101,7 @@ Run Claude Code as a standalone app in your workspace. This will install Claude
```tf
module "claude-code" {
source = "registry.coder.com/coder/claude-code/coder"
version = "2.2.0"
version = "2.2.1"
agent_id = coder_agent.example.id
folder = "/home/coder"
install_claude_code = true
Expand All @@ -114,4 +114,6 @@ module "claude-code" {

## Troubleshooting

By default, this module is configured to run the embedded chat interface as a path-based application. In production, we recommend that you configure a [wildcard access URL](https://coder.com/docs/admin/setup#wildcard-access-url) and set `subdomain = true`. See [here](https://coder.com/docs/tutorials/best-practices/security-best-practices#disable-path-based-apps) for more details.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be a [!TIP] or [!NOTE] in first section of README.md instead of here.


The module will create log files in the workspace's `~/.claude-module` directory. If you run into any issues, look at them for more information.
35 changes: 34 additions & 1 deletion registry/coder/modules/claude-code/main.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
afterEach,
expect,
describe,
it,
setDefaultTimeout,
beforeAll,
} from "bun:test";
Expand Down Expand Up @@ -100,6 +101,7 @@ const writeAgentAPIMockControl = async ({
interface SetupProps {
skipAgentAPIMock?: boolean;
skipClaudeMock?: boolean;
extraVars?: Record<string, string>;
}

const projectDir = "/home/coder/project";
Expand All @@ -112,6 +114,7 @@ const setup = async (props?: SetupProps): Promise<{ id: string }> => {
install_claude_code: "false",
agentapi_version: "preview",
folder: projectDir,
...props?.extraVars,
},
});
await execContainer(id, ["bash", "-c", `mkdir -p '${projectDir}'`]);
Expand Down Expand Up @@ -335,6 +338,36 @@ describe("claude-code", async () => {
id,
"/home/coder/agentapi-mock.log",
);
expect(agentApiStartLog).toContain("AGENTAPI_ALLOWED_HOSTS: *");
expect(agentApiStartLog).toContain("AGENTAPI_ALLOWED_HOSTS=*");
});

describe("subdomain", async () => {
it("sets AGENTAPI_CHAT_BASE_PATH when false", async () => {
const { id } = await setup();
const respModuleScript = await execModuleScript(id);
expect(respModuleScript.exitCode).toBe(0);
await expectAgentAPIStarted(id);
const agentApiStartLog = await readFileContainer(
id,
"/home/coder/agentapi-mock.log",
);
expect(agentApiStartLog).toContain(
"AGENTAPI_CHAT_BASE_PATH=/@default/default.foo/apps/ccw/chat",
);
});

it("does not set AGENTAPI_CHAT_BASE_PATH when true", async () => {
const { id } = await setup({
extraVars: { subdomain: "true" },
});
const respModuleScript = await execModuleScript(id);
expect(respModuleScript.exitCode).toBe(0);
await expectAgentAPIStarted(id);
const agentApiStartLog = await readFileContainer(
id,
"/home/coder/agentapi-mock.log",
);
expect(agentApiStartLog).toMatch(/AGENTAPI_CHAT_BASE_PATH=$/m);
});
});
});
8 changes: 4 additions & 4 deletions registry/coder/modules/claude-code/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -106,12 +106,12 @@ variable "agentapi_version" {
variable "subdomain" {
type = bool
description = "Whether to use a subdomain for the Claude Code app."
default = true
default = false
}

locals {
# we have to trim the slash because otherwise coder exp mcp will
# set up an invalid claude config
# set up an invalid claude config
workdir = trimsuffix(var.folder, "/")
encoded_pre_install_script = var.experiment_pre_install_script != null ? base64encode(var.experiment_pre_install_script) : ""
encoded_post_install_script = var.experiment_post_install_script != null ? base64encode(var.experiment_post_install_script) : ""
Expand Down Expand Up @@ -244,7 +244,7 @@ resource "coder_script" "claude_code" {

# Disable host header check since AgentAPI is proxied by Coder (which does its own validation)
export AGENTAPI_ALLOWED_HOSTS="*"

# Set chat base path for non-subdomain routing (only set if not using subdomain)
export AGENTAPI_CHAT_BASE_PATH="${local.agentapi_chat_base_path}"

Expand Down Expand Up @@ -295,4 +295,4 @@ resource "coder_ai_task" "claude_code" {
sidebar_app {
id = coder_app.claude_code_web.id
}
}
}
3 changes: 2 additions & 1 deletion registry/coder/modules/claude-code/testdata/agentapi-mock.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ if (

fs.writeFileSync(
"/home/coder/agentapi-mock.log",
`AGENTAPI_ALLOWED_HOSTS: ${process.env.AGENTAPI_ALLOWED_HOSTS}`,
`AGENTAPI_ALLOWED_HOSTS=${process.env.AGENTAPI_ALLOWED_HOSTS}
AGENTAPI_CHAT_BASE_PATH=${process.env.AGENTAPI_CHAT_BASE_PATH}`,
);

console.log(`starting server on port ${port}`);
Expand Down