#!/bin/bash # NomadArch Installer for Linux # Version: 0.6.0 - Robust Edition # Exit on error, but handle gracefully set -u # Colors RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' CYAN='\033[0;36m' NC='\033[0m' BOLD='\033[1m' # Script directory SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" TARGET_DIR="$SCRIPT_DIR" BIN_DIR="$TARGET_DIR/bin" LOG_FILE="$TARGET_DIR/install.log" ERRORS=0 WARNINGS=0 BINARY_FREE_MODE=1 # Logging function log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE" } print_header() { echo "" echo -e "${CYAN}╔═══════════════════════════════════════════════════════════════╗${NC}" echo -e "${CYAN}║${NC} ${BOLD}NomadArch Installer for Linux${NC} ${CYAN}║${NC}" echo -e "${CYAN}║${NC} Version: 0.6.0 - Robust Edition ${CYAN}║${NC}" echo -e "${CYAN}╚═══════════════════════════════════════════════════════════════╝${NC}" echo "" } print_header log "========== Installer started ==========" # ═══════════════════════════════════════════════════════════════ # STEP 1: OS and Architecture Detection # ═══════════════════════════════════════════════════════════════ echo "[STEP 1/8] Detecting System..." OS_TYPE=$(uname -s) ARCH_TYPE=$(uname -m) log "OS: $OS_TYPE, Arch: $ARCH_TYPE" if [[ "$OS_TYPE" != "Linux" ]]; then echo -e "${RED}[ERROR]${NC} This installer is for Linux. Current OS: $OS_TYPE" echo " Use Install-Mac.sh for macOS or Install-Windows.bat for Windows." log "ERROR: Not Linux ($OS_TYPE)" exit 1 fi case "$ARCH_TYPE" in x86_64) ARCH="x64" ;; aarch64) ARCH="arm64" ;; armv7l) ARCH="arm" ;; *) echo -e "${YELLOW}[WARN]${NC} Unusual architecture: $ARCH_TYPE (proceeding anyway)" ARCH="$ARCH_TYPE" ((WARNINGS++)) || true ;; esac echo -e "${GREEN}[OK]${NC} OS: Linux" echo -e "${GREEN}[OK]${NC} Architecture: $ARCH_TYPE ($ARCH)" # Detect distribution if [[ -f /etc/os-release ]]; then # shellcheck disable=SC1091 . /etc/os-release DISTRO="${ID:-unknown}" DISTRO_NAME="${PRETTY_NAME:-$DISTRO}" echo -e "${GREEN}[INFO]${NC} Distribution: $DISTRO_NAME" else DISTRO="unknown" DISTRO_NAME="Unknown Linux" fi log "Distribution: $DISTRO_NAME" # ═══════════════════════════════════════════════════════════════ # STEP 2: Check Write Permissions # ═══════════════════════════════════════════════════════════════ echo "" echo "[STEP 2/8] Checking Write Permissions..." mkdir -p "$BIN_DIR" 2>/dev/null || true if ! touch "$SCRIPT_DIR/.install-write-test" 2>/dev/null; then echo -e "${YELLOW}[WARN]${NC} No write access to $SCRIPT_DIR" TARGET_DIR="$HOME/.nomadarch" BIN_DIR="$TARGET_DIR/bin" LOG_FILE="$TARGET_DIR/install.log" mkdir -p "$BIN_DIR" if ! touch "$TARGET_DIR/.install-write-test" 2>/dev/null; then echo -e "${RED}[ERROR]${NC} Cannot write to $TARGET_DIR" log "ERROR: Write permission denied" exit 1 fi rm -f "$TARGET_DIR/.install-write-test" echo -e "${GREEN}[OK]${NC} Using fallback: $TARGET_DIR" else rm -f "$SCRIPT_DIR/.install-write-test" echo -e "${GREEN}[OK]${NC} Write access verified" fi log "Install target: $TARGET_DIR" # ═══════════════════════════════════════════════════════════════ # STEP 3: Detect Package Manager and sudo # ═══════════════════════════════════════════════════════════════ echo "" echo "[STEP 3/8] Detecting Package Manager..." SUDO="" if [[ $EUID -ne 0 ]]; then if command -v sudo >/dev/null 2>&1; then SUDO="sudo" echo -e "${GREEN}[OK]${NC} sudo available (may prompt for password)" else echo -e "${YELLOW}[WARN]${NC} Not root and sudo not found. Package installation may fail." ((WARNINGS++)) || true fi else echo -e "${GREEN}[OK]${NC} Running as root" fi # Detect package manager PACKAGE_MANAGER="" if command -v apt-get >/dev/null 2>&1; then PACKAGE_MANAGER="apt" echo -e "${GREEN}[OK]${NC} Package manager: apt (Debian/Ubuntu)" elif command -v dnf >/dev/null 2>&1; then PACKAGE_MANAGER="dnf" echo -e "${GREEN}[OK]${NC} Package manager: dnf (Fedora/RHEL)" elif command -v yum >/dev/null 2>&1; then PACKAGE_MANAGER="yum" echo -e "${GREEN}[OK]${NC} Package manager: yum (CentOS/RHEL)" elif command -v pacman >/dev/null 2>&1; then PACKAGE_MANAGER="pacman" echo -e "${GREEN}[OK]${NC} Package manager: pacman (Arch)" elif command -v zypper >/dev/null 2>&1; then PACKAGE_MANAGER="zypper" echo -e "${GREEN}[OK]${NC} Package manager: zypper (openSUSE)" elif command -v apk >/dev/null 2>&1; then PACKAGE_MANAGER="apk" echo -e "${GREEN}[OK]${NC} Package manager: apk (Alpine)" else echo -e "${YELLOW}[WARN]${NC} No recognized package manager found" echo -e "${YELLOW}[INFO]${NC} You may need to install dependencies manually" ((WARNINGS++)) || true fi # Package installation helper install_packages() { local packages=("$@") if [[ -z "$PACKAGE_MANAGER" ]]; then echo -e "${YELLOW}[WARN]${NC} Cannot install packages: no package manager" return 1 fi echo -e "${BLUE}[INFO]${NC} Installing: ${packages[*]}" case "$PACKAGE_MANAGER" in apt) $SUDO apt-get update -y >/dev/null 2>&1 || true $SUDO apt-get install -y "${packages[@]}" ;; dnf) $SUDO dnf install -y "${packages[@]}" ;; yum) $SUDO yum install -y "${packages[@]}" ;; pacman) $SUDO pacman -Sy --noconfirm "${packages[@]}" ;; zypper) $SUDO zypper -n install "${packages[@]}" ;; apk) $SUDO apk add --no-cache "${packages[@]}" ;; esac } # ═══════════════════════════════════════════════════════════════ # STEP 4: Install Node.js # ═══════════════════════════════════════════════════════════════ echo "" echo "[STEP 4/8] Checking Node.js..." NODE_OK=0 NPM_OK=0 if command -v node >/dev/null 2>&1; then NODE_VERSION=$(node --version 2>/dev/null || echo "unknown") if [[ "$NODE_VERSION" != "unknown" ]]; then NODE_MAJOR=$(echo "$NODE_VERSION" | sed 's/v//' | cut -d'.' -f1) echo -e "${GREEN}[OK]${NC} Node.js: $NODE_VERSION" NODE_OK=1 if [[ $NODE_MAJOR -lt 18 ]]; then echo -e "${YELLOW}[WARN]${NC} Node.js 18+ recommended (current: $NODE_VERSION)" ((WARNINGS++)) || true fi fi fi if [[ $NODE_OK -eq 0 ]]; then echo -e "${BLUE}[INFO]${NC} Node.js not found. Attempting installation..." log "Node.js not found, installing" INSTALL_SUCCESS=0 # Try package manager first if [[ -n "$PACKAGE_MANAGER" ]]; then case "$PACKAGE_MANAGER" in apt) # Try NodeSource for newer versions if curl -fsSL https://deb.nodesource.com/setup_20.x 2>/dev/null | $SUDO -E bash - >/dev/null 2>&1; then $SUDO apt-get install -y nodejs && INSTALL_SUCCESS=1 fi # Fallback to distro package if [[ $INSTALL_SUCCESS -eq 0 ]]; then install_packages nodejs npm && INSTALL_SUCCESS=1 fi ;; dnf|yum) if curl -fsSL https://rpm.nodesource.com/setup_20.x 2>/dev/null | $SUDO bash - >/dev/null 2>&1; then $SUDO "$PACKAGE_MANAGER" install -y nodejs && INSTALL_SUCCESS=1 fi if [[ $INSTALL_SUCCESS -eq 0 ]]; then install_packages nodejs npm && INSTALL_SUCCESS=1 fi ;; pacman) install_packages nodejs npm && INSTALL_SUCCESS=1 ;; zypper) install_packages nodejs18 npm18 && INSTALL_SUCCESS=1 if [[ $INSTALL_SUCCESS -eq 0 ]]; then install_packages nodejs npm && INSTALL_SUCCESS=1 fi ;; apk) install_packages nodejs npm && INSTALL_SUCCESS=1 ;; esac fi # Try nvm as fallback if [[ $INSTALL_SUCCESS -eq 0 ]] && command -v curl >/dev/null 2>&1; then echo -e "${BLUE}[INFO]${NC} Trying nvm installation..." export NVM_DIR="$HOME/.nvm" if curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh 2>/dev/null | bash >/dev/null 2>&1; then [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" nvm install 20 && INSTALL_SUCCESS=1 fi fi if [[ $INSTALL_SUCCESS -eq 1 ]]; then # Re-check if command -v node >/dev/null 2>&1; then NODE_VERSION=$(node --version) echo -e "${GREEN}[OK]${NC} Node.js installed: $NODE_VERSION" NODE_OK=1 fi fi if [[ $NODE_OK -eq 0 ]]; then echo -e "${RED}[ERROR]${NC} Could not install Node.js automatically" echo "" echo "Please install Node.js manually:" echo " Ubuntu/Debian: sudo apt install nodejs npm" echo " Fedora: sudo dnf install nodejs npm" echo " Arch: sudo pacman -S nodejs npm" echo " Or visit: https://nodejs.org/" echo "" log "ERROR: Node.js installation failed" ERRORS=$((ERRORS+1)) # Don't exit - let user see summary fi fi # Check npm if command -v npm >/dev/null 2>&1; then NPM_VERSION=$(npm --version 2>/dev/null || echo "unknown") if [[ "$NPM_VERSION" != "unknown" ]]; then echo -e "${GREEN}[OK]${NC} npm: $NPM_VERSION" NPM_OK=1 fi fi if [[ $NPM_OK -eq 0 && $NODE_OK -eq 1 ]]; then echo -e "${YELLOW}[WARN]${NC} npm not found, trying to install..." install_packages npm || true if command -v npm >/dev/null 2>&1; then NPM_VERSION=$(npm --version) echo -e "${GREEN}[OK]${NC} npm installed: $NPM_VERSION" NPM_OK=1 else echo -e "${RED}[ERROR]${NC} npm not available" ERRORS=$((ERRORS+1)) fi fi # ═══════════════════════════════════════════════════════════════ # STEP 5: Check Git and curl (optional) # ═══════════════════════════════════════════════════════════════ echo "" echo "[STEP 5/8] Checking Optional Dependencies..." if command -v git >/dev/null 2>&1; then echo -e "${GREEN}[OK]${NC} Git: $(git --version)" else echo -e "${YELLOW}[INFO]${NC} Git not found (optional)" fi if command -v curl >/dev/null 2>&1; then echo -e "${GREEN}[OK]${NC} curl: available" else echo -e "${YELLOW}[INFO]${NC} curl not found (optional, installing...)" install_packages curl || true fi # ═══════════════════════════════════════════════════════════════ # STEP 6: Install npm Dependencies # ═══════════════════════════════════════════════════════════════ echo "" echo "[STEP 6/8] Installing Dependencies..." if [[ $NODE_OK -eq 0 || $NPM_OK -eq 0 ]]; then echo -e "${YELLOW}[SKIP]${NC} Skipping npm install (Node.js/npm not available)" else cd "$SCRIPT_DIR" if [[ ! -f "package.json" ]]; then echo -e "${RED}[ERROR]${NC} package.json not found in $SCRIPT_DIR" echo "Make sure you extracted the full NomadArch package." log "ERROR: package.json missing" ERRORS=$((ERRORS+1)) else echo -e "${BLUE}[INFO]${NC} Running npm install (this may take a few minutes)..." log "Running npm install" if npm install --no-audit --no-fund 2>&1; then echo -e "${GREEN}[OK]${NC} Dependencies installed" else echo -e "${YELLOW}[WARN]${NC} npm install had issues, trying with legacy peer deps..." if npm install --legacy-peer-deps --no-audit --no-fund 2>&1; then echo -e "${GREEN}[OK]${NC} Dependencies installed (with legacy peer deps)" else echo -e "${RED}[ERROR]${NC} npm install failed" log "ERROR: npm install failed" ERRORS=$((ERRORS+1)) fi fi fi fi # ═══════════════════════════════════════════════════════════════ # STEP 7: Build UI Assets # ═══════════════════════════════════════════════════════════════ echo "" echo "[STEP 7/8] Building UI Assets..." if [[ $NODE_OK -eq 0 || $NPM_OK -eq 0 ]]; then echo -e "${YELLOW}[SKIP]${NC} Skipping UI build (Node.js/npm not available)" elif [[ -f "$SCRIPT_DIR/packages/ui/dist/index.html" ]]; then echo -e "${GREEN}[OK]${NC} UI build already exists" else echo -e "${BLUE}[INFO]${NC} Building UI (this may take 1-2 minutes)..." cd "$SCRIPT_DIR/packages/ui" if npm run build 2>&1; then echo -e "${GREEN}[OK]${NC} UI assets built successfully" else echo -e "${RED}[ERROR]${NC} UI build failed" log "ERROR: UI build failed" ERRORS=$((ERRORS+1)) fi cd "$SCRIPT_DIR" fi # ═══════════════════════════════════════════════════════════════ # STEP 8: Health Check and Summary # ═══════════════════════════════════════════════════════════════ echo "" echo "[STEP 8/8] Running Health Check..." HEALTH_ERRORS=0 [[ -f "$SCRIPT_DIR/package.json" ]] || { echo -e "${RED}[FAIL]${NC} package.json missing"; HEALTH_ERRORS=$((HEALTH_ERRORS+1)); } [[ -d "$SCRIPT_DIR/packages/ui" ]] || { echo -e "${RED}[FAIL]${NC} packages/ui missing"; HEALTH_ERRORS=$((HEALTH_ERRORS+1)); } [[ -d "$SCRIPT_DIR/packages/server" ]] || { echo -e "${RED}[FAIL]${NC} packages/server missing"; HEALTH_ERRORS=$((HEALTH_ERRORS+1)); } if [[ $NODE_OK -eq 1 && $NPM_OK -eq 1 ]]; then [[ -d "$SCRIPT_DIR/node_modules" ]] || { echo -e "${RED}[FAIL]${NC} node_modules missing"; HEALTH_ERRORS=$((HEALTH_ERRORS+1)); } [[ -f "$SCRIPT_DIR/packages/ui/dist/index.html" ]] || { echo -e "${YELLOW}[WARN]${NC} UI build missing"; ((WARNINGS++)) || true; } fi if [[ $HEALTH_ERRORS -eq 0 ]]; then echo -e "${GREEN}[OK]${NC} Health checks passed" else ERRORS=$((ERRORS+HEALTH_ERRORS)) fi # Summary echo "" echo -e "${CYAN}╔═══════════════════════════════════════════════════════════════╗${NC}" echo -e "${CYAN}║${NC} ${BOLD}INSTALLATION SUMMARY${NC} ${CYAN}║${NC}" echo -e "${CYAN}╚═══════════════════════════════════════════════════════════════╝${NC}" echo "" echo " Install Directory: $TARGET_DIR" echo " Architecture: $ARCH ($ARCH_TYPE)" echo " Distribution: $DISTRO_NAME" [[ -n "${NODE_VERSION:-}" ]] && echo " Node.js: $NODE_VERSION" [[ -n "${NPM_VERSION:-}" ]] && echo " npm: $NPM_VERSION" echo " Mode: Binary-Free Mode" echo " Errors: $ERRORS" echo " Warnings: $WARNINGS" echo " Log File: $LOG_FILE" echo "" if [[ $ERRORS -gt 0 ]]; then echo -e "${RED}╔═══════════════════════════════════════════════════════════════╗${NC}" echo -e "${RED}║${NC} ${BOLD}INSTALLATION COMPLETED WITH ERRORS${NC} ${RED}║${NC}" echo -e "${RED}╚═══════════════════════════════════════════════════════════════╝${NC}" echo "" echo "Review the errors above and check: $LOG_FILE" echo "" echo "Common fixes:" echo " 1. Install Node.js: sudo apt install nodejs npm" echo " 2. Run with sudo if permission issues" echo " 3. Check internet connection" echo "" log "Installation FAILED with $ERRORS errors" else echo -e "${GREEN}╔═══════════════════════════════════════════════════════════════╗${NC}" echo -e "${GREEN}║${NC} ${BOLD}INSTALLATION SUCCESSFUL!${NC} ${GREEN}║${NC}" echo -e "${GREEN}╚═══════════════════════════════════════════════════════════════╝${NC}" echo "" echo "To start NomadArch, run:" echo " ./Launch-Unix.sh" echo "" echo "Available Free Models:" echo " - GPT-5 Nano (fast)" echo " - Grok Code (coding)" echo " - GLM-4.7 (general)" echo " - Doubao (creative)" echo "" log "Installation SUCCESSFUL" fi exit $ERRORS