Merge commit 'd803bfe2b1fe7f5e219e50ac20d6801a0a58ac75' as 'vendor/ruvector'

This commit is contained in:
ruv
2026-02-28 14:39:40 -05:00
7854 changed files with 3522914 additions and 0 deletions

View File

@@ -0,0 +1,738 @@
#!/bin/bash
#
# RuvBot Installer
#
# Usage:
# curl -fsSL https://get.ruvector.dev/ruvbot | bash
# curl -fsSL https://raw.githubusercontent.com/ruvnet/ruvector/main/npm/packages/ruvbot/scripts/install.sh | bash
#
# Options (via environment variables):
# RUVBOT_VERSION - Specific version to install (default: latest)
# RUVBOT_GLOBAL - Install globally (default: true)
# RUVBOT_INIT - Run init after install (default: false)
# RUVBOT_CHANNEL - Configure channel: slack, discord, telegram
# RUVBOT_DEPLOY - Deploy target: local, docker, cloudrun, k8s
# RUVBOT_WIZARD - Run interactive wizard (default: false)
#
# Examples:
# # Basic install
# curl -fsSL https://get.ruvector.dev/ruvbot | bash
#
# # Install specific version
# RUVBOT_VERSION=0.1.3 curl -fsSL https://get.ruvector.dev/ruvbot | bash
#
# # Install and initialize
# RUVBOT_INIT=true curl -fsSL https://get.ruvector.dev/ruvbot | bash
#
# # Install with Slack configuration
# RUVBOT_CHANNEL=slack curl -fsSL https://get.ruvector.dev/ruvbot | bash
#
# # Install and deploy to Cloud Run
# RUVBOT_DEPLOY=cloudrun curl -fsSL https://get.ruvector.dev/ruvbot | bash
#
# # Run full interactive wizard
# RUVBOT_WIZARD=true curl -fsSL https://get.ruvector.dev/ruvbot | bash
set -e
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
MAGENTA='\033[0;35m'
NC='\033[0m' # No Color
BOLD='\033[1m'
DIM='\033[2m'
# Configuration
RUVBOT_VERSION="${RUVBOT_VERSION:-latest}"
RUVBOT_GLOBAL="${RUVBOT_GLOBAL:-true}"
RUVBOT_INIT="${RUVBOT_INIT:-false}"
RUVBOT_CHANNEL="${RUVBOT_CHANNEL:-}"
RUVBOT_DEPLOY="${RUVBOT_DEPLOY:-}"
RUVBOT_WIZARD="${RUVBOT_WIZARD:-false}"
# Feature flags
GCLOUD_AVAILABLE=false
DOCKER_AVAILABLE=false
KUBECTL_AVAILABLE=false
# Banner
print_banner() {
echo -e "${CYAN}"
echo ' ____ ____ _ '
echo ' | _ \ _ ___ _| __ ) ___ | |_ '
echo ' | |_) | | | \ \ / / _ \ / _ \| __|'
echo ' | _ <| |_| |\ V /| |_) | (_) | |_ '
echo ' |_| \_\\__,_| \_/ |____/ \___/ \__|'
echo -e "${NC}"
echo -e "${BOLD}Enterprise-Grade Self-Learning AI Assistant${NC}"
echo -e "${DIM}Military-strength security • 150x faster search • 12+ LLM models${NC}"
echo ""
}
# Logging functions
info() { echo -e "${BLUE}${NC} $1"; }
success() { echo -e "${GREEN}${NC} $1"; }
warn() { echo -e "${YELLOW}${NC} $1"; }
error() { echo -e "${RED}${NC} $1"; exit 1; }
step() { echo -e "\n${MAGENTA}${NC} ${BOLD}$1${NC}"; }
# Check dependencies
check_dependencies() {
step "Checking dependencies"
# Check Node.js
if ! command -v node &> /dev/null; then
error "Node.js is required but not installed. Install from https://nodejs.org"
fi
NODE_VERSION=$(node -v | cut -d 'v' -f 2 | cut -d '.' -f 1)
if [ "$NODE_VERSION" -lt 18 ]; then
error "Node.js 18+ is required. Current: $(node -v)"
fi
success "Node.js $(node -v)"
# Check npm
if ! command -v npm &> /dev/null; then
error "npm is required but not installed"
fi
success "npm $(npm -v)"
# Check optional: gcloud
if command -v gcloud &> /dev/null; then
success "gcloud CLI $(gcloud --version 2>/dev/null | head -1 | awk '{print $4}')"
GCLOUD_AVAILABLE=true
else
echo -e "${DIM} ○ gcloud CLI not found (optional for Cloud Run)${NC}"
fi
# Check optional: docker
if command -v docker &> /dev/null; then
success "Docker $(docker --version | awk '{print $3}' | tr -d ',')"
DOCKER_AVAILABLE=true
else
echo -e "${DIM} ○ Docker not found (optional for containerization)${NC}"
fi
# Check optional: kubectl
if command -v kubectl &> /dev/null; then
success "kubectl $(kubectl version --client -o json 2>/dev/null | grep -o '"gitVersion": "[^"]*"' | cut -d'"' -f4)"
KUBECTL_AVAILABLE=true
else
echo -e "${DIM} ○ kubectl not found (optional for Kubernetes)${NC}"
fi
}
# Install RuvBot
install_ruvbot() {
step "Installing RuvBot"
PACKAGE="ruvbot"
if [ "$RUVBOT_VERSION" != "latest" ]; then
PACKAGE="ruvbot@$RUVBOT_VERSION"
info "Installing version $RUVBOT_VERSION"
fi
if [ "$RUVBOT_GLOBAL" = "true" ]; then
npm install -g "$PACKAGE" 2>/dev/null || sudo npm install -g "$PACKAGE"
success "RuvBot installed globally"
else
npm install "$PACKAGE"
success "RuvBot installed locally"
fi
# Verify installation
if command -v ruvbot &> /dev/null; then
INSTALLED_VERSION=$(ruvbot --version 2>/dev/null || echo "unknown")
success "RuvBot $INSTALLED_VERSION is ready"
else
success "RuvBot installed (use 'npx ruvbot' to run)"
fi
}
# Install optional dependencies for channels
install_channel_deps() {
local channel=$1
step "Installing $channel dependencies"
case "$channel" in
slack)
npm install @slack/bolt @slack/web-api 2>/dev/null
success "Slack SDK installed (@slack/bolt, @slack/web-api)"
;;
discord)
npm install discord.js 2>/dev/null
success "Discord.js installed"
;;
telegram)
npm install telegraf 2>/dev/null
success "Telegraf installed"
;;
all)
npm install @slack/bolt @slack/web-api discord.js telegraf 2>/dev/null
success "All channel dependencies installed"
;;
esac
}
# Initialize project
init_project() {
step "Initializing RuvBot project"
if [ "$RUVBOT_GLOBAL" = "true" ]; then
ruvbot init --yes
else
npx ruvbot init --yes
fi
success "Project initialized"
}
# Configure channel interactively
configure_channel() {
local channel=$1
step "Configuring $channel"
case "$channel" in
slack)
echo ""
echo " To set up Slack, you'll need credentials from:"
echo -e " ${CYAN}https://api.slack.com/apps${NC}"
echo ""
read -p " SLACK_BOT_TOKEN (xoxb-...): " SLACK_BOT_TOKEN
read -p " SLACK_SIGNING_SECRET: " SLACK_SIGNING_SECRET
read -p " SLACK_APP_TOKEN (xapp-...): " SLACK_APP_TOKEN
{
echo "SLACK_BOT_TOKEN=$SLACK_BOT_TOKEN"
echo "SLACK_SIGNING_SECRET=$SLACK_SIGNING_SECRET"
echo "SLACK_APP_TOKEN=$SLACK_APP_TOKEN"
} >> .env
success "Slack configuration saved to .env"
;;
discord)
echo ""
echo " To set up Discord, you'll need credentials from:"
echo -e " ${CYAN}https://discord.com/developers/applications${NC}"
echo ""
read -p " DISCORD_TOKEN: " DISCORD_TOKEN
read -p " DISCORD_CLIENT_ID: " DISCORD_CLIENT_ID
read -p " DISCORD_GUILD_ID (optional): " DISCORD_GUILD_ID
{
echo "DISCORD_TOKEN=$DISCORD_TOKEN"
echo "DISCORD_CLIENT_ID=$DISCORD_CLIENT_ID"
[ -n "$DISCORD_GUILD_ID" ] && echo "DISCORD_GUILD_ID=$DISCORD_GUILD_ID"
} >> .env
success "Discord configuration saved to .env"
;;
telegram)
echo ""
echo " To set up Telegram, get a token from:"
echo -e " ${CYAN}@BotFather${NC} on Telegram"
echo ""
read -p " TELEGRAM_BOT_TOKEN: " TELEGRAM_BOT_TOKEN
echo "TELEGRAM_BOT_TOKEN=$TELEGRAM_BOT_TOKEN" >> .env
success "Telegram configuration saved to .env"
;;
esac
}
# Deploy to Cloud Run
deploy_cloudrun() {
step "Deploying to Google Cloud Run"
if [ "$GCLOUD_AVAILABLE" != "true" ]; then
error "gcloud CLI is required. Install from https://cloud.google.com/sdk"
fi
# Check authentication
if ! gcloud auth list --filter=status:ACTIVE --format="value(account)" 2>/dev/null | head -1; then
warn "Not authenticated with gcloud"
info "Running 'gcloud auth login'..."
gcloud auth login
fi
# Get project
CURRENT_PROJECT=$(gcloud config get-value project 2>/dev/null || echo "")
echo ""
read -p " GCP Project ID [$CURRENT_PROJECT]: " PROJECT_ID
PROJECT_ID="${PROJECT_ID:-$CURRENT_PROJECT}"
if [ -z "$PROJECT_ID" ]; then
error "Project ID is required"
fi
gcloud config set project "$PROJECT_ID" 2>/dev/null
# Get region
read -p " Region [us-central1]: " REGION
REGION="${REGION:-us-central1}"
# Get service name
read -p " Service name [ruvbot]: " SERVICE_NAME
SERVICE_NAME="${SERVICE_NAME:-ruvbot}"
# Get API key
echo ""
echo " LLM Provider:"
echo " 1. OpenRouter (recommended - Gemini, Claude, GPT)"
echo " 2. Anthropic (Claude only)"
read -p " Choose [1]: " PROVIDER_CHOICE
PROVIDER_CHOICE="${PROVIDER_CHOICE:-1}"
if [ "$PROVIDER_CHOICE" = "1" ]; then
read -p " OPENROUTER_API_KEY: " API_KEY
ENV_VARS="OPENROUTER_API_KEY=$API_KEY,DEFAULT_MODEL=google/gemini-2.0-flash-001"
else
read -p " ANTHROPIC_API_KEY: " API_KEY
ENV_VARS="ANTHROPIC_API_KEY=$API_KEY"
fi
# Channel configuration
echo ""
read -p " Configure Slack? [y/N]: " SETUP_SLACK
if [[ "$SETUP_SLACK" =~ ^[Yy]$ ]]; then
read -p " SLACK_BOT_TOKEN: " SLACK_BOT_TOKEN
read -p " SLACK_SIGNING_SECRET: " SLACK_SIGNING_SECRET
ENV_VARS="$ENV_VARS,SLACK_BOT_TOKEN=$SLACK_BOT_TOKEN,SLACK_SIGNING_SECRET=$SLACK_SIGNING_SECRET"
fi
read -p " Configure Telegram? [y/N]: " SETUP_TELEGRAM
if [[ "$SETUP_TELEGRAM" =~ ^[Yy]$ ]]; then
read -p " TELEGRAM_BOT_TOKEN: " TELEGRAM_BOT_TOKEN
ENV_VARS="$ENV_VARS,TELEGRAM_BOT_TOKEN=$TELEGRAM_BOT_TOKEN"
fi
# Enable required APIs
info "Enabling required GCP APIs..."
gcloud services enable run.googleapis.com containerregistry.googleapis.com cloudbuild.googleapis.com 2>/dev/null
# Create Dockerfile if it doesn't exist
if [ ! -f "Dockerfile" ]; then
info "Creating Dockerfile..."
cat > Dockerfile << 'DOCKERFILE'
FROM node:20-slim
WORKDIR /app
# Install curl for health checks
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
# Install ruvbot
RUN npm install -g ruvbot
# Create directories
RUN mkdir -p /app/data /app/plugins /app/skills
# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD curl -f http://localhost:${PORT:-8080}/health || exit 1
# Start command
CMD ["ruvbot", "start", "--port", "8080"]
DOCKERFILE
success "Dockerfile created"
fi
# Deploy
info "Deploying to Cloud Run (this may take a few minutes)..."
gcloud run deploy "$SERVICE_NAME" \
--source . \
--platform managed \
--region "$REGION" \
--allow-unauthenticated \
--port 8080 \
--memory 512Mi \
--min-instances 0 \
--max-instances 10 \
--set-env-vars="$ENV_VARS" \
--quiet
# Get URL
SERVICE_URL=$(gcloud run services describe "$SERVICE_NAME" --region "$REGION" --format='value(status.url)')
echo ""
echo -e "${GREEN}═══════════════════════════════════════${NC}"
echo -e "${BOLD}🚀 RuvBot deployed successfully!${NC}"
echo -e "${GREEN}═══════════════════════════════════════${NC}"
echo ""
echo -e " URL: ${CYAN}$SERVICE_URL${NC}"
echo -e " Health: ${CYAN}$SERVICE_URL/health${NC}"
echo -e " API: ${CYAN}$SERVICE_URL/api/status${NC}"
echo -e " Models: ${CYAN}$SERVICE_URL/api/models${NC}"
echo ""
echo " Quick test:"
echo -e " ${DIM}curl $SERVICE_URL/health${NC}"
echo ""
# Set Telegram webhook if configured
if [ -n "$TELEGRAM_BOT_TOKEN" ]; then
WEBHOOK_URL="$SERVICE_URL/telegram/webhook"
info "Setting Telegram webhook..."
curl -s "https://api.telegram.org/bot$TELEGRAM_BOT_TOKEN/setWebhook?url=$WEBHOOK_URL" > /dev/null
success "Telegram webhook: $WEBHOOK_URL"
fi
}
# Deploy to Docker
deploy_docker() {
step "Deploying with Docker"
if [ "$DOCKER_AVAILABLE" != "true" ]; then
error "Docker is required. Install from https://docker.com"
fi
# Get configuration
read -p " Container name [ruvbot]: " CONTAINER_NAME
CONTAINER_NAME="${CONTAINER_NAME:-ruvbot}"
read -p " Port [3000]: " PORT
PORT="${PORT:-3000}"
# Create docker-compose.yml
info "Creating docker-compose.yml..."
cat > docker-compose.yml << COMPOSE
version: '3.8'
services:
ruvbot:
image: node:20-slim
container_name: $CONTAINER_NAME
working_dir: /app
command: sh -c "npm install -g ruvbot && ruvbot start --port 3000"
ports:
- "$PORT:3000"
environment:
- OPENROUTER_API_KEY=\${OPENROUTER_API_KEY}
- ANTHROPIC_API_KEY=\${ANTHROPIC_API_KEY}
- SLACK_BOT_TOKEN=\${SLACK_BOT_TOKEN}
- SLACK_SIGNING_SECRET=\${SLACK_SIGNING_SECRET}
- SLACK_APP_TOKEN=\${SLACK_APP_TOKEN}
- DISCORD_TOKEN=\${DISCORD_TOKEN}
- DISCORD_CLIENT_ID=\${DISCORD_CLIENT_ID}
- TELEGRAM_BOT_TOKEN=\${TELEGRAM_BOT_TOKEN}
volumes:
- ./data:/app/data
- ./plugins:/app/plugins
- ./skills:/app/skills
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
restart: unless-stopped
COMPOSE
success "docker-compose.yml created"
# Start containers
read -p " Start containers now? [Y/n]: " START_NOW
START_NOW="${START_NOW:-Y}"
if [[ "$START_NOW" =~ ^[Yy]$ ]]; then
info "Starting Docker containers..."
docker-compose up -d
echo ""
echo -e "${GREEN}═══════════════════════════════════════${NC}"
echo -e "${BOLD}🚀 RuvBot is running!${NC}"
echo -e "${GREEN}═══════════════════════════════════════${NC}"
echo ""
echo -e " URL: ${CYAN}http://localhost:$PORT${NC}"
echo -e " Health: ${CYAN}http://localhost:$PORT/health${NC}"
echo -e " Logs: ${DIM}docker-compose logs -f${NC}"
echo -e " Stop: ${DIM}docker-compose down${NC}"
echo ""
fi
}
# Deploy to Kubernetes
deploy_k8s() {
step "Deploying to Kubernetes"
if [ "$KUBECTL_AVAILABLE" != "true" ]; then
error "kubectl is required. Install from https://kubernetes.io/docs/tasks/tools/"
fi
# Get namespace
read -p " Namespace [default]: " NAMESPACE
NAMESPACE="${NAMESPACE:-default}"
# Get API key
read -p " OPENROUTER_API_KEY: " API_KEY
info "Creating Kubernetes manifests..."
mkdir -p k8s
# Create secret
cat > k8s/secret.yaml << SECRET
apiVersion: v1
kind: Secret
metadata:
name: ruvbot-secrets
namespace: $NAMESPACE
type: Opaque
stringData:
OPENROUTER_API_KEY: "$API_KEY"
DEFAULT_MODEL: "google/gemini-2.0-flash-001"
SECRET
# Create deployment
cat > k8s/deployment.yaml << DEPLOYMENT
apiVersion: apps/v1
kind: Deployment
metadata:
name: ruvbot
namespace: $NAMESPACE
spec:
replicas: 2
selector:
matchLabels:
app: ruvbot
template:
metadata:
labels:
app: ruvbot
spec:
containers:
- name: ruvbot
image: node:20-slim
command: ["sh", "-c", "npm install -g ruvbot && ruvbot start --port 3000"]
ports:
- containerPort: 3000
envFrom:
- secretRef:
name: ruvbot-secrets
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 60
periodSeconds: 30
readinessProbe:
httpGet:
path: /ready
port: 3000
initialDelaySeconds: 30
periodSeconds: 10
resources:
requests:
memory: "256Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "500m"
---
apiVersion: v1
kind: Service
metadata:
name: ruvbot
namespace: $NAMESPACE
spec:
selector:
app: ruvbot
ports:
- port: 80
targetPort: 3000
type: LoadBalancer
DEPLOYMENT
success "Kubernetes manifests created in k8s/"
read -p " Apply manifests now? [Y/n]: " APPLY_NOW
APPLY_NOW="${APPLY_NOW:-Y}"
if [[ "$APPLY_NOW" =~ ^[Yy]$ ]]; then
kubectl apply -f k8s/
echo ""
success "Kubernetes resources created"
echo ""
echo " Check status:"
echo -e " ${DIM}kubectl get pods -l app=ruvbot${NC}"
echo ""
echo " Get service URL:"
echo -e " ${DIM}kubectl get svc ruvbot${NC}"
echo ""
fi
}
# Deployment wizard
deployment_wizard() {
step "Deployment Options"
echo ""
echo " 1. Local (development)"
echo " 2. Docker"
echo " 3. Google Cloud Run"
echo " 4. Kubernetes"
echo " 5. Skip deployment"
echo ""
read -p " Select [5]: " DEPLOY_CHOICE
DEPLOY_CHOICE="${DEPLOY_CHOICE:-5}"
case "$DEPLOY_CHOICE" in
1)
info "Starting local development server..."
if [ "$RUVBOT_GLOBAL" = "true" ]; then
ruvbot start --debug
else
npx ruvbot start --debug
fi
;;
2) deploy_docker ;;
3) deploy_cloudrun ;;
4) deploy_k8s ;;
5) info "Skipping deployment" ;;
*) warn "Invalid option, skipping deployment" ;;
esac
}
# Interactive setup wizard
run_wizard() {
step "RuvBot Setup Wizard"
# Ensure .env exists
touch .env 2>/dev/null || true
# LLM Provider
echo ""
echo " ${BOLD}Step 1: LLM Provider${NC}"
echo " ───────────────────"
echo " 1. OpenRouter (Gemini 2.5, Claude, GPT - recommended)"
echo " 2. Anthropic (Claude only)"
echo " 3. Skip (configure later)"
read -p " Select [1]: " PROVIDER
PROVIDER="${PROVIDER:-1}"
case "$PROVIDER" in
1)
read -p " OPENROUTER_API_KEY: " OPENROUTER_KEY
{
echo "OPENROUTER_API_KEY=$OPENROUTER_KEY"
echo "DEFAULT_MODEL=google/gemini-2.0-flash-001"
} >> .env
success "OpenRouter configured"
;;
2)
read -p " ANTHROPIC_API_KEY: " ANTHROPIC_KEY
echo "ANTHROPIC_API_KEY=$ANTHROPIC_KEY" >> .env
success "Anthropic configured"
;;
3) info "Skipping LLM configuration" ;;
esac
# Channel Configuration
echo ""
echo " ${BOLD}Step 2: Channel Integrations${NC}"
echo " ────────────────────────────"
echo " 1. Slack"
echo " 2. Discord"
echo " 3. Telegram"
echo " 4. All channels"
echo " 5. Skip (configure later)"
read -p " Select [5]: " CHANNELS
CHANNELS="${CHANNELS:-5}"
case "$CHANNELS" in
1)
install_channel_deps "slack"
configure_channel "slack"
;;
2)
install_channel_deps "discord"
configure_channel "discord"
;;
3)
install_channel_deps "telegram"
configure_channel "telegram"
;;
4)
install_channel_deps "all"
configure_channel "slack"
configure_channel "discord"
configure_channel "telegram"
;;
5) info "Skipping channel configuration" ;;
esac
# Deployment
echo ""
echo " ${BOLD}Step 3: Deployment${NC}"
echo " ──────────────────"
deployment_wizard
}
# Print next steps
print_next_steps() {
echo ""
echo -e "${BOLD}📚 Quick Start${NC}"
echo "═══════════════════════════════════════"
echo ""
echo " Configure LLM provider:"
echo -e " ${CYAN}export OPENROUTER_API_KEY=sk-or-...${NC}"
echo ""
echo " Run diagnostics:"
echo -e " ${CYAN}ruvbot doctor${NC}"
echo ""
echo " Start the bot:"
echo -e " ${CYAN}ruvbot start${NC}"
echo ""
echo " Channel setup guides:"
echo -e " ${CYAN}ruvbot channels setup slack${NC}"
echo -e " ${CYAN}ruvbot channels setup discord${NC}"
echo -e " ${CYAN}ruvbot channels setup telegram${NC}"
echo ""
echo " Deploy templates:"
echo -e " ${CYAN}ruvbot templates list${NC}"
echo -e " ${CYAN}ruvbot deploy code-reviewer${NC}"
echo ""
echo " Deploy to Cloud Run:"
echo -e " ${CYAN}ruvbot deploy cloudrun${NC}"
echo ""
echo -e "${DIM}Docs: https://github.com/ruvnet/ruvector/tree/main/npm/packages/ruvbot${NC}"
echo ""
}
# Main
main() {
print_banner
check_dependencies
install_ruvbot
# Handle channel installation
if [ -n "$RUVBOT_CHANNEL" ]; then
install_channel_deps "$RUVBOT_CHANNEL"
fi
# Handle initialization
if [ "$RUVBOT_INIT" = "true" ]; then
init_project
fi
# Handle wizard
if [ "$RUVBOT_WIZARD" = "true" ]; then
run_wizard
elif [ -n "$RUVBOT_DEPLOY" ]; then
# Handle deployment without wizard
case "$RUVBOT_DEPLOY" in
cloudrun|cloud-run|gcp) deploy_cloudrun ;;
docker) deploy_docker ;;
k8s|kubernetes) deploy_k8s ;;
*) warn "Unknown deployment target: $RUVBOT_DEPLOY" ;;
esac
fi
print_next_steps
}
main "$@"