330 lines
12 KiB
Bash
Executable File
330 lines
12 KiB
Bash
Executable File
#!/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 <TASK_ID> [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"
|
|
|
|
# Ensure HTTPS dev certificate is available (Aspire may need it even for HTTP mode)
|
|
echo "🔐 Ensuring HTTPS developer certificate is available..."
|
|
if ! dotnet dev-certs https --check > /dev/null 2>&1; then
|
|
echo " Generating HTTPS developer certificate..."
|
|
dotnet dev-certs https --trust > /dev/null 2>&1 || {
|
|
echo "⚠️ Could not generate/trust certificate"
|
|
echo " Will try to use HTTP-only profile"
|
|
}
|
|
fi
|
|
|
|
# Configure Aspire to use HTTP only (avoid certificate issues)
|
|
# Use the "http" launch profile which is configured for HTTP-only
|
|
export ASPNETCORE_URLS="http://localhost:15242"
|
|
export DOTNET_DASHBOARD_OTLP_ENDPOINT_URL="http://localhost:19204"
|
|
export DOTNET_RESOURCE_SERVICE_ENDPOINT_URL="http://localhost:20284"
|
|
export DOTNET_DASHBOARD_OTLP_HTTP_ENDPOINT_URL="http://localhost:19204"
|
|
export ASPNETCORE_ENVIRONMENT="Development"
|
|
export DOTNET_ENVIRONMENT="Development"
|
|
|
|
# Restore packages in the worktree first to ensure all dependencies are available
|
|
# This is important because Aspire will build projects that may reference worktree paths
|
|
echo ""
|
|
echo "📦 Restoring NuGet packages..."
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
|
|
# Restore at solution level in worktree if it exists
|
|
if [ -f "$WORKTREE_PROJECT_ROOT/src/Managing.sln" ]; then
|
|
echo " Restoring in worktree solution..."
|
|
cd "$WORKTREE_PROJECT_ROOT/src"
|
|
# Suppress all warnings and only show errors
|
|
dotnet restore Managing.sln --verbosity quiet --nologo 2>&1 | \
|
|
grep -vE "(warning|Warning|WARNING|NU[0-9]|\.csproj :)" || true
|
|
fi
|
|
|
|
# Restore at solution level in main repo (where we'll actually run from)
|
|
echo " Restoring in main repo solution..."
|
|
cd "$MAIN_REPO/src"
|
|
# Suppress all warnings and only show errors
|
|
RESTORE_OUTPUT=$(dotnet restore Managing.sln --verbosity quiet --nologo 2>&1 | \
|
|
grep -vE "(warning|Warning|WARNING|NU[0-9]|\.csproj :)" || true)
|
|
if echo "$RESTORE_OUTPUT" | grep -qE "(error|Error|ERROR|failed|Failed)"; then
|
|
echo "❌ Package restore failed:"
|
|
echo "$RESTORE_OUTPUT"
|
|
exit 1
|
|
else
|
|
echo "✅ Packages restored successfully"
|
|
fi
|
|
|
|
# Ensure we're in the AppHost directory for running Aspire
|
|
cd "$MAIN_REPO/src/Managing.AppHost"
|
|
echo ""
|
|
|
|
# Run Aspire (this will start the API and Workers)
|
|
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 using the "http" launch profile (HTTP only, no HTTPS)
|
|
# All output goes to log file (warnings will be filtered when displaying)
|
|
dotnet run --launch-profile http > "$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 (filter warnings)
|
|
if [ -f "$ASPIRE_LOG" ]; then
|
|
LAST_LINE=$(tail -20 "$ASPIRE_LOG" 2>/dev/null | grep -vE "(warning|Warning|WARNING|NU[0-9]|\.csproj :)" | tail -1 | 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 (warnings filtered):"
|
|
tail -30 "$ASPIRE_LOG" 2>/dev/null | grep -vE "(warning|Warning|WARNING|NU[0-9]|\.csproj :)" | tail -10 || 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 (filter out warnings for cleaner output)
|
|
echo "📋 Showing Aspire logs (Press Ctrl+C to stop)"
|
|
echo " (Warnings are hidden for cleaner output - full logs in: $ASPIRE_LOG)"
|
|
echo ""
|
|
tail -f "$ASPIRE_LOG" 2>/dev/null | grep -vE "(warning|Warning|WARNING|NU[0-9]|\.csproj :)" || {
|
|
echo "❌ Cannot read Aspire log: $ASPIRE_LOG"
|
|
echo "💡 Aspire may still be starting. Check the log manually."
|
|
exit 1
|
|
}
|