#!/usr/bin/env bash # ═══════════════════════════════════════════════════════════════════════════ # GyanDoot v2.0 — Cross-Platform Universal Installer # ═══════════════════════════════════════════════════════════════════════════ # # Detects: macOS (arm64/x86_64), Linux (x86_64/aarch64/i686), # WSL (Windows Subsystem for Linux), Windows (Git Bash/MSYS2) # # Usage: # curl -fsSL https://git.gyannetra.in/gnpl_admin/gyandoot-release/raw/main/install.sh | bash # # Or locally: # ./install.sh # ═══════════════════════════════════════════════════════════════════════════ set -euo pipefail # ─── Colors ────────────────────────────────────────────────────────────── GREEN='\033[0;32m' BLUE='\033[0;34m' YELLOW='\033[1;33m' RED='\033[0;31m' CYAN='\033[0;36m' NC='\033[0m' info() { echo -e "${BLUE}[INFO]${NC} $*" >&2; } ok() { echo -e "${GREEN}[OK]${NC} $*" >&2; } warn() { echo -e "${YELLOW}[WARN]${NC} $*" >&2; } err() { echo -e "${RED}[ERR]${NC} $*" >&2; exit 1; } banner() { echo -e "${CYAN}" echo ' ______ __ _ _ _ ____ ___ ___ _____ ' echo ' / ___\ \ / // \ | \ | | _ \ / _ \ / _ \_ _|' echo '| | _ \ V // _ \ | \| | | | | | | | | | || | ' echo '| |_| | | |/ ___ \| |\ | |_| | |_| | |_| || | ' echo ' \____| |_/_/ \_\_| \_|____/ \___/ \___/ |_| ' echo -e "${NC}" echo -e "${GREEN} GyanDoot v2.0 — Knowledge Messenger${NC}" echo " Cross-Platform Universal Installer" echo "" } # ─── Platform Detection ────────────────────────────────────────────────── detect_architecture() { local arch arch="$(uname -m)" case "$arch" in x86_64|amd64) echo "x86_64" ;; aarch64|arm64) echo "aarch64" ;; i686|i386) echo "i686" ;; *) err "Unsupported architecture: $arch" ;; esac } detect_os() { local os os="$(uname -s)" case "$os" in Linux) echo "linux" ;; Darwin) echo "darwin" ;; CYGWIN*|MINGW*|MSYS*) echo "windows" ;; *) err "Unsupported OS: $os" ;; esac } detect_wsl() { if [ -f /proc/version ] && grep -qiE 'microsoft|wsl' /proc/version 2>/dev/null; then return 0 fi return 1 } get_shell_profile() { case "$SHELL" in */zsh) echo "$HOME/.zshrc" ;; */bash) echo "$HOME/.bashrc" ;; */fish) echo "$HOME/.config/fish/config.fish" ;; *) echo "$HOME/.profile" ;; esac } # ─── Dependency Installers ─────────────────────────────────────────────── install_rust_if_needed() { if ! command -v cargo &>/dev/null; then info "Rust toolchain not found. Installing..." if [ "$(uname -s)" = "Darwin" ] || [ "$(uname -s)" = "Linux" ]; then curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y source "$HOME/.cargo/env" elif [[ "$(uname -s)" =~ ^(CYGWIN|MINGW|MSYS) ]]; then # Windows: download rustup-init.exe powershell -Command "& {Invoke-WebRequest -Uri https://win.rustup.rs -OutFile '%TEMP%\rustup-init.exe'; Start-Process '%TEMP%\rustup-init.exe' -Wait -ArgumentList '-y'}" export PATH="$PATH:$HOME/.cargo/bin" else err "No Rust install method for this platform" fi ok "Rust installed ($(cargo --version))" else ok "Rust already installed ($(cargo --version))" fi } install_node_if_needed() { if ! command -v node &>/dev/null; then info "Node.js not found. Installing..." if command -v nvm &>/dev/null || [ -s "$HOME/.nvm/nvm.sh" ]; then [ -s "$HOME/.nvm/nvm.sh" ] && \. "$HOME/.nvm/nvm.sh" nvm install 22 2>/dev/null || nvm install node elif [ "$(uname -s)" = "Darwin" ]; then if command -v brew &>/dev/null; then brew install node else warn "Install Node.js manually: https://nodejs.org" fi elif [[ "$(uname -s)" =~ ^(CYGWIN|MINGW|MSYS) ]]; then warn "Install Node.js from: https://nodejs.org" else # Linux: use nvm curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.0/install.sh | bash [ -s "$HOME/.nvm/nvm.sh" ] && \. "$HOME/.nvm/nvm.sh" nvm install 22 fi ok "Node.js installed ($(node --version))" else ok "Node.js already installed ($(node --version))" fi # Ensure npx is available if ! command -v npx &>/dev/null; then warn "npx not found. Installing corepack..." npm install -g npx 2>/dev/null || true fi } # ─── Linux System Dependencies ─────────────────────────────────────────── # Camoufox (Playwright-based) needs these on Linux/WSL CAMOUFOX_LINUX_DEPS=( libgtk-3-0 libnss3 libnspr4 libatk1.0-0t64 libatk-bridge2.0-0t64 libcups2t64 libdrm2 libxkbcommon0 libxcomposite1 libxdamage1 libxfixes3 libxrandr2 libgbm1 libpango-1.0-0 libcairo2 libasound2t64 libxcb-shm0 libx11-xcb1 libx11-6 libxcb1 libxext6 libxcursor1 libxi6 libfreetype6 libfontconfig1 libxshmfence1 libxrender1 libdbus-1-3 ) install_linux_deps() { if [ "$(uname -s)" != "Linux" ]; then return 0 fi if detect_wsl; then info "WSL detected. Installing Linux system dependencies..." fi local missing=() if command -v dpkg-query &>/dev/null; then for pkg in "${CAMOUFOX_LINUX_DEPS[@]}"; do if ! dpkg-query -W -f='${Status}' "$pkg" 2>/dev/null | grep -q "install ok installed"; then local alt_pkg="${pkg%t64}" if [ "$alt_pkg" != "$pkg" ] && dpkg-query -W -f='${Status}' "$alt_pkg" 2>/dev/null | grep -q "install ok installed"; then continue fi missing+=("$pkg") fi done else missing=("${CAMOUFOX_LINUX_DEPS[@]}") fi if [ ${#missing[@]} -eq 0 ]; then info "All Linux system dependencies already installed" return 0 fi info "Installing ${#missing[@]} missing Linux system dependencies..." if command -v apt-get &>/dev/null; then if command -v sudo &>/dev/null; then sudo apt-get update -qq 2>/dev/null || true sudo apt-get install -y -qq "${missing[@]}" 2>/dev/null || { warn "Some packages failed. Retrying with fix..." sudo apt-get --fix-broken install -y -qq 2>/dev/null || true local fallback=() for pkg in "${missing[@]}"; do local alt="${pkg%t64}" [ "$alt" != "$pkg" ] && fallback+=("$alt") done [ ${#fallback[@]} -gt 0 ] && sudo apt-get install -y -qq "${fallback[@]}" 2>/dev/null || true } else apt-get update -qq 2>/dev/null || true apt-get install -y -qq "${missing[@]}" 2>/dev/null || true fi ok "Linux system dependencies installed" elif command -v dnf &>/dev/null; then sudo dnf install -y nss nspr atk at-spi2-atk cups-libs \ libdrm libXcomposite libXdamage libXrandr mesa-libgbm \ pango alsa-lib libxkbcommon libxcb libX11-xcb libX11 \ libXext libXcursor libXfixes libXi gtk3 cairo-gobject 2>/dev/null || true ok "Linux system dependencies installed" elif command -v yum &>/dev/null; then sudo yum install -y nss nspr atk at-spi2-atk cups-libs \ libdrm libXcomposite libXdamage libXrandr mesa-libgbm \ pango alsa-lib libxkbcommon 2>/dev/null || true ok "Linux system dependencies installed" else warn "No supported package manager. Install deps manually." warn "Required: ${CAMOUFOX_LINUX_DEPS[*]}" fi } # ─── Camoufox Browser Installer ────────────────────────────────────────── install_camoufox_browser() { info "Installing Camoufox browser (anti-detection engine)..." install_linux_deps if ! command -v npx &>/dev/null && ! command -v npm &>/dev/null; then warn "Node.js not found. Skipping Camoufox install." warn "Install Node.js and re-run: npm install -g camoufox-browser@0.1.0" return 0 fi # Step 1: Install npm package (daemon) info "Installing npm package (camoufox-browser@0.1.0)..." npm install -g camoufox-browser@0.1.0 2>&1 | tail -3 || { warn "npm install failed. Try manually: npm install -g camoufox-browser@0.1.0" return 0 } # Step 2: Override bundled camoufox-js@0.9.3 with v0.11.0 # The daemon does: import("camoufox-js") — Node resolves this from # the daemon's own node_modules/ FIRST, before checking global. # So we must REMOVE the bundled copy so Node falls through to global. info "Upgrading bundled camoufox-js to v0.11.0 (daemon dependency)..." local cb_pkg cb_pkg="$(npm root -g 2>/dev/null)/camoufox-browser" if [ -d "$cb_pkg/node_modules/camoufox-js" ]; then rm -rf "$cb_pkg/node_modules/camoufox-js" ok "Removed bundled camoufox-js@0.9.3 from daemon package" fi # Ensure global v0.11.0 exists npm install -g camoufox-js@0.11.0 2>&1 | tail -3 || { warn "Failed to install camoufox-js@0.11.0 globally" } # Step 3: Download browser binary info "Downloading Camoufox browser binary (~311MB)..." npx --yes camoufox-js@0.11.0 fetch 2>&1 || { warn "Download failed. Try manually: npx --yes camoufox-js@0.11.0 fetch" return 0 } # Step 3: macOS — remove Gatekeeper quarantine if [ "$(uname -s)" = "Darwin" ]; then if command -v xattr &>/dev/null; then info "Removing macOS quarantine from Camoufox..." xattr -dr com.apple.quarantine ~/Library/Caches/camoufox 2>/dev/null || true fi fi # Step 4: Verify local cache_dir if [ "$(uname -s)" = "Darwin" ]; then cache_dir="$HOME/Library/Caches/camoufox" else cache_dir="$HOME/.cache/camoufox" fi if [ -f "$cache_dir/version.json" ]; then ok "Camoufox browser installed ($(du -sh "$cache_dir" 2>/dev/null | cut -f1))" else warn "Browser binary not found. Run manually: npx --yes camoufox-js@0.11.0 fetch" fi } # ─── Build or Download GyanDoot ─────────────────────────────────────────── # In the source repo (gyandoot-v2): builds from Cargo workspace # In the release repo (gyandoot-release): uses prebuilt binary ensure_gyandoot_binary() { local root_dir root_dir="$(cd "$(dirname "$0")" 2>/dev/null && pwd || echo "$PWD")" cd "$root_dir" # Check 1: Is there a Cargo workspace? → Build from source local probe="$root_dir" while [ "$probe" != "/" ]; do if [ -f "$probe/Cargo.toml" ] && grep -q '\[workspace\]' "$probe/Cargo.toml" 2>/dev/null; then info "Source code found — building GyanDoot from source..." cd "$probe" cargo build --release 2>&1 | tail -5 ok "Build complete" echo "$probe/target/release/gyandoot" return 0 fi probe="$(dirname "$probe")" done # Check 2: Is there a prebuilt binary in the linux/ directory? local os os="$(uname -s)" local arch arch="$(uname -m)" # Map platform names local os_dir case "$os" in Darwin) os_dir="macos" ;; Linux) os_dir="linux" ;; CYGWIN*|MINGW*|MSYS*) os_dir="windows" ;; *) err "Unsupported OS: $os" ;; esac local prebuilt="$root_dir/$os_dir/gyandoot" if [ -f "$prebuilt" ]; then info "Prebuilt binary found at $prebuilt" echo "$prebuilt" return 0 fi # Check 3: Download from source repo (clone and build) info "No prebuilt binary found for $os/$arch" info "Cloning source repository to build from scratch..." local clone_dir clone_dir="$(mktemp -d 2>/dev/null || echo "/tmp/gyandoot-build-$$")" if command -v git &>/dev/null; then git clone --depth=1 https://git.gyannetra.in/gnpl_admin/gyandoot-v2.git "$clone_dir" 2>&1 | tail -5 >&2 cd "$clone_dir" cargo build --release 2>&1 | tail -5 >&2 if [ -f "target/release/gyandoot" ]; then ok "Built from source" echo "$clone_dir/target/release/gyandoot" return 0 fi if [ -f "target/release/gyandoot.exe" ]; then ok "Built from source" echo "$clone_dir/target/release/gyandoot.exe" return 0 fi fi err "Could not find or build GyanDoot binary. 1. Clone the source repo: git clone https://git.gyannetra.in/gnpl_admin/gyandoot-v2.git 2. cd gyandoot-v2 && cargo build --release 3. Then run: ./target/release/gyandoot" } # ─── Install Binary ────────────────────────────────────────────────────── install_binary() { local binary_path="$1" local bin_name if [ -z "$binary_path" ]; then err "No binary path provided to install_binary" fi if [ ! -f "$binary_path" ]; then err "Binary not found at $binary_path" fi bin_name="$(basename "$binary_path")" local os os="$(uname -s)" local install_dir="" local installed_to="" case "$os" in Darwin|Linux) # Priority: ~/.cargo/bin/ → /usr/local/bin → ~/.local/bin/ if [ -d "$HOME/.cargo/bin" ] && echo "$PATH" | grep -q "$HOME/.cargo/bin"; then install_dir="$HOME/.cargo/bin" elif [ -d "/usr/local/bin" ]; then if [ -w "/usr/local/bin" ]; then install_dir="/usr/local/bin" else info "Need sudo to install to /usr/local/bin" sudo cp "$binary_path" "/usr/local/bin/$bin_name" sudo chmod +x "/usr/local/bin/$bin_name" install_dir="/usr/local/bin" fi elif [ -d "$HOME/.local/bin" ] && echo "$PATH" | grep -q "$HOME/.local/bin"; then install_dir="$HOME/.local/bin" else mkdir -p "$HOME/.cargo/bin" install_dir="$HOME/.cargo/bin" if ! echo "$PATH" | grep -q "$HOME/.cargo/bin"; then warn "Add ~/.cargo/bin to your PATH in $(get_shell_profile):" echo " export PATH=\"\$HOME/.cargo/bin:\$PATH\"" fi fi if [ -n "$install_dir" ]; then cp "$binary_path" "$install_dir/$bin_name" chmod +x "$install_dir/$bin_name" installed_to="$install_dir/$bin_name" fi ;; CYGWIN*|MINGW*|MSYS*) install_dir="/usr/local/bin" cp "$binary_path" "$install_dir/$bin_name" chmod +x "$install_dir/$bin_name" installed_to="$install_dir/$bin_name" ;; *) err "Unsupported OS: $os" ;; esac ok "Installed to $installed_to" # ── Verify PATH resolution ────────────────────────────────────────── local cmd_path cmd_path="$(command -v gyandoot 2>/dev/null || true)" if [ -z "$cmd_path" ]; then warn "'gyandoot' not found in PATH. Use: $installed_to" elif [ "$cmd_path" != "$installed_to" ]; then warn "OLD binary at '$cmd_path' takes priority over '$installed_to'." warn "Remove old: sudo rm $cmd_path || rm $cmd_path" warn "Then 'gyandoot run' will use the new version." else ok "'gyandoot' resolves to the newly installed binary." fi } # ─── Post-Install Summary ──────────────────────────────────────────────── print_post_install() { echo "" ok "GyanDoot v2.0 installed successfully!" echo "" echo "╔═══════════════════════════════════════════════════════════╗" echo "║ Quick Start ║" echo "╠═══════════════════════════════════════════════════════════╣" echo "║ gyandoot --help Show all commands ║" echo "║ gyandoot setup Interactive config wizard ║" echo "║ gyandoot run Start interactive agent ║" echo "╠═══════════════════════════════════════════════════════════╣" echo "║ Browser Tools (anti-detection): ║" echo "║ gyandoot browser health Check Camoufox status ║" echo "║ gyandoot browser search Search the web ║" echo "║ gyandoot browser browse Visit a website ║" echo "╠═══════════════════════════════════════════════════════════╣" echo "║ Service Management: ║" echo "║ gyandoot service install Auto-start on boot ║" echo "║ gyandoot service status Check service status ║" echo "╚═══════════════════════════════════════════════════════════╝" echo "" if [ "$(uname -s)" = "Darwin" ]; then echo " 🍎 macOS — Camoufox Gatekeeper (one-time):" echo " xattr -dr com.apple.quarantine ~/Library/Caches/camoufox" echo "" fi if detect_wsl; then echo " ⚠️ WSL detected — Node.js must be installed INSIDE WSL." echo " (The Windows-side Node.js is not accessible from WSL.)" echo "" fi } # ─── Service Installation Prompt ───────────────────────────────────────── prompt_service_install() { echo "────────────────────────────────────────────" echo " Optional: Auto-start GyanDoot on Boot?" echo "────────────────────────────────────────────" echo " GyanDoot can run as a system service and" echo " start automatically when your computer boots." echo "" echo " (You can also do this later: gyandoot service install)" echo "" read -r -p " Install system service? [y/N]: " response case "$response" in [yY]|[yY][eE][sS]) info "Installing GyanDoot system service..." gyandoot service install 2>&1 || warn "Service install failed (run later: gyandoot service install)" ;; *) info "Skipping service install" ;; esac } # ═══════════════════════════════════════════════════════════════════════════ # MAIN # ═══════════════════════════════════════════════════════════════════════════ main() { banner local os arch os=$(detect_os) arch=$(detect_architecture) info "Detected: $os / $arch" if detect_wsl; then info "WSL (Windows Subsystem for Linux) detected" fi # ── Install dependencies ─────────────────────────────────────────── info "Phase 1: Checking prerequisites..." install_rust_if_needed install_node_if_needed # ── Install Camoufox browser ─────────────────────────────────────── info "Phase 2: Installing Camoufox browser..." install_camoufox_browser # ── Build or download binary ───────────────────────────────────── info "Phase 3: Preparing GyanDoot binary..." local gyandoot_binary gyandoot_binary="$(ensure_gyandoot_binary)" ok "Binary ready: $gyandoot_binary ($(du -sh "$gyandoot_binary" 2>/dev/null | cut -f1))" # ── Install binary ──────────────────────────────────────────────── info "Phase 4: Installing binary..." install_binary "$gyandoot_binary" # ── Optional: system service ─────────────────────────────────────── info "Phase 5: Service setup..." prompt_service_install # ── Done ─────────────────────────────────────────────────────────── print_post_install } main "$@"