#!/bin/bash # scripts/vibe-kanban/vibe-dev-server.sh # Simplified script for Vibe Kanban - starts API and Workers using Aspire # Assumes database setup is already done by vibe-setup.sh # Detect worktree root WORKTREE_ROOT="$(pwd)" # Check if we're in a nested structure (Vibe Kanban worktree) if [ -d "$WORKTREE_ROOT/managing-apps" ] && [ -d "$WORKTREE_ROOT/managing-apps/src/Managing.Api" ]; then WORKTREE_PROJECT_ROOT="$WORKTREE_ROOT/managing-apps" elif [ -d "$WORKTREE_ROOT/src/Managing.Api" ]; then WORKTREE_PROJECT_ROOT="$WORKTREE_ROOT" else echo "❌ Cannot find project structure in worktree" echo " Current directory: $WORKTREE_ROOT" exit 1 fi echo "📁 Worktree project root: $WORKTREE_PROJECT_ROOT" # TASK_ID file to ensure consistency (same as vibe-setup.sh) TASK_ID_FILE="$WORKTREE_PROJECT_ROOT/.vibe-task-id" # Load setup configuration if available SETUP_CONFIG_FILE="$WORKTREE_PROJECT_ROOT/.vibe-setup.env" if [ -f "$SETUP_CONFIG_FILE" ]; then echo "📋 Loading setup configuration from: $SETUP_CONFIG_FILE" source "$SETUP_CONFIG_FILE" echo " Task ID: $TASK_ID" echo " Task Slot: ${TASK_SLOT:-not set}" echo " Port offset: $PORT_OFFSET" echo " API Port: $API_PORT" else echo "⚠️ Setup configuration not found: $SETUP_CONFIG_FILE" echo "💡 Run scripts/vibe-kanban/vibe-setup.sh first to set up the database" # Try to get TASK_ID from stored file (ensures consistency) if [ -f "$TASK_ID_FILE" ]; then TASK_ID=$(cat "$TASK_ID_FILE" 2>/dev/null | tr -d '[:space:]') if [ -n "$TASK_ID" ]; then echo "📋 Using stored TASK_ID: $TASK_ID" fi fi # Try command line argument if [ -z "$TASK_ID" ]; then TASK_ID=${1:-""} fi # Try environment variables if [ -z "$TASK_ID" ]; then if [ -n "$VIBE_TASK_ID" ]; then TASK_ID="$VIBE_TASK_ID" elif [ -n "$VIBE_TASK_NAME" ]; then TASK_ID="$VIBE_TASK_NAME" fi fi PORT_OFFSET=${2:-0} if [ -z "$TASK_ID" ]; then echo "❌ TASK_ID is required" echo "💡 Usage: $0 [PORT_OFFSET]" echo "💡 Or run scripts/vibe-kanban/vibe-setup.sh first to create setup configuration" exit 1 fi API_PORT=$((5000 + PORT_OFFSET)) # Extract TASK_SLOT from TASK_ID if not in config if [ -z "$TASK_SLOT" ]; then TASK_SLOT=$(echo "$TASK_ID" | grep -oE '[0-9]+' | head -1) if [ -z "$TASK_SLOT" ] || [ "$TASK_SLOT" = "0" ]; then TASK_SLOT=$((PORT_OFFSET / 10 + 1)) fi fi echo " Using Task ID: $TASK_ID" echo " Using Task Slot: $TASK_SLOT" echo " Using Port offset: $PORT_OFFSET" fi # Find main repository MAIN_REPO_PATHS=( "/Users/oda/Desktop/Projects/managing-apps" "$(git -C "$WORKTREE_PROJECT_ROOT" rev-parse --show-toplevel 2>/dev/null || echo '')" "$(dirname "$WORKTREE_ROOT" 2>/dev/null)/managing-apps" "${MAIN_REPO:-}" ) MAIN_REPO="" for path in "${MAIN_REPO_PATHS[@]}"; do if [ -n "$path" ] && [ -d "$path" ] && [ -d "$path/src/Managing.AppHost" ]; then MAIN_REPO="$path" break fi done if [ -z "$MAIN_REPO" ]; then echo "❌ Cannot find main repository with Aspire AppHost" exit 1 fi echo "📁 Main repository: $MAIN_REPO" echo "🚀 Starting API and Workers using Aspire..." echo " Task ID: $TASK_ID" echo " Port offset: $PORT_OFFSET" echo " Task Slot: $TASK_SLOT" # Verify database is ready if [ -n "$POSTGRES_PORT" ]; then echo "🔍 Verifying database is ready on port $POSTGRES_PORT..." if ! PGPASSWORD=postgres psql -h localhost -p $POSTGRES_PORT -U postgres -d postgres -c '\q' 2>/dev/null; then echo "❌ Database is not ready on port $POSTGRES_PORT" echo "💡 Run scripts/vibe-kanban/vibe-setup.sh first to set up the database" exit 1 fi echo "✅ Database is ready" fi # Ensure API_PORT is set (should be from config, but fallback if needed) if [ -z "$API_PORT" ]; then API_PORT=$((5000 + PORT_OFFSET)) fi # Set environment variables for Aspire export TASK_ID="$TASK_ID" export PORT_OFFSET="$PORT_OFFSET" export TASK_SLOT="$TASK_SLOT" # Change to AppHost directory cd "$MAIN_REPO/src/Managing.AppHost" # Run Aspire (this will start the API and Workers) echo "" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "🚀 Starting Aspire..." echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "" # Run Aspire in the background and capture output ASPIRE_LOG="$WORKTREE_PROJECT_ROOT/.task-pids/aspire-${TASK_ID}.log" mkdir -p "$(dirname "$ASPIRE_LOG")" # Start Aspire dotnet run > "$ASPIRE_LOG" 2>&1 & ASPIRE_PID=$! # Save PID echo $ASPIRE_PID > "$WORKTREE_PROJECT_ROOT/.task-pids/aspire-${TASK_ID}.pid" echo "✅ Aspire started (PID: $ASPIRE_PID)" echo "📋 Log: $ASPIRE_LOG" echo "" echo "⏳ Aspire is starting (this may take 30-60 seconds on first run)..." echo " Building projects and starting services..." # Wait a bit for Aspire to start writing to the log sleep 3 # Try to extract the dashboard URL from the log (Aspire prints it when it starts) ASPIRE_DASHBOARD_URL="" ASPIRE_DASHBOARD_PORT="" # Common Aspire dashboard ports to try POSSIBLE_PORTS=(15242 15000 15888 17247) echo "" echo "⏳ Waiting for Aspire dashboard to be ready..." for i in {1..120}; do # Try to extract dashboard URL from log if [ -f "$ASPIRE_LOG" ]; then # Look for "Now listening on: http://localhost:PORT" or similar patterns DASHBOARD_LINE=$(grep -i "listening\|dashboard\|http://localhost" "$ASPIRE_LOG" 2>/dev/null | tail -1) if [ -n "$DASHBOARD_LINE" ]; then # Extract port from the line EXTRACTED_PORT=$(echo "$DASHBOARD_LINE" | grep -oE 'localhost:[0-9]+' | head -1 | cut -d: -f2) if [ -n "$EXTRACTED_PORT" ]; then ASPIRE_DASHBOARD_PORT="$EXTRACTED_PORT" ASPIRE_DASHBOARD_URL="http://localhost:${ASPIRE_DASHBOARD_PORT}" fi fi fi # If we don't have a URL yet, try common ports if [ -z "$ASPIRE_DASHBOARD_URL" ]; then for port in "${POSSIBLE_PORTS[@]}"; do if curl -s -f "http://localhost:${port}" > /dev/null 2>&1; then ASPIRE_DASHBOARD_PORT="$port" ASPIRE_DASHBOARD_URL="http://localhost:${port}" break fi done fi # If we found the dashboard, break if [ -n "$ASPIRE_DASHBOARD_URL" ] && curl -s -f "$ASPIRE_DASHBOARD_URL" > /dev/null 2>&1; then echo "✅ Aspire dashboard is ready at $ASPIRE_DASHBOARD_URL!" break fi # Show progress every 10 seconds if [ $((i % 10)) -eq 0 ]; then echo " Still starting... (${i}/120 seconds)" # Show last few lines of log for progress if [ -f "$ASPIRE_LOG" ]; then LAST_LINE=$(tail -1 "$ASPIRE_LOG" 2>/dev/null | cut -c1-80) if [ -n "$LAST_LINE" ]; then echo " Latest: $LAST_LINE" fi fi fi if [ $i -eq 120 ]; then echo "⚠️ Aspire dashboard did not become ready after 120 seconds" echo "💡 Check the log: $ASPIRE_LOG" echo "💡 Last 10 lines of log:" tail -10 "$ASPIRE_LOG" 2>/dev/null || echo " (log file not found)" # Try to use default port anyway if [ -z "$ASPIRE_DASHBOARD_URL" ]; then ASPIRE_DASHBOARD_PORT=15242 ASPIRE_DASHBOARD_URL="http://localhost:15242" echo "💡 Using default port: $ASPIRE_DASHBOARD_URL" fi fi sleep 1 done # Wait for API to be ready (give it more time since Aspire needs to build first) echo "" echo "⏳ Waiting for API to be ready..." API_READY=false for i in {1..90}; do if curl -s -f "http://localhost:${API_PORT}/alive" > /dev/null 2>&1; then API_READY=true echo "✅ API is ready!" break fi # Show progress every 15 seconds if [ $((i % 15)) -eq 0 ]; then echo " Still waiting for API... (${i}/90 seconds)" fi if [ $i -eq 90 ]; then echo "⚠️ API did not become ready after 90 seconds" echo "💡 Check the log: $ASPIRE_LOG" echo "💡 The API may still be building or starting" fi sleep 1 done # Print the Aspire dashboard URL in the format Vibe Kanban expects # This must be printed so Vibe Kanban can detect the server is running echo "" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" if [ "$API_READY" = true ]; then echo "✅ Dev server is running" else echo "⚠️ Dev server started (API may still be initializing)" fi echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "$ASPIRE_DASHBOARD_URL" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "" echo "📊 Additional URLs:" echo " API: http://localhost:${API_PORT}" echo " Swagger UI: http://localhost:${API_PORT}/swagger" echo " Health check: http://localhost:${API_PORT}/alive" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "" # Tail the Aspire log echo "📋 Showing Aspire logs (Press Ctrl+C to stop)" echo "" tail -f "$ASPIRE_LOG" 2>/dev/null || { echo "❌ Cannot read Aspire log: $ASPIRE_LOG" echo "💡 Aspire may still be starting. Check the log manually." exit 1 }