From 8305a82186aa60f71db9398362ed6e03a145b634 Mon Sep 17 00:00:00 2001 From: Rob W <30517573+bertlebee@users.noreply.github.com> Date: Fri, 18 Apr 2025 10:55:36 +1000 Subject: [PATCH 1/4] add claude-code and claude-yolo --- src/claude-code/README.md | 34 +++++ src/claude-code/devcontainer-feature.json | 20 +++ src/claude-code/install.sh | 21 +++ src/claude-code/library_scripts.sh | 173 ++++++++++++++++++++++ src/claude-yolo/README.md | 39 +++++ src/claude-yolo/devcontainer-feature.json | 19 +++ src/claude-yolo/install.sh | 27 ++++ src/claude-yolo/library_scripts.sh | 173 ++++++++++++++++++++++ test/claude-code/scenarios.json | 18 +++ test/claude-code/test.sh | 9 ++ test/claude-code/test_debian.sh | 9 ++ test/claude-code/test_specific_version.sh | 9 ++ test/claude-yolo/scenarios.json | 20 +++ test/claude-yolo/test.sh | 11 ++ test/claude-yolo/test_debian.sh | 9 ++ test/claude-yolo/test_specific_version.sh | 11 ++ 16 files changed, 602 insertions(+) create mode 100644 src/claude-code/README.md create mode 100644 src/claude-code/devcontainer-feature.json create mode 100755 src/claude-code/install.sh create mode 100644 src/claude-code/library_scripts.sh create mode 100644 src/claude-yolo/README.md create mode 100644 src/claude-yolo/devcontainer-feature.json create mode 100755 src/claude-yolo/install.sh create mode 100644 src/claude-yolo/library_scripts.sh create mode 100644 test/claude-code/scenarios.json create mode 100755 test/claude-code/test.sh create mode 100755 test/claude-code/test_debian.sh create mode 100755 test/claude-code/test_specific_version.sh create mode 100644 test/claude-yolo/scenarios.json create mode 100755 test/claude-yolo/test.sh create mode 100755 test/claude-yolo/test_debian.sh create mode 100755 test/claude-yolo/test_specific_version.sh diff --git a/src/claude-code/README.md b/src/claude-code/README.md new file mode 100644 index 000000000..827c22334 --- /dev/null +++ b/src/claude-code/README.md @@ -0,0 +1,34 @@ +# Claude Code (via npm) + +Claude Code is Anthropic's official CLI for Claude, enabling access to Claude's capabilities from the command line. + +## Example Usage + +```json +"features": { + "ghcr.io/devcontainers-extra/features/claude-code:1": { + "version": "latest" + } +} +``` + +## Options + +| Options Id | Description | Type | Default Value | +|-----|-----|-----|-----| +| version | Select the version to install. | string | "latest" | + +## Customizations + +### VS Code Extensions + +- `anthropic.claude-vscode`: Claude for VS Code - The official extension for using Claude in VS Code + +## License + +MIT + +## References + +- [Claude Code documentation](https://docs.anthropic.com/en/docs/agents-and-tools/claude-code/overview) +- [Claude Code GitHub repository](https://github.com/anthropics/claude-code) \ No newline at end of file diff --git a/src/claude-code/devcontainer-feature.json b/src/claude-code/devcontainer-feature.json new file mode 100644 index 000000000..25ce3024e --- /dev/null +++ b/src/claude-code/devcontainer-feature.json @@ -0,0 +1,20 @@ +{ + "id": "claude-code", + "version": "1.0.0", + "name": "claude-code (via npm)", + "documentationURL": "http://github.com/devcontainers-extra/features/tree/main/src/claude-code", + "description": "Claude Code is Anthropic's official CLI for Claude, enabling access to Claude's capabilities from the command line", + "options": { + "version": { + "default": "latest", + "description": "Select the version to install.", + "proposals": [ + "latest" + ], + "type": "string" + } + }, + "installsAfter": [ + "ghcr.io/devcontainers/features/node" + ] +} \ No newline at end of file diff --git a/src/claude-code/install.sh b/src/claude-code/install.sh new file mode 100755 index 000000000..c7de5a3a8 --- /dev/null +++ b/src/claude-code/install.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +set -e + +source ./library_scripts.sh + +# nanolayer is a cli utility which keeps container layers as small as possible +# source code: https://github.com/devcontainers-extra/nanolayer +# `ensure_nanolayer` is a bash function that will find any existing nanolayer installations, +# and if missing - will download a temporary copy that automatically get deleted at the end +# of the script +ensure_nanolayer nanolayer_location "v0.5.6" + +# Install Claude Code globally via npm +if [ "${VERSION}" = "latest" ]; then + npm install -g "@anthropic-ai/claude-code" +else + npm install -g "@anthropic-ai/claude-code@${VERSION}" +fi + +echo 'Claude Code installed successfully!' diff --git a/src/claude-code/library_scripts.sh b/src/claude-code/library_scripts.sh new file mode 100644 index 000000000..f6d0760d7 --- /dev/null +++ b/src/claude-code/library_scripts.sh @@ -0,0 +1,173 @@ +#!/usr/bin/env bash + +clean_download() { + # The purpose of this function is to download a file with minimal impact on container layer size + # this means if no valid downloader is found (curl or wget) then we install a downloader (currently wget) in a + # temporary manner, and making sure to + # 1. uninstall the downloader at the return of the function + # 2. revert back any changes to the package installer database/cache (for example apt-get lists) + # The above steps will minimize the leftovers being created while installing the downloader + # Supported distros: + # debian/ubuntu/alpine + + url=$1 + output_location=$2 + tempdir=$(mktemp -d) + downloader_installed="" + + function _apt_get_install() { + tempdir=$1 + + # copy current state of apt list - in order to revert back later (minimize contianer layer size) + cp -p -R /var/lib/apt/lists $tempdir + apt-get update -y + apt-get -y install --no-install-recommends wget ca-certificates + } + + function _apt_get_cleanup() { + tempdir=$1 + + echo "removing wget" + apt-get -y purge wget --auto-remove + + echo "revert back apt lists" + rm -rf /var/lib/apt/lists/* + rm -r /var/lib/apt/lists && mv $tempdir/lists /var/lib/apt/lists + } + + function _apk_install() { + tempdir=$1 + # copy current state of apk cache - in order to revert back later (minimize contianer layer size) + cp -p -R /var/cache/apk $tempdir + + apk add --no-cache wget + } + + function _apk_cleanup() { + tempdir=$1 + + echo "removing wget" + apk del wget + } + # try to use either wget or curl if one of them already installer + if type curl >/dev/null 2>&1; then + downloader=curl + elif type wget >/dev/null 2>&1; then + downloader=wget + else + downloader="" + fi + + # in case none of them is installed, install wget temporarly + if [ -z $downloader ]; then + if [ -x "/usr/bin/apt-get" ]; then + _apt_get_install $tempdir + elif [ -x "/sbin/apk" ]; then + _apk_install $tempdir + else + echo "distro not supported" + exit 1 + fi + downloader="wget" + downloader_installed="true" + fi + + if [ $downloader = "wget" ]; then + wget -q $url -O $output_location + else + curl -sfL $url -o $output_location + fi + + # NOTE: the cleanup procedure was not implemented using `trap X RETURN` only because + # alpine lack bash, and RETURN is not a valid signal under sh shell + if ! [ -z $downloader_installed ]; then + if [ -x "/usr/bin/apt-get" ]; then + _apt_get_cleanup $tempdir + elif [ -x "/sbin/apk" ]; then + _apk_cleanup $tempdir + else + echo "distro not supported" + exit 1 + fi + fi + +} + +ensure_nanolayer() { + # Ensure existance of the nanolayer cli program + local variable_name=$1 + + local required_version=$2 + # normalize version + if ! [[ $required_version == v* ]]; then + required_version=v$required_version + fi + + local nanolayer_location="" + + # If possible - try to use an already installed nanolayer + if [[ -z "${NANOLAYER_FORCE_CLI_INSTALLATION}" ]]; then + if [[ -z "${NANOLAYER_CLI_LOCATION}" ]]; then + if type nanolayer >/dev/null 2>&1; then + echo "Found a pre-existing nanolayer in PATH" + nanolayer_location=nanolayer + fi + elif [ -f "${NANOLAYER_CLI_LOCATION}" ] && [ -x "${NANOLAYER_CLI_LOCATION}" ]; then + nanolayer_location=${NANOLAYER_CLI_LOCATION} + echo "Found a pre-existing nanolayer which were given in env variable: $nanolayer_location" + fi + + # make sure its of the required version + if ! [[ -z "${nanolayer_location}" ]]; then + local current_version + current_version=$($nanolayer_location --version) + if ! [[ $current_version == v* ]]; then + current_version=v$current_version + fi + + if ! [ $current_version == $required_version ]; then + echo "skipping usage of pre-existing nanolayer. (required version $required_version does not match existing version $current_version)" + nanolayer_location="" + fi + fi + + fi + + # If not previuse installation found, download it temporarly and delete at the end of the script + if [[ -z "${nanolayer_location}" ]]; then + + if [ "$(uname -sm)" == "Linux x86_64" ] || [ "$(uname -sm)" == "Linux aarch64" ]; then + tmp_dir=$(mktemp -d -t nanolayer-XXXXXXXXXX) + + clean_up() { + ARG=$? + rm -rf $tmp_dir + exit $ARG + } + trap clean_up EXIT + + if [ -x "/sbin/apk" ]; then + clib_type=musl + else + clib_type=gnu + fi + + tar_filename=nanolayer-"$(uname -m)"-unknown-linux-$clib_type.tgz + + # clean download will minimize leftover in case a downloaderlike wget or curl need to be installed + clean_download https://github.com/devcontainers-extra/nanolayer/releases/download/$required_version/$tar_filename $tmp_dir/$tar_filename + + tar xfzv $tmp_dir/$tar_filename -C "$tmp_dir" + chmod a+x $tmp_dir/nanolayer + nanolayer_location=$tmp_dir/nanolayer + + else + echo "No binaries compiled for non-x86-linux architectures yet: $(uname -m)" + exit 1 + fi + fi + + # Expose outside the resolved location + declare -g ${variable_name}=$nanolayer_location + +} diff --git a/src/claude-yolo/README.md b/src/claude-yolo/README.md new file mode 100644 index 000000000..f88e0667d --- /dev/null +++ b/src/claude-yolo/README.md @@ -0,0 +1,39 @@ +# Claude YOLO (via npm) + +Claude YOLO enables visual object detection capabilities with Claude in the command line. It works with the Claude Code CLI to provide AI-powered object detection. + +## Example Usage + +```json +"features": { + "ghcr.io/devcontainers-extra/features/claude-code:1": {}, + "ghcr.io/devcontainers-extra/features/claude-yolo:1": { + "version": "latest" + } +} +``` + +## Options + +| Options Id | Description | Type | Default Value | +|-----|-----|-----|-----| +| version | Select the version to install. | string | "latest" | + +## Requirements + +- This feature requires the Claude Code CLI to be installed first +- Node.js is required for installation + +## Customizations + +### VS Code Extensions + +- `anthropic.claude-vscode`: Claude for VS Code - The official extension for using Claude in VS Code + +## License + +MIT + +## References + +- [Claude Code documentation](https://docs.anthropic.com/en/docs/agents-and-tools/claude-code/overview) \ No newline at end of file diff --git a/src/claude-yolo/devcontainer-feature.json b/src/claude-yolo/devcontainer-feature.json new file mode 100644 index 000000000..960b18f0e --- /dev/null +++ b/src/claude-yolo/devcontainer-feature.json @@ -0,0 +1,19 @@ +{ + "id": "claude-yolo", + "version": "1.0.0", + "name": "claude-yolo (via npm)", + "documentationURL": "http://github.com/devcontainers-extra/features/tree/main/src/claude-yolo", + "description": "A wrapper for the Claude CLI that ALWAYS enables --dangerously-skip-permissions mode AND bypasses Docker and internet permission checks so that you can run in danger mode anywhere, anytime. Use at your own risk.", + "options": { + "version": { + "default": "latest", + "description": "Select the version to install.", + "proposals": ["latest"], + "type": "string" + } + }, + "installsAfter": [ + "ghcr.io/devcontainers/features/node", + "ghcr.io/devcontainers-extra/features/claude-code" + ] +} diff --git a/src/claude-yolo/install.sh b/src/claude-yolo/install.sh new file mode 100755 index 000000000..774d8b735 --- /dev/null +++ b/src/claude-yolo/install.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash + +set -e + +source ./library_scripts.sh + +# nanolayer is a cli utility which keeps container layers as small as possible +# source code: https://github.com/devcontainers-extra/nanolayer +# `ensure_nanolayer` is a bash function that will find any existing nanolayer installations, +# and if missing - will download a temporary copy that automatically get deleted at the end +# of the script +ensure_nanolayer nanolayer_location "v0.5.6" + +# Check if claude-code is installed +if ! command -v claude-code &> /dev/null; then + echo "Error: claude-code is required but not installed. Please install it first." + exit 1 +fi + +# Install Claude YOLO globally via npm +if [ "${VERSION}" = "latest" ]; then + npm install -g "claude-yolo" +else + npm install -g "claude-yolo@${VERSION}" +fi + +echo 'Claude YOLO installed successfully!' diff --git a/src/claude-yolo/library_scripts.sh b/src/claude-yolo/library_scripts.sh new file mode 100644 index 000000000..f6d0760d7 --- /dev/null +++ b/src/claude-yolo/library_scripts.sh @@ -0,0 +1,173 @@ +#!/usr/bin/env bash + +clean_download() { + # The purpose of this function is to download a file with minimal impact on container layer size + # this means if no valid downloader is found (curl or wget) then we install a downloader (currently wget) in a + # temporary manner, and making sure to + # 1. uninstall the downloader at the return of the function + # 2. revert back any changes to the package installer database/cache (for example apt-get lists) + # The above steps will minimize the leftovers being created while installing the downloader + # Supported distros: + # debian/ubuntu/alpine + + url=$1 + output_location=$2 + tempdir=$(mktemp -d) + downloader_installed="" + + function _apt_get_install() { + tempdir=$1 + + # copy current state of apt list - in order to revert back later (minimize contianer layer size) + cp -p -R /var/lib/apt/lists $tempdir + apt-get update -y + apt-get -y install --no-install-recommends wget ca-certificates + } + + function _apt_get_cleanup() { + tempdir=$1 + + echo "removing wget" + apt-get -y purge wget --auto-remove + + echo "revert back apt lists" + rm -rf /var/lib/apt/lists/* + rm -r /var/lib/apt/lists && mv $tempdir/lists /var/lib/apt/lists + } + + function _apk_install() { + tempdir=$1 + # copy current state of apk cache - in order to revert back later (minimize contianer layer size) + cp -p -R /var/cache/apk $tempdir + + apk add --no-cache wget + } + + function _apk_cleanup() { + tempdir=$1 + + echo "removing wget" + apk del wget + } + # try to use either wget or curl if one of them already installer + if type curl >/dev/null 2>&1; then + downloader=curl + elif type wget >/dev/null 2>&1; then + downloader=wget + else + downloader="" + fi + + # in case none of them is installed, install wget temporarly + if [ -z $downloader ]; then + if [ -x "/usr/bin/apt-get" ]; then + _apt_get_install $tempdir + elif [ -x "/sbin/apk" ]; then + _apk_install $tempdir + else + echo "distro not supported" + exit 1 + fi + downloader="wget" + downloader_installed="true" + fi + + if [ $downloader = "wget" ]; then + wget -q $url -O $output_location + else + curl -sfL $url -o $output_location + fi + + # NOTE: the cleanup procedure was not implemented using `trap X RETURN` only because + # alpine lack bash, and RETURN is not a valid signal under sh shell + if ! [ -z $downloader_installed ]; then + if [ -x "/usr/bin/apt-get" ]; then + _apt_get_cleanup $tempdir + elif [ -x "/sbin/apk" ]; then + _apk_cleanup $tempdir + else + echo "distro not supported" + exit 1 + fi + fi + +} + +ensure_nanolayer() { + # Ensure existance of the nanolayer cli program + local variable_name=$1 + + local required_version=$2 + # normalize version + if ! [[ $required_version == v* ]]; then + required_version=v$required_version + fi + + local nanolayer_location="" + + # If possible - try to use an already installed nanolayer + if [[ -z "${NANOLAYER_FORCE_CLI_INSTALLATION}" ]]; then + if [[ -z "${NANOLAYER_CLI_LOCATION}" ]]; then + if type nanolayer >/dev/null 2>&1; then + echo "Found a pre-existing nanolayer in PATH" + nanolayer_location=nanolayer + fi + elif [ -f "${NANOLAYER_CLI_LOCATION}" ] && [ -x "${NANOLAYER_CLI_LOCATION}" ]; then + nanolayer_location=${NANOLAYER_CLI_LOCATION} + echo "Found a pre-existing nanolayer which were given in env variable: $nanolayer_location" + fi + + # make sure its of the required version + if ! [[ -z "${nanolayer_location}" ]]; then + local current_version + current_version=$($nanolayer_location --version) + if ! [[ $current_version == v* ]]; then + current_version=v$current_version + fi + + if ! [ $current_version == $required_version ]; then + echo "skipping usage of pre-existing nanolayer. (required version $required_version does not match existing version $current_version)" + nanolayer_location="" + fi + fi + + fi + + # If not previuse installation found, download it temporarly and delete at the end of the script + if [[ -z "${nanolayer_location}" ]]; then + + if [ "$(uname -sm)" == "Linux x86_64" ] || [ "$(uname -sm)" == "Linux aarch64" ]; then + tmp_dir=$(mktemp -d -t nanolayer-XXXXXXXXXX) + + clean_up() { + ARG=$? + rm -rf $tmp_dir + exit $ARG + } + trap clean_up EXIT + + if [ -x "/sbin/apk" ]; then + clib_type=musl + else + clib_type=gnu + fi + + tar_filename=nanolayer-"$(uname -m)"-unknown-linux-$clib_type.tgz + + # clean download will minimize leftover in case a downloaderlike wget or curl need to be installed + clean_download https://github.com/devcontainers-extra/nanolayer/releases/download/$required_version/$tar_filename $tmp_dir/$tar_filename + + tar xfzv $tmp_dir/$tar_filename -C "$tmp_dir" + chmod a+x $tmp_dir/nanolayer + nanolayer_location=$tmp_dir/nanolayer + + else + echo "No binaries compiled for non-x86-linux architectures yet: $(uname -m)" + exit 1 + fi + fi + + # Expose outside the resolved location + declare -g ${variable_name}=$nanolayer_location + +} diff --git a/test/claude-code/scenarios.json b/test/claude-code/scenarios.json new file mode 100644 index 000000000..e68863cc0 --- /dev/null +++ b/test/claude-code/scenarios.json @@ -0,0 +1,18 @@ +{ + "test_debian": { + "image": "mcr.microsoft.com/devcontainers/base:debian", + "features": { + "ghcr.io/devcontainers/features/node:1": {}, + "claude-code": {} + } + }, + "test_specific_version": { + "image": "mcr.microsoft.com/devcontainers/base:debian", + "features": { + "ghcr.io/devcontainers/features/node:1": {}, + "claude-code": { + "version": "0.2.72" + } + } + } +} \ No newline at end of file diff --git a/test/claude-code/test.sh b/test/claude-code/test.sh new file mode 100755 index 000000000..d21e69cd5 --- /dev/null +++ b/test/claude-code/test.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +set -e + +source dev-container-features-test-lib + +check "Claude Code is installed" claude-code --version + +reportResults diff --git a/test/claude-code/test_debian.sh b/test/claude-code/test_debian.sh new file mode 100755 index 000000000..b2873a73c --- /dev/null +++ b/test/claude-code/test_debian.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +set -e + +source dev-container-features-test-lib + +check "something is installed" something --version + +reportResults diff --git a/test/claude-code/test_specific_version.sh b/test/claude-code/test_specific_version.sh new file mode 100755 index 000000000..1d71f5ebe --- /dev/null +++ b/test/claude-code/test_specific_version.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +set -e + +source dev-container-features-test-lib + +check "Claude Code version is equal to 0.2.72" sh -c "claude-code --version | grep '0.2.72'" + +reportResults diff --git a/test/claude-yolo/scenarios.json b/test/claude-yolo/scenarios.json new file mode 100644 index 000000000..97bef6b58 --- /dev/null +++ b/test/claude-yolo/scenarios.json @@ -0,0 +1,20 @@ +{ + "test_debian": { + "image": "mcr.microsoft.com/devcontainers/base:debian", + "features": { + "ghcr.io/devcontainers/features/node:1": {}, + "ghcr.io/devcontainers-extra/features/claude-code:1": {}, + "claude-yolo": {} + } + }, + "test_specific_version": { + "image": "mcr.microsoft.com/devcontainers/base:debian", + "features": { + "ghcr.io/devcontainers/features/node:1": {}, + "ghcr.io/devcontainers-extra/features/claude-code:1": {}, + "claude-yolo": { + "version": "0.1.0" + } + } + } +} \ No newline at end of file diff --git a/test/claude-yolo/test.sh b/test/claude-yolo/test.sh new file mode 100755 index 000000000..db3200253 --- /dev/null +++ b/test/claude-yolo/test.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +set -e + +source dev-container-features-test-lib + +# Check both Claude Code and Claude YOLO are installed +check "Claude Code is installed" claude-code --version +check "Claude YOLO is installed" claude-yolo --version + +reportResults diff --git a/test/claude-yolo/test_debian.sh b/test/claude-yolo/test_debian.sh new file mode 100755 index 000000000..b2873a73c --- /dev/null +++ b/test/claude-yolo/test_debian.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +set -e + +source dev-container-features-test-lib + +check "something is installed" something --version + +reportResults diff --git a/test/claude-yolo/test_specific_version.sh b/test/claude-yolo/test_specific_version.sh new file mode 100755 index 000000000..faaa1872f --- /dev/null +++ b/test/claude-yolo/test_specific_version.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +set -e + +source dev-container-features-test-lib + +# Check that Claude Code is installed and Claude YOLO has the specific version +check "Claude Code is installed" claude-code --version +check "Claude YOLO version is equal to 0.1.0" sh -c "claude-yolo --version | grep '0.1.0'" + +reportResults From cbc4513ceea08dd40001dc3d23e76679397d664b Mon Sep 17 00:00:00 2001 From: Rob W <30517573+bertlebee@users.noreply.github.com> Date: Fri, 18 Apr 2025 04:18:45 +0000 Subject: [PATCH 2/4] claude-yolo --- src/claude-yolo/devcontainer-feature.json | 3 +-- src/claude-yolo/install.sh | 6 ------ test/claude-code/scenarios.json | 2 +- test/claude-code/test.sh | 2 +- test/claude-code/test_debian.sh | 2 +- test/claude-code/test_specific_version.sh | 2 +- test/claude-yolo/scenarios.json | 2 +- test/claude-yolo/test_debian.sh | 2 +- test/claude-yolo/test_specific_version.sh | 3 +-- 9 files changed, 8 insertions(+), 16 deletions(-) diff --git a/src/claude-yolo/devcontainer-feature.json b/src/claude-yolo/devcontainer-feature.json index 960b18f0e..bb3b1f451 100644 --- a/src/claude-yolo/devcontainer-feature.json +++ b/src/claude-yolo/devcontainer-feature.json @@ -13,7 +13,6 @@ } }, "installsAfter": [ - "ghcr.io/devcontainers/features/node", - "ghcr.io/devcontainers-extra/features/claude-code" + "ghcr.io/devcontainers/features/node" ] } diff --git a/src/claude-yolo/install.sh b/src/claude-yolo/install.sh index 774d8b735..2f715c03c 100755 --- a/src/claude-yolo/install.sh +++ b/src/claude-yolo/install.sh @@ -11,12 +11,6 @@ source ./library_scripts.sh # of the script ensure_nanolayer nanolayer_location "v0.5.6" -# Check if claude-code is installed -if ! command -v claude-code &> /dev/null; then - echo "Error: claude-code is required but not installed. Please install it first." - exit 1 -fi - # Install Claude YOLO globally via npm if [ "${VERSION}" = "latest" ]; then npm install -g "claude-yolo" diff --git a/test/claude-code/scenarios.json b/test/claude-code/scenarios.json index e68863cc0..93eac09cc 100644 --- a/test/claude-code/scenarios.json +++ b/test/claude-code/scenarios.json @@ -11,7 +11,7 @@ "features": { "ghcr.io/devcontainers/features/node:1": {}, "claude-code": { - "version": "0.2.72" + "version": "0.2.70" } } } diff --git a/test/claude-code/test.sh b/test/claude-code/test.sh index d21e69cd5..60c2c9789 100755 --- a/test/claude-code/test.sh +++ b/test/claude-code/test.sh @@ -4,6 +4,6 @@ set -e source dev-container-features-test-lib -check "Claude Code is installed" claude-code --version +check "Claude Code is installed" claude --version reportResults diff --git a/test/claude-code/test_debian.sh b/test/claude-code/test_debian.sh index b2873a73c..d8c00b08c 100755 --- a/test/claude-code/test_debian.sh +++ b/test/claude-code/test_debian.sh @@ -4,6 +4,6 @@ set -e source dev-container-features-test-lib -check "something is installed" something --version +check "claude is installed" claude --version reportResults diff --git a/test/claude-code/test_specific_version.sh b/test/claude-code/test_specific_version.sh index 1d71f5ebe..2f1e4dd38 100755 --- a/test/claude-code/test_specific_version.sh +++ b/test/claude-code/test_specific_version.sh @@ -4,6 +4,6 @@ set -e source dev-container-features-test-lib -check "Claude Code version is equal to 0.2.72" sh -c "claude-code --version | grep '0.2.72'" +check "Claude Code version is equal to 0.2.70" sh -c "claude --version | grep '0.2.70'" reportResults diff --git a/test/claude-yolo/scenarios.json b/test/claude-yolo/scenarios.json index 97bef6b58..e419efa1f 100644 --- a/test/claude-yolo/scenarios.json +++ b/test/claude-yolo/scenarios.json @@ -13,7 +13,7 @@ "ghcr.io/devcontainers/features/node:1": {}, "ghcr.io/devcontainers-extra/features/claude-code:1": {}, "claude-yolo": { - "version": "0.1.0" + "version": "1.6.4" } } } diff --git a/test/claude-yolo/test_debian.sh b/test/claude-yolo/test_debian.sh index b2873a73c..7a88356da 100755 --- a/test/claude-yolo/test_debian.sh +++ b/test/claude-yolo/test_debian.sh @@ -4,6 +4,6 @@ set -e source dev-container-features-test-lib -check "something is installed" something --version +check "claude-yolo is installed" claude-yolo --version reportResults diff --git a/test/claude-yolo/test_specific_version.sh b/test/claude-yolo/test_specific_version.sh index faaa1872f..0d521a2ab 100755 --- a/test/claude-yolo/test_specific_version.sh +++ b/test/claude-yolo/test_specific_version.sh @@ -5,7 +5,6 @@ set -e source dev-container-features-test-lib # Check that Claude Code is installed and Claude YOLO has the specific version -check "Claude Code is installed" claude-code --version -check "Claude YOLO version is equal to 0.1.0" sh -c "claude-yolo --version | grep '0.1.0'" +check "claude-yolo version is equal to 1.6.4" sh -c "claude-yolo --version | grep '1.6.4'" reportResults From a48625042e65ae7c4a08b762e2a5b3ad2352120d Mon Sep 17 00:00:00 2001 From: Rob W <30517573+bertlebee@users.noreply.github.com> Date: Fri, 18 Apr 2025 04:20:54 +0000 Subject: [PATCH 3/4] remove claude yolo --- src/claude-yolo/README.md | 39 ----- src/claude-yolo/devcontainer-feature.json | 18 --- src/claude-yolo/install.sh | 21 --- src/claude-yolo/library_scripts.sh | 173 ---------------------- test/claude-yolo/scenarios.json | 20 --- test/claude-yolo/test.sh | 11 -- test/claude-yolo/test_debian.sh | 9 -- test/claude-yolo/test_specific_version.sh | 10 -- 8 files changed, 301 deletions(-) delete mode 100644 src/claude-yolo/README.md delete mode 100644 src/claude-yolo/devcontainer-feature.json delete mode 100755 src/claude-yolo/install.sh delete mode 100644 src/claude-yolo/library_scripts.sh delete mode 100644 test/claude-yolo/scenarios.json delete mode 100755 test/claude-yolo/test.sh delete mode 100755 test/claude-yolo/test_debian.sh delete mode 100755 test/claude-yolo/test_specific_version.sh diff --git a/src/claude-yolo/README.md b/src/claude-yolo/README.md deleted file mode 100644 index f88e0667d..000000000 --- a/src/claude-yolo/README.md +++ /dev/null @@ -1,39 +0,0 @@ -# Claude YOLO (via npm) - -Claude YOLO enables visual object detection capabilities with Claude in the command line. It works with the Claude Code CLI to provide AI-powered object detection. - -## Example Usage - -```json -"features": { - "ghcr.io/devcontainers-extra/features/claude-code:1": {}, - "ghcr.io/devcontainers-extra/features/claude-yolo:1": { - "version": "latest" - } -} -``` - -## Options - -| Options Id | Description | Type | Default Value | -|-----|-----|-----|-----| -| version | Select the version to install. | string | "latest" | - -## Requirements - -- This feature requires the Claude Code CLI to be installed first -- Node.js is required for installation - -## Customizations - -### VS Code Extensions - -- `anthropic.claude-vscode`: Claude for VS Code - The official extension for using Claude in VS Code - -## License - -MIT - -## References - -- [Claude Code documentation](https://docs.anthropic.com/en/docs/agents-and-tools/claude-code/overview) \ No newline at end of file diff --git a/src/claude-yolo/devcontainer-feature.json b/src/claude-yolo/devcontainer-feature.json deleted file mode 100644 index bb3b1f451..000000000 --- a/src/claude-yolo/devcontainer-feature.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "id": "claude-yolo", - "version": "1.0.0", - "name": "claude-yolo (via npm)", - "documentationURL": "http://github.com/devcontainers-extra/features/tree/main/src/claude-yolo", - "description": "A wrapper for the Claude CLI that ALWAYS enables --dangerously-skip-permissions mode AND bypasses Docker and internet permission checks so that you can run in danger mode anywhere, anytime. Use at your own risk.", - "options": { - "version": { - "default": "latest", - "description": "Select the version to install.", - "proposals": ["latest"], - "type": "string" - } - }, - "installsAfter": [ - "ghcr.io/devcontainers/features/node" - ] -} diff --git a/src/claude-yolo/install.sh b/src/claude-yolo/install.sh deleted file mode 100755 index 2f715c03c..000000000 --- a/src/claude-yolo/install.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env bash - -set -e - -source ./library_scripts.sh - -# nanolayer is a cli utility which keeps container layers as small as possible -# source code: https://github.com/devcontainers-extra/nanolayer -# `ensure_nanolayer` is a bash function that will find any existing nanolayer installations, -# and if missing - will download a temporary copy that automatically get deleted at the end -# of the script -ensure_nanolayer nanolayer_location "v0.5.6" - -# Install Claude YOLO globally via npm -if [ "${VERSION}" = "latest" ]; then - npm install -g "claude-yolo" -else - npm install -g "claude-yolo@${VERSION}" -fi - -echo 'Claude YOLO installed successfully!' diff --git a/src/claude-yolo/library_scripts.sh b/src/claude-yolo/library_scripts.sh deleted file mode 100644 index f6d0760d7..000000000 --- a/src/claude-yolo/library_scripts.sh +++ /dev/null @@ -1,173 +0,0 @@ -#!/usr/bin/env bash - -clean_download() { - # The purpose of this function is to download a file with minimal impact on container layer size - # this means if no valid downloader is found (curl or wget) then we install a downloader (currently wget) in a - # temporary manner, and making sure to - # 1. uninstall the downloader at the return of the function - # 2. revert back any changes to the package installer database/cache (for example apt-get lists) - # The above steps will minimize the leftovers being created while installing the downloader - # Supported distros: - # debian/ubuntu/alpine - - url=$1 - output_location=$2 - tempdir=$(mktemp -d) - downloader_installed="" - - function _apt_get_install() { - tempdir=$1 - - # copy current state of apt list - in order to revert back later (minimize contianer layer size) - cp -p -R /var/lib/apt/lists $tempdir - apt-get update -y - apt-get -y install --no-install-recommends wget ca-certificates - } - - function _apt_get_cleanup() { - tempdir=$1 - - echo "removing wget" - apt-get -y purge wget --auto-remove - - echo "revert back apt lists" - rm -rf /var/lib/apt/lists/* - rm -r /var/lib/apt/lists && mv $tempdir/lists /var/lib/apt/lists - } - - function _apk_install() { - tempdir=$1 - # copy current state of apk cache - in order to revert back later (minimize contianer layer size) - cp -p -R /var/cache/apk $tempdir - - apk add --no-cache wget - } - - function _apk_cleanup() { - tempdir=$1 - - echo "removing wget" - apk del wget - } - # try to use either wget or curl if one of them already installer - if type curl >/dev/null 2>&1; then - downloader=curl - elif type wget >/dev/null 2>&1; then - downloader=wget - else - downloader="" - fi - - # in case none of them is installed, install wget temporarly - if [ -z $downloader ]; then - if [ -x "/usr/bin/apt-get" ]; then - _apt_get_install $tempdir - elif [ -x "/sbin/apk" ]; then - _apk_install $tempdir - else - echo "distro not supported" - exit 1 - fi - downloader="wget" - downloader_installed="true" - fi - - if [ $downloader = "wget" ]; then - wget -q $url -O $output_location - else - curl -sfL $url -o $output_location - fi - - # NOTE: the cleanup procedure was not implemented using `trap X RETURN` only because - # alpine lack bash, and RETURN is not a valid signal under sh shell - if ! [ -z $downloader_installed ]; then - if [ -x "/usr/bin/apt-get" ]; then - _apt_get_cleanup $tempdir - elif [ -x "/sbin/apk" ]; then - _apk_cleanup $tempdir - else - echo "distro not supported" - exit 1 - fi - fi - -} - -ensure_nanolayer() { - # Ensure existance of the nanolayer cli program - local variable_name=$1 - - local required_version=$2 - # normalize version - if ! [[ $required_version == v* ]]; then - required_version=v$required_version - fi - - local nanolayer_location="" - - # If possible - try to use an already installed nanolayer - if [[ -z "${NANOLAYER_FORCE_CLI_INSTALLATION}" ]]; then - if [[ -z "${NANOLAYER_CLI_LOCATION}" ]]; then - if type nanolayer >/dev/null 2>&1; then - echo "Found a pre-existing nanolayer in PATH" - nanolayer_location=nanolayer - fi - elif [ -f "${NANOLAYER_CLI_LOCATION}" ] && [ -x "${NANOLAYER_CLI_LOCATION}" ]; then - nanolayer_location=${NANOLAYER_CLI_LOCATION} - echo "Found a pre-existing nanolayer which were given in env variable: $nanolayer_location" - fi - - # make sure its of the required version - if ! [[ -z "${nanolayer_location}" ]]; then - local current_version - current_version=$($nanolayer_location --version) - if ! [[ $current_version == v* ]]; then - current_version=v$current_version - fi - - if ! [ $current_version == $required_version ]; then - echo "skipping usage of pre-existing nanolayer. (required version $required_version does not match existing version $current_version)" - nanolayer_location="" - fi - fi - - fi - - # If not previuse installation found, download it temporarly and delete at the end of the script - if [[ -z "${nanolayer_location}" ]]; then - - if [ "$(uname -sm)" == "Linux x86_64" ] || [ "$(uname -sm)" == "Linux aarch64" ]; then - tmp_dir=$(mktemp -d -t nanolayer-XXXXXXXXXX) - - clean_up() { - ARG=$? - rm -rf $tmp_dir - exit $ARG - } - trap clean_up EXIT - - if [ -x "/sbin/apk" ]; then - clib_type=musl - else - clib_type=gnu - fi - - tar_filename=nanolayer-"$(uname -m)"-unknown-linux-$clib_type.tgz - - # clean download will minimize leftover in case a downloaderlike wget or curl need to be installed - clean_download https://github.com/devcontainers-extra/nanolayer/releases/download/$required_version/$tar_filename $tmp_dir/$tar_filename - - tar xfzv $tmp_dir/$tar_filename -C "$tmp_dir" - chmod a+x $tmp_dir/nanolayer - nanolayer_location=$tmp_dir/nanolayer - - else - echo "No binaries compiled for non-x86-linux architectures yet: $(uname -m)" - exit 1 - fi - fi - - # Expose outside the resolved location - declare -g ${variable_name}=$nanolayer_location - -} diff --git a/test/claude-yolo/scenarios.json b/test/claude-yolo/scenarios.json deleted file mode 100644 index e419efa1f..000000000 --- a/test/claude-yolo/scenarios.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "test_debian": { - "image": "mcr.microsoft.com/devcontainers/base:debian", - "features": { - "ghcr.io/devcontainers/features/node:1": {}, - "ghcr.io/devcontainers-extra/features/claude-code:1": {}, - "claude-yolo": {} - } - }, - "test_specific_version": { - "image": "mcr.microsoft.com/devcontainers/base:debian", - "features": { - "ghcr.io/devcontainers/features/node:1": {}, - "ghcr.io/devcontainers-extra/features/claude-code:1": {}, - "claude-yolo": { - "version": "1.6.4" - } - } - } -} \ No newline at end of file diff --git a/test/claude-yolo/test.sh b/test/claude-yolo/test.sh deleted file mode 100755 index db3200253..000000000 --- a/test/claude-yolo/test.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env bash - -set -e - -source dev-container-features-test-lib - -# Check both Claude Code and Claude YOLO are installed -check "Claude Code is installed" claude-code --version -check "Claude YOLO is installed" claude-yolo --version - -reportResults diff --git a/test/claude-yolo/test_debian.sh b/test/claude-yolo/test_debian.sh deleted file mode 100755 index 7a88356da..000000000 --- a/test/claude-yolo/test_debian.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bash - -set -e - -source dev-container-features-test-lib - -check "claude-yolo is installed" claude-yolo --version - -reportResults diff --git a/test/claude-yolo/test_specific_version.sh b/test/claude-yolo/test_specific_version.sh deleted file mode 100755 index 0d521a2ab..000000000 --- a/test/claude-yolo/test_specific_version.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash - -set -e - -source dev-container-features-test-lib - -# Check that Claude Code is installed and Claude YOLO has the specific version -check "claude-yolo version is equal to 1.6.4" sh -c "claude-yolo --version | grep '1.6.4'" - -reportResults From 25b5f581a8a21100160f1320aa75083429437b8a Mon Sep 17 00:00:00 2001 From: Rob W <30517573+bertlebee@users.noreply.github.com> Date: Fri, 18 Apr 2025 05:46:14 +0000 Subject: [PATCH 4/4] update readme --- src/claude-code/README.md | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/claude-code/README.md b/src/claude-code/README.md index 827c22334..aa7185b33 100644 --- a/src/claude-code/README.md +++ b/src/claude-code/README.md @@ -1,6 +1,6 @@ # Claude Code (via npm) -Claude Code is Anthropic's official CLI for Claude, enabling access to Claude's capabilities from the command line. +Claude Code is an agentic coding tool that lives in your terminal, understands your codebase, and helps you code faster by executing routine tasks, explaining complex code, and handling git workflows - all through natural language commands. ## Example Usage @@ -18,12 +18,6 @@ Claude Code is Anthropic's official CLI for Claude, enabling access to Claude's |-----|-----|-----|-----| | version | Select the version to install. | string | "latest" | -## Customizations - -### VS Code Extensions - -- `anthropic.claude-vscode`: Claude for VS Code - The official extension for using Claude in VS Code - ## License MIT