Files
gyandoot-v2/install.sh
Tara Menon 3b5b995af8 fix(install): cross-platform binary install + PATH conflict detection
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.
2026-06-13 18:26:39 +05:30

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 "$@"