diff --git a/Dockerfile.test-install b/Dockerfile.test-install new file mode 100644 index 0000000..eb9f7b4 --- /dev/null +++ b/Dockerfile.test-install @@ -0,0 +1,85 @@ +# CmdForge - Test Installation Container +# +# This container simulates a fresh computer for testing the installation process. +# CmdForge source is available but NOT installed - you run the installer yourself. +# +# Build: +# docker build -f Dockerfile.test-install -t cmdforge-test-install . +# +# Run: +# docker run -it --rm cmdforge-test-install +# +# Inside the container: +# ./install.sh # Run the installer +# cmdforge ui # Launch the UI +# cmdforge providers install # Set up an AI provider + +FROM ubuntu:22.04 + +LABEL maintainer="rob" +LABEL description="CmdForge installation test environment" + +# Prevent interactive prompts during package installation +ENV DEBIAN_FRONTEND=noninteractive + +# Install system dependencies (what a typical dev machine would have) +RUN apt-get update && apt-get install -y --no-install-recommends \ + # Python + python3 \ + python3-pip \ + python3-venv \ + # Common tools a developer would have + git \ + curl \ + vim \ + less \ + # For providers that need browser auth + firefox \ + xdg-utils \ + # X11 for display forwarding + libx11-6 \ + libxext6 \ + libxrender1 \ + && rm -rf /var/lib/apt/lists/* + +# Create a non-root user (simulates typical user setup) +RUN useradd -m -s /bin/bash testuser +USER testuser +WORKDIR /home/testuser + +# Copy CmdForge source (owned by testuser) +COPY --chown=testuser:testuser . /home/testuser/CmdForge + +# Set up PATH for local bin (where cmdforge wrappers go) +RUN mkdir -p /home/testuser/.local/bin +ENV PATH="/home/testuser/.local/bin:${PATH}" + +# Make install script executable +RUN chmod +x /home/testuser/CmdForge/install.sh + +# Welcome message +RUN echo '\n\ +echo ""\n\ +echo "================================================================="\n\ +echo " CmdForge Installation Test Environment"\n\ +echo "================================================================="\n\ +echo ""\n\ +echo " CmdForge source is in: ~/CmdForge"\n\ +echo " To install, run:"\n\ +echo ""\n\ +echo " cd ~/CmdForge"\n\ +echo " ./install.sh"\n\ +echo ""\n\ +echo " After installation:"\n\ +echo " cmdforge ui # Launch the UI"\n\ +echo " cmdforge list # List tools"\n\ +echo " cmdforge providers install # Set up AI provider"\n\ +echo ""\n\ +echo "================================================================="\n\ +echo ""\n\ +' >> /home/testuser/.bashrc + +WORKDIR /home/testuser/CmdForge + +# Start in interactive bash +CMD ["/bin/bash"] diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..fc661cd --- /dev/null +++ b/install.sh @@ -0,0 +1,413 @@ +#!/bin/bash +# +# CmdForge Installer +# +# Usage: +# ./install.sh # Interactive installation +# ./install.sh --yes # Accept all defaults (non-interactive) +# ./install.sh --no-venv # Install to system Python (not recommended) +# ./install.sh --no-examples # Skip example tools +# + +set -e + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +CYAN='\033[0;36m' +NC='\033[0m' # No Color +BOLD='\033[1m' + +# Configuration +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +VENV_DIR="$HOME/.cmdforge-venv" +LOCAL_BIN="$HOME/.local/bin" +MIN_PYTHON_VERSION="3.10" + +# Parse arguments +USE_VENV=true +INSTALL_EXAMPLES=true +AUTO_YES=false + +while [[ $# -gt 0 ]]; do + case $1 in + --yes|-y) + AUTO_YES=true + shift + ;; + --no-venv) + USE_VENV=false + shift + ;; + --no-examples) + INSTALL_EXAMPLES=false + shift + ;; + --help|-h) + echo "CmdForge Installer" + echo "" + echo "Usage: ./install.sh [OPTIONS]" + echo "" + echo "Options:" + echo " --yes, -y Accept all defaults (non-interactive)" + echo " --no-venv Install to system Python (not recommended)" + echo " --no-examples Skip installing example tools" + echo " --help, -h Show this help message" + exit 0 + ;; + *) + echo "Unknown option: $1" + echo "Run './install.sh --help' for usage" + exit 1 + ;; + esac +done + +# Helper functions +print_header() { + echo "" + echo -e "${CYAN}${BOLD}$1${NC}" + echo -e "${CYAN}$(printf '=%.0s' {1..60})${NC}" +} + +print_step() { + echo -e "${BLUE}[*]${NC} $1" +} + +print_success() { + echo -e "${GREEN}[+]${NC} $1" +} + +print_warning() { + echo -e "${YELLOW}[!]${NC} $1" +} + +print_error() { + echo -e "${RED}[X]${NC} $1" +} + +ask_yes_no() { + if $AUTO_YES; then + return 0 + fi + local prompt="$1" + local default="${2:-y}" + + if [[ "$default" == "y" ]]; then + prompt="$prompt [Y/n] " + else + prompt="$prompt [y/N] " + fi + + read -r -p "$prompt" response + response=${response:-$default} + + [[ "$response" =~ ^[Yy]$ ]] +} + +version_gte() { + # Check if version $1 >= version $2 + printf '%s\n%s\n' "$2" "$1" | sort -V -C +} + +# Start installation +clear 2>/dev/null || true + +echo "" +echo -e "${CYAN}${BOLD}" +echo " ____ _ _____ " +echo " / ___|_ __ ___ __| | ___|__ _ __ __ _ ___ " +echo " | | | '_ \` _ \\ / _\` | |_ / _ \\| '__/ _\` |/ _ \\" +echo " | |___| | | | | | (_| | _| (_) | | | (_| | __/" +echo " \\____|_| |_| |_|\\__,_|_| \\___/|_| \\__, |\\___|" +echo " |___/ " +echo -e "${NC}" +echo " AI-powered CLI command builder" +echo "" + +# ============================================================================== +# Step 1: Check prerequisites +# ============================================================================== +print_header "Step 1: Checking Prerequisites" + +# Check Python +print_step "Checking Python version..." + +PYTHON_CMD="" +for cmd in python3 python; do + if command -v "$cmd" &> /dev/null; then + version=$("$cmd" --version 2>&1 | awk '{print $2}') + if version_gte "$version" "$MIN_PYTHON_VERSION"; then + PYTHON_CMD="$cmd" + break + fi + fi +done + +if [[ -z "$PYTHON_CMD" ]]; then + print_error "Python $MIN_PYTHON_VERSION or higher is required" + echo "" + echo "Please install Python first:" + echo " Ubuntu/Debian: sudo apt install python3 python3-pip python3-venv" + echo " macOS: brew install python3" + echo " Windows: https://www.python.org/downloads/" + exit 1 +fi + +PYTHON_VERSION=$("$PYTHON_CMD" --version 2>&1 | awk '{print $2}') +print_success "Python $PYTHON_VERSION found ($PYTHON_CMD)" + +# Check pip +print_step "Checking pip..." +if ! "$PYTHON_CMD" -m pip --version &> /dev/null; then + print_error "pip is not installed" + echo "" + echo "Please install pip:" + echo " Ubuntu/Debian: sudo apt install python3-pip" + echo " macOS: python3 -m ensurepip" + exit 1 +fi +print_success "pip is available" + +# Check venv module (if using venv) +if $USE_VENV; then + print_step "Checking venv module..." + if ! "$PYTHON_CMD" -m venv --help &> /dev/null; then + print_warning "venv module not available" + echo "" + if ask_yes_no "Install python3-venv? (recommended)" "y"; then + if command -v apt-get &> /dev/null; then + sudo apt-get update && sudo apt-get install -y python3-venv + else + print_error "Cannot auto-install venv. Please install manually." + echo " Ubuntu/Debian: sudo apt install python3-venv" + exit 1 + fi + else + print_warning "Continuing without venv (installing to system Python)" + USE_VENV=false + fi + else + print_success "venv module is available" + fi +fi + +# Check we're in the CmdForge directory +print_step "Checking CmdForge source..." +if [[ ! -f "$SCRIPT_DIR/pyproject.toml" ]]; then + print_error "Cannot find CmdForge source files" + echo "Please run this script from the CmdForge directory" + exit 1 +fi +print_success "CmdForge source found at $SCRIPT_DIR" + +# ============================================================================== +# Step 2: Installation options +# ============================================================================== +print_header "Step 2: Installation Options" + +if ! $AUTO_YES; then + echo "" + echo "Installation options:" + echo "" + + if $USE_VENV; then + echo -e " ${GREEN}1.${NC} Use virtual environment at $VENV_DIR ${GREEN}(recommended)${NC}" + else + echo -e " ${YELLOW}1.${NC} Install to system Python ${YELLOW}(--no-venv specified)${NC}" + fi + + if $INSTALL_EXAMPLES; then + echo -e " ${GREEN}2.${NC} Install 28 example tools" + else + echo -e " ${YELLOW}2.${NC} Skip example tools ${YELLOW}(--no-examples specified)${NC}" + fi + + echo "" + + if ! ask_yes_no "Proceed with installation?" "y"; then + echo "Installation cancelled." + exit 0 + fi +fi + +# ============================================================================== +# Step 3: Create virtual environment (if using) +# ============================================================================== +if $USE_VENV; then + print_header "Step 3: Setting Up Virtual Environment" + + if [[ -d "$VENV_DIR" ]]; then + print_warning "Virtual environment already exists at $VENV_DIR" + if ask_yes_no "Remove and recreate?" "n"; then + rm -rf "$VENV_DIR" + fi + fi + + if [[ ! -d "$VENV_DIR" ]]; then + print_step "Creating virtual environment..." + "$PYTHON_CMD" -m venv "$VENV_DIR" + print_success "Virtual environment created at $VENV_DIR" + fi + + print_step "Activating virtual environment..." + source "$VENV_DIR/bin/activate" + print_success "Virtual environment activated" + + # Upgrade pip in venv + print_step "Upgrading pip..." + pip install --upgrade pip --quiet + print_success "pip upgraded" +else + print_header "Step 3: Using System Python" + print_warning "Installing to system Python (use --no-venv was specified)" +fi + +# ============================================================================== +# Step 4: Install CmdForge +# ============================================================================== +print_header "Step 4: Installing CmdForge" + +print_step "Installing CmdForge and dependencies..." +cd "$SCRIPT_DIR" + +# Install with all optional dependencies +pip install -e ".[all]" --quiet + +print_success "CmdForge installed successfully" + +# Verify installation +print_step "Verifying installation..." +if command -v cmdforge &> /dev/null; then + VERSION=$(cmdforge --version 2>&1 | head -1) + print_success "cmdforge command available: $VERSION" +else + print_error "cmdforge command not found in PATH" + exit 1 +fi + +# ============================================================================== +# Step 5: Set up PATH +# ============================================================================== +print_header "Step 5: Setting Up PATH" + +# Create local bin directory +mkdir -p "$LOCAL_BIN" + +# Determine shell config file +SHELL_CONFIG="" +if [[ -f "$HOME/.bashrc" ]]; then + SHELL_CONFIG="$HOME/.bashrc" +elif [[ -f "$HOME/.zshrc" ]]; then + SHELL_CONFIG="$HOME/.zshrc" +elif [[ -f "$HOME/.bash_profile" ]]; then + SHELL_CONFIG="$HOME/.bash_profile" +fi + +# Check if PATH already includes local bin +PATH_LINE='export PATH="$HOME/.local/bin:$PATH"' +PATH_CONFIGURED=false + +if [[ -n "$SHELL_CONFIG" ]]; then + if grep -q '.local/bin' "$SHELL_CONFIG" 2>/dev/null; then + print_success "PATH already configured in $SHELL_CONFIG" + PATH_CONFIGURED=true + fi +fi + +# Add venv activation if using venv +if $USE_VENV; then + VENV_LINE="source $VENV_DIR/bin/activate" + if [[ -n "$SHELL_CONFIG" ]] && ! grep -q "cmdforge-venv" "$SHELL_CONFIG" 2>/dev/null; then + print_step "Adding virtual environment activation to $SHELL_CONFIG..." + echo "" >> "$SHELL_CONFIG" + echo "# CmdForge virtual environment" >> "$SHELL_CONFIG" + echo "$VENV_LINE" >> "$SHELL_CONFIG" + print_success "Added venv activation to $SHELL_CONFIG" + fi +fi + +# Add PATH if not already there +if ! $PATH_CONFIGURED && [[ -n "$SHELL_CONFIG" ]]; then + print_step "Adding ~/.local/bin to PATH in $SHELL_CONFIG..." + echo "" >> "$SHELL_CONFIG" + echo "# CmdForge tool wrappers" >> "$SHELL_CONFIG" + echo "$PATH_LINE" >> "$SHELL_CONFIG" + print_success "Added PATH configuration to $SHELL_CONFIG" +fi + +# Export for current session +export PATH="$LOCAL_BIN:$PATH" + +# ============================================================================== +# Step 6: Create wrapper scripts +# ============================================================================== +print_header "Step 6: Creating Tool Wrappers" + +print_step "Running cmdforge refresh..." +cmdforge refresh +print_success "Wrapper scripts created in $LOCAL_BIN" + +# ============================================================================== +# Step 7: Install example tools (optional) +# ============================================================================== +if $INSTALL_EXAMPLES; then + print_header "Step 7: Installing Example Tools" + + print_step "Installing 28 example tools..." + "$PYTHON_CMD" "$SCRIPT_DIR/examples/install.py" + + print_step "Refreshing wrappers for new tools..." + cmdforge refresh + + print_success "Example tools installed" +else + print_header "Step 7: Skipping Example Tools" + print_warning "Example tools not installed (use 'python examples/install.py' later)" +fi + +# ============================================================================== +# Complete! +# ============================================================================== +print_header "Installation Complete!" + +echo "" +echo -e "${GREEN}${BOLD}CmdForge has been installed successfully!${NC}" +echo "" + +# Show installed tools count +TOOL_COUNT=$(cmdforge list 2>/dev/null | grep -c "^" || echo "0") +echo -e " ${CYAN}Tools installed:${NC} $TOOL_COUNT" +echo -e " ${CYAN}Config location:${NC} ~/.cmdforge/" +echo -e " ${CYAN}Tool wrappers:${NC} ~/.local/bin/" +if $USE_VENV; then + echo -e " ${CYAN}Virtual env:${NC} $VENV_DIR" +fi + +echo "" +echo -e "${BOLD}Next Steps:${NC}" +echo "" +echo " 1. Reload your shell (or run: source $SHELL_CONFIG)" +echo "" +echo " 2. Set up an AI provider:" +echo -e " ${CYAN}cmdforge providers install${NC}" +echo "" +echo " 3. Launch the UI:" +echo -e " ${CYAN}cmdforge ui${NC}" +echo "" +echo " 4. Or try a tool directly:" +echo -e " ${CYAN}echo 'Hello world' | eli5${NC}" +echo "" + +if $USE_VENV; then + echo -e "${YELLOW}Note:${NC} The virtual environment will be activated automatically" + echo " in new shell sessions. For this session, run:" + echo -e " ${CYAN}source $VENV_DIR/bin/activate${NC}" + echo "" +fi + +echo -e "${CYAN}Documentation:${NC} https://pages.brrd.tech/rob/cmdforge/" +echo -e "${CYAN}Source code:${NC} https://gitea.brrd.tech/rob/CmdForge" +echo ""