diff --git a/src/claude-code/NOTES.md b/src/claude-code/NOTES.md index 8694121..ee84484 100644 --- a/src/claude-code/NOTES.md +++ b/src/claude-code/NOTES.md @@ -13,6 +13,14 @@ By default, the `latest` release channel is installed. You can also specify: The channel chosen at install time becomes the default for auto-updates. +## YOLO Alias + +When `yoloAlias` is set to `true`, a `yolo` shell alias is created that expands to `claude --allow-dangerously-skip-permissions`. The alias is configured for bash, zsh, and fish. + +> **Warning:** `--allow-dangerously-skip-permissions` disables Claude Code's normal permission checks and confirmation prompts for potentially sensitive actions. This meaningfully reduces safety and may allow unintended or unsafe changes, so only enable `yoloAlias` if you understand and accept the security implications. +> +> If a `yolo` alias already exists in `.bashrc`/`.zshrc`, or a `yolo.fish` function file already exists, the installer will skip adding it to avoid overwriting your setup. + ## Auto-Updates The native binary automatically updates in the background. Update checks are performed on startup and periodically while running. To disable auto-updates, set the `DISABLE_AUTOUPDATER=1` environment variable. diff --git a/src/claude-code/devcontainer-feature.json b/src/claude-code/devcontainer-feature.json index 9003213..486629b 100644 --- a/src/claude-code/devcontainer-feature.json +++ b/src/claude-code/devcontainer-feature.json @@ -1,6 +1,6 @@ { "id": "claude-code", - "version": "2.1.0", + "version": "2.2.0", "name": "Claude Code", "description": "Installs Claude Code CLI for AI-powered development assistance", "options": { @@ -8,6 +8,11 @@ "type": "string", "default": "latest", "description": "Version to install. Use 'latest', 'stable', or a specific semver (e.g. '1.0.58')." + }, + "yoloAlias": { + "type": "boolean", + "default": false, + "description": "Create a 'yolo' shell alias for 'claude --allow-dangerously-skip-permissions' in bash, zsh, and fish." } }, "customizations": { diff --git a/src/claude-code/install.sh b/src/claude-code/install.sh index a7e371b..c4d1075 100755 --- a/src/claude-code/install.sh +++ b/src/claude-code/install.sh @@ -53,4 +53,61 @@ if [ -f "$INSTALL_HOME/.local/bin/claude" ] && [ ! -f /usr/local/bin/claude ]; t echo "Symlinked claude to /usr/local/bin/claude" fi +# Set up yolo alias if requested +if [ "${YOLOALIAS:-false}" = "true" ]; then + echo "Setting up 'yolo' alias..." + ALIAS_CMD='alias yolo="claude --allow-dangerously-skip-permissions"' + TARGET_HOME="${INSTALL_HOME}" + + add_shell_alias_if_missing() { + local rc_file="$1" + local alias_name="$2" + local alias_cmd="$3" + + if [ -f "$rc_file" ] && grep -Eq "^[[:space:]]*alias[[:space:]]+${alias_name}=" "$rc_file"; then + echo "Skipping $rc_file: alias '$alias_name' already exists." + return 0 + fi + + touch "$rc_file" + # Ensure the file ends with a newline before appending + if [ -s "$rc_file" ] && [ "$(tail -c 1 "$rc_file" | wc -l)" -eq 0 ]; then + printf '\n' >> "$rc_file" + fi + printf '%s\n' "$alias_cmd" >> "$rc_file" + } + + # bash + add_shell_alias_if_missing "$TARGET_HOME/.bashrc" "yolo" "$ALIAS_CMD" + + # zsh + add_shell_alias_if_missing "$TARGET_HOME/.zshrc" "yolo" "$ALIAS_CMD" + + # fish — create a function file (idiomatic for fish) + FISH_FUNC_DIR="$TARGET_HOME/.config/fish/functions" + FISH_FUNC_FILE="$FISH_FUNC_DIR/yolo.fish" + FISH_CREATED=false + if [ -f "$FISH_FUNC_FILE" ]; then + echo "Skipping $FISH_FUNC_FILE: function already exists." + else + mkdir -p "$FISH_FUNC_DIR" + cat > "$FISH_FUNC_FILE" << 'FISHEOF' +function yolo --description "claude --allow-dangerously-skip-permissions" + claude --allow-dangerously-skip-permissions $argv +end +FISHEOF + FISH_CREATED=true + fi + + # Fix ownership if installing for non-root user + if [ -n "$_REMOTE_USER" ] && [ "$_REMOTE_USER" != "root" ]; then + chown "$_REMOTE_USER" "$TARGET_HOME/.bashrc" "$TARGET_HOME/.zshrc" + if [ "$FISH_CREATED" = true ]; then + chown "$_REMOTE_USER" "$TARGET_HOME/.config" "$TARGET_HOME/.config/fish" "$FISH_FUNC_DIR" "$FISH_FUNC_FILE" + fi + fi + + echo "yolo alias configured for bash, zsh, and fish." +fi + echo "Claude Code installed successfully!" diff --git a/test/claude-code/claude_code_yolo_alias.sh b/test/claude-code/claude_code_yolo_alias.sh new file mode 100755 index 0000000..2030b5d --- /dev/null +++ b/test/claude-code/claude_code_yolo_alias.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +# This test file will be executed against the 'claude_code_yolo_alias' scenario +# to verify that the yolo alias is properly configured. + +set -e + +# Import test library bundled with the devcontainer CLI +source dev-container-features-test-lib + +# Feature-specific tests +check "claude command available" which claude +check "yolo alias in bashrc" bash -c "grep -Fq 'claude --allow-dangerously-skip-permissions' ~/.bashrc" +check "yolo alias in zshrc" bash -c "grep -Fq 'claude --allow-dangerously-skip-permissions' ~/.zshrc" +check "fish yolo function body" bash -c "test -f ~/.config/fish/functions/yolo.fish && grep -Fq 'claude --allow-dangerously-skip-permissions' ~/.config/fish/functions/yolo.fish" +check "yolo resolves in bash" bash -ic "type yolo" + +# Report results +reportResults diff --git a/test/claude-code/claude_code_yolo_alias_with_custom_user.sh b/test/claude-code/claude_code_yolo_alias_with_custom_user.sh new file mode 100755 index 0000000..1a583b6 --- /dev/null +++ b/test/claude-code/claude_code_yolo_alias_with_custom_user.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +# This test file will be executed against the 'claude_code_yolo_alias_with_custom_user' scenario +# to verify that the yolo alias is properly configured for a non-root remoteUser. + +set -e + +# Import test library bundled with the devcontainer CLI +source dev-container-features-test-lib + +# Feature-specific tests +check "claude command available" which claude +check "yolo alias in bashrc" bash -c "grep -Fq 'claude --allow-dangerously-skip-permissions' ~/.bashrc" +check "yolo alias in zshrc" bash -c "grep -Fq 'claude --allow-dangerously-skip-permissions' ~/.zshrc" +check "fish yolo function body" bash -c "test -f ~/.config/fish/functions/yolo.fish && grep -Fq 'claude --allow-dangerously-skip-permissions' ~/.config/fish/functions/yolo.fish" +check "bashrc owned by current user" bash -c "test \"$(stat -c '%U' ~/.bashrc)\" = \"$(whoami)\"" +check "zshrc owned by current user" bash -c "test \"$(stat -c '%U' ~/.zshrc)\" = \"$(whoami)\"" +check "fish functions dir owned by current user" bash -c "test \"$(stat -c '%U' ~/.config/fish/functions)\" = \"$(whoami)\"" +check "fish function owned by current user" bash -c "test \"$(stat -c '%U' ~/.config/fish/functions/yolo.fish)\" = \"$(whoami)\"" +check "yolo resolves in bash" bash -ic "type yolo" + +# Report results +reportResults diff --git a/test/claude-code/scenarios.json b/test/claude-code/scenarios.json index 7c4a444..41ea1b0 100644 --- a/test/claude-code/scenarios.json +++ b/test/claude-code/scenarios.json @@ -19,5 +19,22 @@ "features": { "claude-code": {} } + }, + "claude_code_yolo_alias": { + "image": "mcr.microsoft.com/devcontainers/base:ubuntu", + "features": { + "claude-code": { + "yoloAlias": true + } + } + }, + "claude_code_yolo_alias_with_custom_user": { + "image": "mcr.microsoft.com/devcontainers/base:ubuntu", + "remoteUser": "vscode", + "features": { + "claude-code": { + "yoloAlias": true + } + } } }