The old banner was a handwritten ASCII art that didn't actually spell 'GYANDOOT'. Replaced with proper figlet 'standard' font output so the banner is readable and correct.
460 lines
20 KiB
Bash
460 lines
20 KiB
Bash
#!/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} $*"; }
|
|
ok() { echo -e "${GREEN}[OK]${NC} $*"; }
|
|
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
|
|
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
|
|
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: 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 GyanDoot ──────────────────────────────────────────────────────
|
|
build_gyandoot() {
|
|
local root_dir
|
|
root_dir="$(cd "$(dirname "$0")" 2>/dev/null && pwd || echo "$PWD")"
|
|
|
|
# Find workspace root (where Cargo.toml with [workspace] is)
|
|
cd "$root_dir"
|
|
while [ "$PWD" != "/" ]; do
|
|
if [ -f "Cargo.toml" ] && grep -q '\[workspace\]' Cargo.toml 2>/dev/null; then
|
|
info "Found workspace root at $PWD"
|
|
break
|
|
fi
|
|
cd ..
|
|
done
|
|
|
|
if [ "$PWD" = "/" ]; then
|
|
err "Could not find Cargo workspace. Make sure you're in the gyandoot-v2 directory."
|
|
fi
|
|
|
|
info "Building GyanDoot v2.0 (release mode)..."
|
|
cargo build --release 2>&1 | tail -5
|
|
ok "Build complete ($(du -sh target/release/gyandoot* 2>/dev/null | cut -f1))"
|
|
}
|
|
|
|
# ─── Install Binary ──────────────────────────────────────────────────────
|
|
install_binary() {
|
|
local target_dir="$PWD/target/release"
|
|
local bin_name="gyandoot"
|
|
|
|
if [ -f "$target_dir/gyandoot.exe" ]; then
|
|
bin_name="gyandoot.exe"
|
|
fi
|
|
|
|
if [ ! -f "$target_dir/$bin_name" ]; then
|
|
err "Binary not found at $target_dir/$bin_name"
|
|
fi
|
|
|
|
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 "$target_dir/$bin_name" "/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 "$target_dir/$bin_name" "$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 "$target_dir/$bin_name" "$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 from source ──────────────────────────────────────────────
|
|
info "Phase 3: Building GyanDoot..."
|
|
build_gyandoot
|
|
|
|
# ── Install binary ─────────────────────────────────────────────────
|
|
info "Phase 4: Installing binary..."
|
|
install_binary
|
|
|
|
# ── Optional: system service ───────────────────────────────────────
|
|
info "Phase 5: Service setup..."
|
|
prompt_service_install
|
|
|
|
# ── Done ───────────────────────────────────────────────────────────
|
|
print_post_install
|
|
}
|
|
|
|
main "$@" |