install_binary() now: 1. Automatically picks best location per platform: - macOS: ~/.cargo/bin/ (no sudo, in PATH for Rust users) - Linux: ~/.cargo/bin/ → /usr/local/bin → ~/.local/bin/ - Windows: /usr/local/bin (Git Bash/MSYS2) 2. Detects if old binary exists at a different PATH location and warns the user: 'There is ANOTHER gyandoot at ...' 3. Verifies 'command -v gyandoot' resolves correctly after install 4. Shows shell profile instructions if PATH needs updating Previous issue: always installed to /usr/local/bin with sudo, overwriting the old binary from install.sh but not warning if another copy existed elsewhere in PATH.
448 lines
17 KiB
Bash
Executable File
448 lines
17 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
# GyanDoot v2.0 — Cross-platform installer
|
|
# Detects OS, architecture, and installs the gyandoot binary + camofox-browser.
|
|
# For full documentation, visit: https://git.gyannetra.in/gnpl_admin/gyandoot-v2
|
|
|
|
GREEN='\033[0;32m'
|
|
BLUE='\033[0;34m'
|
|
YELLOW='\033[1;33m'
|
|
RED='\033[0;31m'
|
|
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; }
|
|
|
|
detect_architecture() {
|
|
local arch
|
|
arch="$(uname -m)"
|
|
case "$arch" in
|
|
x86_64|amd64) echo "x86_64" ;;
|
|
aarch64|arm64) echo "aarch64" ;;
|
|
*) 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
|
|
}
|
|
|
|
# ── WSL Detection ──────────────────────────────────────────────────────────
|
|
# Detect if we're running inside Windows Subsystem for Linux.
|
|
# /proc/version contains "microsoft" or "wsl" (case-insensitive) on WSL.
|
|
detect_wsl() {
|
|
if [ -f /proc/version ] && grep -qiE 'microsoft|wsl' /proc/version 2>/dev/null; then
|
|
return 0 # true — we are in WSL
|
|
fi
|
|
return 1
|
|
}
|
|
|
|
# ── Linux System Dependencies ──────────────────────────────────────────────
|
|
# Camoufox (Playwright-based) needs ~30 system libraries on Linux/WSL.
|
|
# Without these, the browser daemon crashes silently with
|
|
# "Failed to connect: No such file or directory (os error 2)".
|
|
# See: https://playwright.dev/docs/troubleshooting#system-dependencies
|
|
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_rust_if_needed() {
|
|
if ! command -v cargo &>/dev/null; then
|
|
info "Rust toolchain not found. Installing..."
|
|
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
|
|
source "$HOME/.cargo/env"
|
|
ok "Rust installed"
|
|
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 via 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
|
|
ok "Node.js installed ($(node --version))"
|
|
else
|
|
ok "Node.js already installed ($(node --version))"
|
|
fi
|
|
}
|
|
|
|
# ── Linux System Deps Installer ────────────────────────────────────────────
|
|
install_linux_deps() {
|
|
if [ "$(uname -s)" != "Linux" ]; then
|
|
return 0 # Not Linux, skip
|
|
fi
|
|
|
|
# Check if we're in WSL (Windows Subsystem for Linux)
|
|
if detect_wsl; then
|
|
info "WSL detected. Checking Linux system dependencies..."
|
|
fi
|
|
|
|
# Check which packages are already installed
|
|
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
|
|
# Handle libasound2 vs libasound2t64 and similar t64 variants
|
|
# Try without 't64' suffix as fallback
|
|
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 # alt version is already installed
|
|
fi
|
|
missing+=("$pkg")
|
|
fi
|
|
done
|
|
else
|
|
# Can't check, just try to install all
|
|
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 || {
|
|
# If some packages failed, retry with auto-detected alternatives
|
|
warn "Some packages had issues. Retrying with apt --fix..."
|
|
sudo apt-get --fix-broken install -y -qq 2>/dev/null || true
|
|
# Try installing without t64 variants as fallback
|
|
local fallback=()
|
|
for pkg in "${missing[@]}"; do
|
|
local alt="${pkg%t64}"
|
|
if [ "$alt" != "$pkg" ]; then
|
|
fallback+=("$alt")
|
|
fi
|
|
done
|
|
if [ ${#fallback[@]} -gt 0 ]; then
|
|
sudo apt-get install -y -qq "${fallback[@]}" 2>/dev/null || true
|
|
fi
|
|
}
|
|
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
|
|
info "Detected dnf package manager"
|
|
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
|
|
info "Detected yum package manager"
|
|
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 (apt-get/dnf/yum). You may need to install system dependencies manually."
|
|
warn "Required packages: ${CAMOUFOX_LINUX_DEPS[*]}"
|
|
fi
|
|
}
|
|
|
|
install_camofox_browser() {
|
|
info "Installing camofox-browser (anti-detection browser)..."
|
|
|
|
# Step 1: Install Linux system dependencies (needed by Playwright/Camoufox)
|
|
install_linux_deps
|
|
|
|
# Step 2: Install the npm package
|
|
if command -v npx &>/dev/null || command -v npm &>/dev/null; then
|
|
info "Installing npm package..."
|
|
npm install -g camoufox-browser@0.1.0 2>&1 | tail -3
|
|
|
|
info "Downloading Camoufox browser binary (this may take a while, ~662MB)..."
|
|
info "Running: npx --yes camoufox-js@0.11.0 fetch"
|
|
npx --yes camoufox-js@0.11.0 fetch 2>&1
|
|
|
|
# Verify the browser binary was actually downloaded
|
|
# macOS: ~/Library/Caches/camoufox/ | Linux: ~/.cache/camoufox/
|
|
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/camoufox" ]; then
|
|
ok "Camoufox browser binary downloaded ($cache_dir/)"
|
|
elif [ -f "$cache_dir/version.json" ]; then
|
|
ok "Camoufox browser cache found at $cache_dir/ (binary downloaded)"
|
|
else
|
|
warn "Browser binary not found at $cache_dir/. May need manual 'npx --yes camoufox-js@0.11.0 fetch'"
|
|
fi
|
|
|
|
ok "Camoufox browser npm package installed"
|
|
elif command -v docker &>/dev/null; then
|
|
info "Installing via Docker..."
|
|
docker run -d --name camoufox -p 9377:9377 \
|
|
-e CAMOUFOX_WS_PORT=9377 \
|
|
--restart unless-stopped \
|
|
ghcr.io/nousresearch/camoufox-browser:latest 2>&1 | tail -3
|
|
ok "Camoufox browser installed (Docker)"
|
|
else
|
|
warn "Neither npm nor docker found. Install manually: npm install -g camoufox-browser@0.1.0"
|
|
fi
|
|
}
|
|
|
|
build_release() {
|
|
local root_dir
|
|
root_dir="$(cd "$(dirname "$0")" && pwd)"
|
|
info "Building GyanDoot v2.0 in release mode..."
|
|
cd "$root_dir"
|
|
if [ ! -f "$root_dir/Cargo.toml" ]; then
|
|
local probe
|
|
probe="$(pwd)"
|
|
while [ "$probe" != "/" ]; do
|
|
if [ -f "$probe/Cargo.toml" ] && grep -q '\[workspace\]' "$probe/Cargo.toml" 2>/dev/null; then
|
|
root_dir="$probe"
|
|
cd "$root_dir"
|
|
info "Found workspace root at $root_dir"
|
|
break
|
|
fi
|
|
probe="$(dirname "$probe")"
|
|
done
|
|
fi
|
|
cargo build --release
|
|
ok "Build complete ($(du -sh target/release/gyandoot | cut -f1))"
|
|
}
|
|
|
|
install_binary() {
|
|
local root_dir
|
|
root_dir="$(cd "$(dirname "$0")" && pwd)"
|
|
local target_dir="$root_dir/target/release"
|
|
local bin_name="gyandoot"
|
|
|
|
if [ ! -f "$target_dir/$bin_name" ]; then
|
|
err "Binary not found at $target_dir/$bin_name"
|
|
fi
|
|
|
|
# ── Detect best install location per platform ─────────────────────
|
|
# Priority:
|
|
# 1. ~/.cargo/bin/ — always in PATH for Rust users, no sudo
|
|
# 2. /usr/local/bin/ — standard Unix location, may need sudo
|
|
# 3. Windows: use a standard PATH location or just warn
|
|
#
|
|
local os
|
|
os="$(uname -s)"
|
|
|
|
local install_dir=""
|
|
local installed_to=""
|
|
|
|
# Detect WSL (Windows Subsystem for Linux)
|
|
local is_wsl=false
|
|
if [ -f /proc/version ] && grep -qiE 'microsoft|wsl' /proc/version 2>/dev/null; then
|
|
is_wsl=true
|
|
fi
|
|
|
|
case "$os" in
|
|
Darwin|Linux)
|
|
# Option A: ~/.cargo/bin/ (no sudo needed, always in PATH for Rust users)
|
|
if [ -d "$HOME/.cargo/bin" ] && echo "$PATH" | grep -q "$HOME/.cargo/bin"; then
|
|
install_dir="$HOME/.cargo/bin"
|
|
cp "$target_dir/$bin_name" "$install_dir/$bin_name"
|
|
chmod +x "$install_dir/$bin_name"
|
|
installed_to="$install_dir/$bin_name"
|
|
# Option B: /usr/local/bin/ (standard, may need sudo)
|
|
elif [ -d "/usr/local/bin" ]; then
|
|
if [ -w "/usr/local/bin" ]; then
|
|
install_dir="/usr/local/bin"
|
|
cp "$target_dir/$bin_name" "$install_dir/$bin_name"
|
|
chmod +x "$install_dir/$bin_name"
|
|
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
|
|
installed_to="$install_dir/$bin_name"
|
|
# Option C: ~/.local/bin/ (XDG, common on modern Linux)
|
|
elif [ -d "$HOME/.local/bin" ] && echo "$PATH" | grep -q "$HOME/.local/bin"; then
|
|
install_dir="$HOME/.local/bin"
|
|
cp "$target_dir/$bin_name" "$install_dir/$bin_name"
|
|
chmod +x "$install_dir/$bin_name"
|
|
installed_to="$install_dir/$bin_name"
|
|
else
|
|
# Fallback: just copy to ~/.cargo/bin and create it
|
|
mkdir -p "$HOME/.cargo/bin"
|
|
cp "$target_dir/$bin_name" "$HOME/.cargo/bin/$bin_name"
|
|
chmod +x "$HOME/.cargo/bin/$bin_name"
|
|
install_dir="$HOME/.cargo/bin"
|
|
installed_to="$install_dir/$bin_name"
|
|
if ! echo "$PATH" | grep -q "$HOME/.cargo/bin"; then
|
|
warn "$HOME/.cargo/bin is not in your PATH."
|
|
warn "Add this to your shell profile (~/.zshrc, ~/.bashrc, etc.):"
|
|
echo " export PATH=\"\$HOME/.cargo/bin:\$PATH\""
|
|
fi
|
|
fi
|
|
;;
|
|
CYGWIN*|MINGW*|MSYS*)
|
|
# Windows / Git Bash / MSYS2
|
|
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"
|
|
warn "Windows detected. Make sure '$install_dir' is in your PATH."
|
|
;;
|
|
*)
|
|
err "Unsupported OS: $os"
|
|
;;
|
|
esac
|
|
|
|
ok "Installed to $installed_to"
|
|
|
|
# ── Verify it's usable via PATH ──────────────────────────────────
|
|
local cmd_path
|
|
cmd_path="$(command -v gyandoot 2>/dev/null || true)"
|
|
if [ -z "$cmd_path" ]; then
|
|
warn "'gyandoot' not found in PATH after install."
|
|
warn "The install directory may not be in your PATH."
|
|
warn "Try running with: $installed_to"
|
|
if [ -n "$install_dir" ]; then
|
|
case "$os" in
|
|
Darwin)
|
|
echo ""
|
|
echo " Add to your ~/.zshrc:"
|
|
echo " export PATH=\"$install_dir:\$PATH\""
|
|
echo " Then: source ~/.zshrc"
|
|
;;
|
|
Linux)
|
|
echo ""
|
|
echo " Add to your ~/.bashrc:"
|
|
echo " export PATH=\"$install_dir:\$PATH\""
|
|
echo " Then: source ~/.bashrc"
|
|
;;
|
|
esac
|
|
fi
|
|
elif [ "$cmd_path" != "$installed_to" ]; then
|
|
warn "There's ANOTHER 'gyandoot' at '$cmd_path' that takes priority over '$installed_to'."
|
|
warn "That binary is from a PREVIOUS installation and may be outdated."
|
|
warn ""
|
|
warn " ▶ To use the NEW version, run: $installed_to"
|
|
warn " ▶ Or remove the old one: sudo rm $cmd_path"
|
|
warn " ▶ Then 'gyandoot run' will pick up the new one."
|
|
else
|
|
ok "PATH resolves to the newly installed binary."
|
|
fi
|
|
}
|
|
|
|
print_post_install() {
|
|
echo ""
|
|
ok "GyanDoot v2.0 installed successfully!"
|
|
echo ""
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo " Quick Start:"
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo " gyandoot --help Show all commands"
|
|
echo " gyandoot init Create config"
|
|
echo " gyandoot setup Interactive setup wizard"
|
|
echo " gyandoot run Start interactive agent"
|
|
echo ""
|
|
echo " Browser Tools (anti-detection browsing):"
|
|
echo " gyandoot browser health Check camofox status"
|
|
echo " gyandoot browser search <query>"
|
|
echo " gyandoot browser browse <url>"
|
|
echo ""
|
|
echo " Service Management:"
|
|
echo " gyandoot service install Auto-start on boot"
|
|
echo " gyandoot service remove Remove system service"
|
|
echo " gyandoot service status Check service status"
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo ""
|
|
|
|
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
|
|
}
|
|
|
|
prompt_service_install() {
|
|
echo ""
|
|
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 " This keeps the gateway server running in the background."
|
|
echo ""
|
|
echo " (You can also do this later with: gyandoot service install)"
|
|
echo ""
|
|
read -r -p " Install system service? [y/N]: " response
|
|
}
|
|
|
|
main() {
|
|
local os arch
|
|
os=$(detect_os)
|
|
arch=$(detect_architecture)
|
|
info "Detected: $os / $arch"
|
|
if detect_wsl; then
|
|
info "WSL (Windows Subsystem for Linux) detected — will install Linux dependencies"
|
|
fi
|
|
|
|
install_rust_if_needed
|
|
install_node_if_needed
|
|
install_camofox_browser
|
|
|
|
build_release
|
|
install_binary
|
|
|
|
# Optional: install GyanDoot system service (auto-start on boot)
|
|
prompt_service_install
|
|
case "$response" in
|
|
[yY]|[yY][eE][sS])
|
|
info "Installing GyanDoot system service..."
|
|
gyandoot service install 2>&1 || warn "Service install failed (run 'gyandoot service install' later)"
|
|
;;
|
|
*)
|
|
info "Skipping service install (use 'gyandoot service install' later)"
|
|
;;
|
|
esac
|
|
|
|
print_post_install
|
|
}
|
|
|
|
main "$@" |