diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 883fb26..699ba69 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -15,6 +15,7 @@ jobs: features: - adr-tools - chrome + - claude-code - codex - color - gemini-cli diff --git a/src/claude-code/NOTES.md b/src/claude-code/NOTES.md index 4507974..1926254 100644 --- a/src/claude-code/NOTES.md +++ b/src/claude-code/NOTES.md @@ -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) @@ -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). diff --git a/src/claude-code/devcontainer-feature.json b/src/claude-code/devcontainer-feature.json index 0d5663d..8993c0f 100644 --- a/src/claude-code/devcontainer-feature.json +++ b/src/claude-code/devcontainer-feature.json @@ -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" + } } diff --git a/src/claude-code/install.sh b/src/claude-code/install.sh old mode 100644 new mode 100755 index bb3304d..75e4969 --- a/src/claude-code/install.sh +++ b/src/claude-code/install.sh @@ -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!" diff --git a/test/claude-code/claude_code_with_node_feature.sh b/test/claude-code/claude_code_default.sh old mode 100644 new mode 100755 similarity index 65% rename from test/claude-code/claude_code_with_node_feature.sh rename to test/claude-code/claude_code_default.sh index 56ac37c..e958bbd --- a/test/claude-code/claude_code_with_node_feature.sh +++ b/test/claude-code/claude_code_default.sh @@ -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 @@ -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" diff --git a/test/claude-code/claude_code_with_custom_user.sh b/test/claude-code/claude_code_with_custom_user.sh old mode 100644 new mode 100755 index 88bb73a..9af9e29 --- a/test/claude-code/claude_code_with_custom_user.sh +++ b/test/claude-code/claude_code_with_custom_user.sh @@ -1,7 +1,7 @@ #!/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 @@ -9,21 +9,8 @@ set -e 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 diff --git a/test/claude-code/claude_code_with_node_image.sh b/test/claude-code/claude_code_with_node_image.sh deleted file mode 100644 index d09721b..0000000 --- a/test/claude-code/claude_code_with_node_image.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash - -# This test file will be executed against the 'claude_code_with_node_image' scenario -# to verify that Claude Code works with Node.js base images that already have Node.js installed. - -set -e - -# Optional: Import test library bundled with the devcontainer CLI -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" - -# Report results -# If any of the checks above exited with a non-zero exit code, the test will fail. -reportResults diff --git a/test/claude-code/scenarios.json b/test/claude-code/scenarios.json index fe1f311..40a82a9 100644 --- a/test/claude-code/scenarios.json +++ b/test/claude-code/scenarios.json @@ -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": {} } @@ -18,9 +9,6 @@ "image": "mcr.microsoft.com/devcontainers/base:ubuntu", "remoteUser": "vscode", "features": { - "ghcr.io/devcontainers/features/node:1": { - "version": "lts" - }, "claude-code": {} } } diff --git a/test/claude-code/test.sh b/test/claude-code/test.sh new file mode 100755 index 0000000..e8811e0 --- /dev/null +++ b/test/claude-code/test.sh @@ -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