diff --git a/setup_timmy.sh b/setup_timmy.sh new file mode 100755 index 0000000..6e3da7a --- /dev/null +++ b/setup_timmy.sh @@ -0,0 +1,218 @@ +#!/usr/bin/env bash + +# ============================================================================= +# Sovereign Agent Stack — VPS Deployment Script (Final Remote-Ready) +# +# A single file to bootstrap Paperclip + OpenFang + Obsidian on a VPS. +# +# Usage: +# 1. curl -O https://raw.githubusercontent.com/AlexanderWhitestone/Timmy-time-dashboard/main/setup_timmy.sh +# 2. chmod +x setup_timmy.sh +# 3. ./setup_timmy.sh install +# 4. ./setup_timmy.sh start +# +# Dashboard: http://YOUR_VPS_IP:3100 +# ============================================================================= + +set -euo pipefail + +# --- Configuration --- +PROJECT_DIR="${PROJECT_DIR:-$HOME/sovereign-stack}" +VAULT_DIR="${VAULT_DIR:-$PROJECT_DIR/TimmyVault}" +PAPERCLIP_DIR="$PROJECT_DIR/paperclip" +AGENTS_DIR="$PROJECT_DIR/agents" +LOG_DIR="$PROJECT_DIR/logs" +PID_DIR="$PROJECT_DIR/pids" + +# Database Configuration (System Postgres) +DB_USER="paperclip" +DB_PASS="paperclip" +DB_NAME="paperclip" +DATABASE_URL="postgres://$DB_USER:$DB_PASS@localhost:5432/$DB_NAME" + +# --- Colors --- +CYAN='\033[0;36m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +RED='\033[0;31m' +BOLD='\033[1m' +NC='\033[0m' + +# --- Helper Functions --- +banner() { echo -e "\n${CYAN}═══════════════════════════════════════════════${NC}\n${BOLD}$1${NC}\n${CYAN}═══════════════════════════════════════════════${NC}\n"; } +step() { echo -e "${GREEN}▸${NC} $1"; } +warn() { echo -e "${YELLOW}⚠${NC} $1"; } +error() { echo -e "${RED}✘${NC} $1"; exit 1; } +info() { echo -e "${BOLD}$1${NC}"; } + +# --- Core Logic --- + +check_preflight() { + banner "Preflight Checks" + + # Check OS + if [[ "$OSTYPE" == "linux-gnu"* ]]; then + step "OS: Linux detected ✓" + else + warn "OS: $OSTYPE detected. This script is optimized for Ubuntu/Debian." + fi + + # Install basic dependencies if missing (Ubuntu/Debian only) + if command -v apt-get >/dev/null 2>&1; then + step "Updating system and installing base dependencies..." + sudo apt-get update -y > /dev/null + sudo apt-get install -y curl git postgresql postgresql-contrib build-essential > /dev/null + fi + + # Check for Node.js + if ! command -v node >/dev/null 2>&1; then + step "Installing Node.js 20..." + curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - + sudo apt-get install -y nodejs + fi + step "Node $(node -v) ✓" + + # Check for pnpm + if ! command -v pnpm >/dev/null 2>&1; then + step "Installing pnpm..." + sudo npm install -g pnpm + fi + step "pnpm $(pnpm -v) ✓" +} + +setup_database() { + banner "Database Setup" + step "Ensuring PostgreSQL service is running..." + sudo service postgresql start || true + + step "Configuring Paperclip database and user..." + # Create user and database if they don't exist + sudo -u postgres psql -tAc "SELECT 1 FROM pg_roles WHERE rolname='$DB_USER'" | grep -q 1 || \ + sudo -u postgres psql -c "CREATE USER $DB_USER WITH PASSWORD '$DB_PASS' SUPERUSER;" + + sudo -u postgres psql -lqt | cut -d \| -f 1 | grep -qw "$DB_NAME" || \ + sudo -u postgres psql -c "CREATE DATABASE $DB_NAME OWNER $DB_USER;" + + step "Database ready ✓" +} + +install_stack() { + banner "Installing Sovereign Stack" + mkdir -p "$PROJECT_DIR" "$AGENTS_DIR" "$LOG_DIR" "$PID_DIR" + + # 1. OpenFang + if ! command -v openfang >/dev/null 2>&1; then + step "Installing OpenFang..." + curl -fsSL https://openfang.sh/install | sh + fi + step "OpenFang ready ✓" + + # 2. Paperclip + if [ ! -d "$PAPERCLIP_DIR" ]; then + step "Cloning Paperclip..." + git clone --depth 1 https://github.com/paperclipai/paperclip.git "$PAPERCLIP_DIR" + fi + cd "$PAPERCLIP_DIR" + step "Installing Paperclip dependencies (this may take a few minutes)..." + pnpm install --frozen-lockfile 2>/dev/null || pnpm install + cd - > /dev/null + step "Paperclip ready ✓" + + # 3. Obsidian Vault + mkdir -p "$VAULT_DIR" + if [ ! -f "$VAULT_DIR/Genesis.md" ]; then + echo "# Genesis Note" > "$VAULT_DIR/Genesis.md" + echo "Created on $(date)" >> "$VAULT_DIR/Genesis.md" + fi + step "Obsidian Vault ready: $VAULT_DIR ✓" +} + +start_services() { + banner "Starting Services" + + # Start Paperclip + if [ -f "$PID_DIR/paperclip.pid" ] && ps -p $(cat "$PID_DIR/paperclip.pid") > /dev/null; then + warn "Paperclip is already running." + else + step "Starting Paperclip (binding to 0.0.0.0)..." + cd "$PAPERCLIP_DIR" + export DATABASE_URL="$DATABASE_URL" + export BETTER_AUTH_SECRET="sovereign-$(openssl rand -hex 16)" + export PAPERCLIP_AGENT_JWT_SECRET="agent-$(openssl rand -hex 16)" + export BETTER_AUTH_URL="http://$(curl -s ifconfig.me):3100" + + nohup pnpm dev --authenticated-private > "$LOG_DIR/paperclip.log" 2>&1 & + echo $! > "$PID_DIR/paperclip.pid" + cd - > /dev/null + fi + + # Start OpenFang + if [ -f "$PID_DIR/openfang.pid" ] && ps -p $(cat "$PID_DIR/openfang.pid") > /dev/null; then + warn "OpenFang is already running." + else + step "Starting OpenFang..." + nohup openfang start > "$LOG_DIR/openfang.log" 2>&1 & + echo $! > "$PID_DIR/openfang.pid" + fi + + step "Waiting for Paperclip to initialize..." + for i in {1..30}; do + if grep -q "Server listening on" "$LOG_DIR/paperclip.log" 2>/dev/null; then + info "SUCCESS: Paperclip is live!" + info "Dashboard: http://$(curl -s ifconfig.me):3100" + return + fi + sleep 2 + done + warn "Startup taking longer than expected. Check logs: $LOG_DIR/paperclip.log" +} + +stop_services() { + banner "Stopping Services" + for service in paperclip openfang; do + pid_file="$PID_DIR/$service.pid" + if [ -f "$pid_file" ]; then + pid=$(cat "$pid_file") + step "Stopping $service (PID: $pid)..." + pkill -P "$pid" 2>/dev/null || true + kill "$pid" 2>/dev/null || true + rm "$pid_file" + fi + done + step "Services stopped ✓" +} + +# --- Main CLI --- + +case "${1:-}" in + install) + check_preflight + setup_database + install_stack + banner "Installation Complete" + info "Run: ./setup_timmy.sh start" + ;; + start) + start_services + ;; + stop) + stop_services + ;; + status) + banner "Stack Status" + for s in paperclip openfang; do + if [ -f "$PID_DIR/$s.pid" ] && ps -p $(cat "$PID_DIR/$s.pid") > /dev/null; then + echo -e "${GREEN}●${NC} $s is running" + else + echo -e "${RED}○${NC} $s is stopped" + fi + done + ;; + logs) + tail -f "$LOG_DIR"/*.log + ;; + *) + echo "Usage: $0 {install|start|stop|status|logs}" + exit 1 + ;; +esac