739 lines
20 KiB
Bash
Executable File
739 lines
20 KiB
Bash
Executable File
#!/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 "$@"
|