# Installation Scripts - Agent Guide **Scope:** Shell scripts for tool installation, update, uninstall, reconcile ## Overview 13+ Bash scripts for installing developer tools with multiple actions: - **install**: Fresh installation (default action) - **update**: Upgrade to latest version - **uninstall**: Remove installation - **reconcile**: Switch to preferred installation method (e.g., system → user) **Key scripts:** - `install_core.sh`: Core tools (fd, fzf, ripgrep, jq, yq, bat, delta, just) - `install_python.sh`: Python toolchain via uv - `install_node.sh`: Node.js via nvm - `install_rust.sh`: Rust via rustup - `install_go.sh`, `install_aws.sh`, `install_kubectl.sh`, etc. - `guide.sh`: Interactive upgrade guide - `test_smoke.sh`: Smoke test for audit output **Shared utilities:** `lib/` directory (colors, logging, common functions) ## Setup **Requirements:** - Bash 4.0+ - `curl` or `wget` for downloads - Internet access for fresh installs - Appropriate permissions (user for `~/.local/bin`, sudo for system) **Environment variables:** ```bash INSTALL_PREFIX=${INSTALL_PREFIX:-~/.local} # Default: user-level FORCE_INSTALL=1 # Skip confirmation prompts DEBUG=1 # Verbose output ``` **Permissions:** ```bash make scripts-perms # Ensure all scripts are executable ``` ## Build & Tests **Run individual script:** ```bash # Install action (default) ./scripts/install_python.sh # Update action ./scripts/install_python.sh update # Uninstall action ./scripts/install_python.sh uninstall # Reconcile action (switch installation method) ./scripts/install_node.sh reconcile ``` **Via Make:** ```bash make install-python # Install Python toolchain make update-python # Update Python toolchain make uninstall-python # Uninstall Python toolchain make reconcile-node # Switch Node.js to nvm-managed ``` **Smoke test:** ```bash ./scripts/test_smoke.sh # Verify audit output format ``` **Debug mode:** ```bash DEBUG=1 ./scripts/install_python.sh bash -x ./scripts/install_python.sh # Trace execution ``` ## Code Style **Shell standards:** - Bash 4.0+ features allowed - Shebang: `#!/usr/bin/env bash` or `#!/bin/bash` - Set strict mode: `set -euo pipefail` - `-e`: Exit on error - `-u`: Error on undefined variables - `-o pipefail`: Fail on pipe errors **Formatting:** - 4-space indentation (matches EditorConfig) - Function names: lowercase_with_underscores - Constants: UPPER_CASE - Local variables: lowercase **Structure:** ```bash #!/usr/bin/env bash set -euo pipefail # Source shared utilities SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "${SCRIPT_DIR}/lib/colors.sh" || true source "${SCRIPT_DIR}/lib/common.sh" || true # Main function per action install_tool() { echo_info "Installing ..." # Implementation } update_tool() { echo_info "Updating ..." # Implementation } uninstall_tool() { echo_info "Uninstalling ..." # Implementation } reconcile_tool() { echo_info "Reconciling ..." # Implementation } # Action dispatcher ACTION="${1:-install}" case "$ACTION" in install) install_tool ;; update) update_tool ;; uninstall) uninstall_tool ;; reconcile) reconcile_tool ;; *) echo "Usage: $0 {install|update|uninstall|reconcile}"; exit 1 ;; esac ``` **Error handling:** ```bash # Good: Check command exists before using if ! command -v curl >/dev/null 2>&1; then echo_error "curl not found. Install it first." exit 1 fi # Good: Check return codes if ! download_file "$URL" "$DEST"; then echo_error "Download failed" exit 1 fi # Good: Cleanup on error trap 'rm -rf "$TMPDIR"' EXIT ERR ``` **Confirmation prompts:** ```bash # Good: Skip prompt if FORCE_INSTALL=1 if [[ "${FORCE_INSTALL:-0}" != "1" ]]; then read -p "Install ? [y/N] " -n 1 -r echo [[ ! $REPLY =~ ^[Yy]$ ]] && exit 0 fi ``` ## Security **Download verification:** ```bash # Always use HTTPS URL="https://github.com/owner/repo/releases/download/..." # Verify checksums when available EXPECTED_SHA256="abc123..." ACTUAL_SHA256=$(sha256sum "$FILE" | awk '{print $1}') if [[ "$ACTUAL_SHA256" != "$EXPECTED_SHA256" ]]; then echo_error "Checksum mismatch!" exit 1 fi ``` **Path safety:** ```bash # Good: Quote variables, use absolute paths INSTALL_DIR="${HOME}/.local/bin" mkdir -p "$INSTALL_DIR" mv "$TMPFILE" "$INSTALL_DIR/tool" # Bad: Unquoted, relative paths mkdir -p $INSTALL_DIR mv tool bin/ ``` **Sudo usage:** ```bash # Good: Prompt for sudo only when needed if [[ "$INSTALL_PREFIX" == "/usr/local" ]]; then if ! sudo -v; then echo_error "Sudo required for system installation" exit 1 fi sudo mv "$FILE" "$INSTALL_PREFIX/bin/" else # User-level, no sudo mv "$FILE" "$INSTALL_PREFIX/bin/" fi ``` **No secrets in scripts:** - No API keys, tokens, passwords in scripts - Use environment variables: `${GITHUB_TOKEN:-}` - Document required env vars in script comments ## PR/Commit Checklist **Before commit:** - [ ] Run `shellcheck