Skip to content
Merged
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
1 change: 1 addition & 0 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ jobs:
features:
- adr-tools
- chrome
- claude-code
- codex
- color
- gemini-cli
Expand Down
8 changes: 3 additions & 5 deletions src/claude-code/NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,11 @@

This feature installs [Claude Code](https://www.anthropic.com/claude-code), Anthropic's official CLI for AI-powered development assistance.

## Requirements

- Node.js
Claude Code is installed using the [native installer](https://code.claude.com/docs/en/setup), which automatically keeps itself up to date.

## Manual config for `devcontainer.json`

Mount the local `~/.claude/` directory into the Dev Contaier.
Mount the local `~/.claude/` directory into the Dev Container.
Add the following mount to the `devcontainer.json` file.
Replace `vscode` with the actual name of your user (see `remoteUser` property)

Expand All @@ -26,4 +24,4 @@ Replace `vscode` with the actual name of your user (see `remoteUser` property)

After installation, run `claude` in your project directory to get started.

For detailed documentation, see the [Claude Code documentation](https://docs.anthropic.com/en/docs/claude-code/overview).
For detailed documentation, see the [Claude Code documentation](https://code.claude.com/docs/en/setup).
8 changes: 2 additions & 6 deletions src/claude-code/devcontainer-feature.json
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
{
"id": "claude-code",
"version": "1.0.0",
"version": "2.0.0",
"name": "Claude Code",
"description": "Installs Claude Code CLI for AI-powered development assistance",
"options": {},
"installsAfter": [
"ghcr.io/devcontainers/features/node"
],
"customizations": {
"vscode": {
"extensions": [
"anthropic.claude-code"
]
}
},
"postStartCommand": "if command -v claude &>/dev/null; then claude update || true; fi"
}
}
56 changes: 26 additions & 30 deletions src/claude-code/install.sh
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -3,42 +3,38 @@ set -e

echo "Installing Claude Code..."

# Check if Node.js is available
if ! command -v node &> /dev/null; then
echo "Error: Node.js is required but not found. Please ensure the Node.js feature is installed."
exit 1
# Ensure curl is available
if ! command -v curl &> /dev/null; then
echo "curl not found, installing..."
if command -v apt-get &> /dev/null; then
apt-get update && apt-get install -y curl
elif command -v apk &> /dev/null; then
apk add --no-cache curl
elif command -v yum &> /dev/null; then
yum install -y curl
else
echo "Error: curl is required but could not be installed automatically."
exit 1
fi
fi

# Check Node.js version (requires 18+)
NODE_VERSION=$(node --version | sed 's/v//')
MAJOR_VERSION=$(echo $NODE_VERSION | cut -d. -f1)

if [ "$MAJOR_VERSION" -lt 18 ]; then
echo "Error: Node.js 18+ is required, but found version $NODE_VERSION"
exit 1
fi

# Check if npm is available
if ! command -v npm &> /dev/null; then
echo "Error: npm is required but not found."
exit 1
fi

# Install Claude Code - prefer remote user installation if available
# Install Claude Code using the native installer
# See https://code.claude.com/docs/en/setup
if [ -n "$_REMOTE_USER" ] && [ "$_REMOTE_USER" != "root" ]; then
echo "Installing Claude Code as user: $_REMOTE_USER"
NPM_PATH=$(which npm)
BIN_DIR=$(dirname "$NPM_PATH")
su "$_REMOTE_USER" -c "PATH=$BIN_DIR:\$PATH $NPM_PATH install -g @anthropic-ai/claude-code"
echo "Installing Claude Code for user: $_REMOTE_USER"
su "$_REMOTE_USER" -c "curl -fsSL https://claude.ai/install.sh | bash"
INSTALL_HOME="$_REMOTE_USER_HOME"
else
echo "Installing Claude Code globally as root"
npm install -g @anthropic-ai/claude-code
echo "Installing Claude Code"
curl -fsSL https://claude.ai/install.sh | bash
INSTALL_HOME="${HOME:-/root}"
fi

# Verify installation
if ! command -v claude &> /dev/null; then
echo "Error: Claude Code installation failed"
exit 1
# Ensure claude is on PATH for all users by symlinking to /usr/local/bin
# The native installer places the binary at ~/.local/bin/claude
if [ -f "$INSTALL_HOME/.local/bin/claude" ] && [ ! -f /usr/local/bin/claude ]; then
ln -s "$INSTALL_HOME/.local/bin/claude" /usr/local/bin/claude
echo "Symlinked claude to /usr/local/bin/claude"
fi

echo "Claude Code installed successfully!"
6 changes: 2 additions & 4 deletions ...ude-code/claude_code_with_node_feature.sh → test/claude-code/claude_code_default.sh
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/bin/bash

# This test file will be executed against the 'claude_code_with_node_feature' scenario
# to verify that Claude Code is properly installed with Node.js feature dependency.
# This test file will be executed against the 'claude_code_default' scenario
# to verify that Claude Code is properly installed using the native installer.

set -e

Expand All @@ -10,8 +10,6 @@ source dev-container-features-test-lib

# Feature-specific tests - simple smoke test
# The 'check' command comes from the dev-container-features-test-lib.
check "node is available" which node
check "npm is available" which npm
check "claude command available" which claude
check "claude shows version" bash -c "claude --version"

Expand Down
15 changes: 1 addition & 14 deletions test/claude-code/claude_code_with_custom_user.sh
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,29 +1,16 @@
#!/bin/bash

# This test file will be executed against the 'claude_code_with_custom_user' scenario
# to verify that Claude Code is installed globally using the remote user.
# to verify that Claude Code is installed for the remote user.

set -e

# Import test library bundled with the devcontainer CLI
source dev-container-features-test-lib

# Basic functionality tests
check "node is available" which node
check "npm is available" which npm
check "claude command available" which claude
check "claude shows version" bash -c "claude --version"

# Verify Claude Code is owned by the remote user (vscode), not root
# CLAUDE_PATH=$(which claude)
# check "claude binary is owned by vscode" bash -c "stat -c '%U' '$CLAUDE_PATH' | grep -q vscode"

# Verify npm global directory is owned by vscode
# NPM_GLOBAL_DIR=$(npm config get prefix)
# check "npm global directory is owned by vscode" bash -c "stat -c '%U' '$NPM_GLOBAL_DIR' | grep -q vscode"

# Verify Claude Code appears in user's global npm packages
check "claude appears in npm global packages" bash -c "npm list -g --depth=0 | grep -q claude"

# Report results
reportResults
20 changes: 0 additions & 20 deletions test/claude-code/claude_code_with_node_image.sh

This file was deleted.

14 changes: 1 addition & 13 deletions test/claude-code/scenarios.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,6 @@
{
"claude_code_with_node_feature": {
"claude_code_default": {
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
"features": {
"ghcr.io/devcontainers/features/node:1": {
"version": "lts"
},
"claude-code": {}
}
},
"claude_code_with_node_image": {
"image": "mcr.microsoft.com/devcontainers/javascript-node:1-20-bullseye",
"features": {
"claude-code": {}
}
Expand All @@ -18,9 +9,6 @@
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
"remoteUser": "vscode",
"features": {
"ghcr.io/devcontainers/features/node:1": {
"version": "lts"
},
"claude-code": {}
}
}
Expand Down
42 changes: 42 additions & 0 deletions test/claude-code/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#!/bin/bash

# This test file will be executed against an auto-generated devcontainer.json that
# includes the 'claude-code' Feature with no options.
#
# For more information, see: https://github.com/devcontainers/cli/blob/main/docs/features/test.md
#
# Eg:
# {
# "image": "<..some-base-image...>",
# "features": {
# "claude-code": {}
# },
# "remoteUser": "root"
# }
#
# Thus, the value of all options will fall back to the default value in the
# Feature's 'devcontainer-feature.json'.
#
# These scripts are run as 'root' by default. Although that can be changed
# with the '--remote-user' flag.
#
# This test can be run with the following command:
#
# devcontainer features test \
# --features claude-code \
# --remote-user root \
# --skip-scenarios \
# --base-image mcr.microsoft.com/devcontainers/base:ubuntu \
# /path/to/this/repo

set -e

# Optional: Import test library bundled with the devcontainer CLI
source dev-container-features-test-lib

# Feature-specific tests
check "claude command available" which claude
check "claude shows version" bash -c "claude --version"

# Report results
reportResults
Loading