#!/usr/bin/env bash set -euo pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)" TMP_DIR="$ROOT_DIR/.tmp/ui-e2e" LOG_DIR="$TMP_DIR/logs" POSTGRES_CONTAINER="crank-e2e-postgres" POSTGRES_PORT="${CRANK_E2E_POSTGRES_PORT:-55433}" ADMIN_PORT="${CRANK_E2E_ADMIN_PORT:-3301}" MCP_PORT="${CRANK_E2E_MCP_PORT:-3302}" UI_PORT="${CRANK_E2E_UI_PORT:-3300}" POSTGRES_DB="${CRANK_E2E_POSTGRES_DB:-crank}" POSTGRES_USER="${CRANK_E2E_POSTGRES_USER:-crank}" POSTGRES_PASSWORD="${CRANK_E2E_POSTGRES_PASSWORD:-crank}" ADMIN_EMAIL="${CRANK_E2E_ADMIN_EMAIL:-owner@crank.local}" ADMIN_PASSWORD="${CRANK_E2E_ADMIN_PASSWORD:-change-me-admin-password}" mkdir -p "$LOG_DIR" kill_port_processes() { local port="$1" if command -v lsof >/dev/null 2>&1; then lsof -ti "tcp:$port" | xargs -r kill >/dev/null 2>&1 || true fi } cleanup() { set +e if [[ -f "$TMP_DIR/admin-api.pid" ]]; then kill "$(cat "$TMP_DIR/admin-api.pid")" >/dev/null 2>&1 || true rm -f "$TMP_DIR/admin-api.pid" fi if [[ -f "$TMP_DIR/mcp-server.pid" ]]; then kill "$(cat "$TMP_DIR/mcp-server.pid")" >/dev/null 2>&1 || true rm -f "$TMP_DIR/mcp-server.pid" fi if [[ -f "$TMP_DIR/ui-server.pid" ]]; then kill "$(cat "$TMP_DIR/ui-server.pid")" >/dev/null 2>&1 || true rm -f "$TMP_DIR/ui-server.pid" fi docker rm -f "$POSTGRES_CONTAINER" >/dev/null 2>&1 || true kill_port_processes "$UI_PORT" kill_port_processes "$ADMIN_PORT" kill_port_processes "$MCP_PORT" } trap cleanup EXIT INT TERM cleanup docker run -d --rm \ --name "$POSTGRES_CONTAINER" \ -e POSTGRES_DB="$POSTGRES_DB" \ -e POSTGRES_USER="$POSTGRES_USER" \ -e POSTGRES_PASSWORD="$POSTGRES_PASSWORD" \ -p "$POSTGRES_PORT:5432" \ postgres:16-alpine >/dev/null until docker exec "$POSTGRES_CONTAINER" pg_isready -U "$POSTGRES_USER" -d "$POSTGRES_DB" >/dev/null 2>&1; do sleep 1 done export CRANK_DATABASE_URL="postgres://$POSTGRES_USER:$POSTGRES_PASSWORD@127.0.0.1:$POSTGRES_PORT/$POSTGRES_DB" export CRANK_STORAGE_ROOT="$TMP_DIR/storage" export CRANK_ADMIN_BIND="0.0.0.0:$ADMIN_PORT" export CRANK_MCP_BIND="0.0.0.0:$MCP_PORT" export CRANK_MCP_REFRESH_MS="1000" export CRANK_LOG_LEVEL="info" export CRANK_SECRET_PROVIDER="env" export CRANK_SESSION_SECRET="e2e-session-secret" export CRANK_PASSWORD_PEPPER="e2e-password-pepper" export CRANK_SESSION_TTL_HOURS="24" export CRANK_BOOTSTRAP_ADMIN_EMAIL="$ADMIN_EMAIL" export CRANK_BOOTSTRAP_ADMIN_PASSWORD="$ADMIN_PASSWORD" export CRANK_BOOTSTRAP_ADMIN_DISPLAY_NAME="Crank E2E" export CRANK_DEMO_SEED="true" export CRANK_PUBLIC_BASE_URL="http://127.0.0.1:$UI_PORT" export CRANK_MCP_PUBLIC_URL="http://127.0.0.1:$MCP_PORT" mkdir -p "$CRANK_STORAGE_ROOT" ( cd "$ROOT_DIR" cargo run -p admin-api >"$LOG_DIR/admin-api.log" 2>&1 ) & echo $! > "$TMP_DIR/admin-api.pid" until curl -fsS "http://127.0.0.1:$ADMIN_PORT/health" >/dev/null 2>&1; do sleep 1 done ( cd "$ROOT_DIR" cargo run -p mcp-server >"$LOG_DIR/mcp-server.log" 2>&1 ) & echo $! > "$TMP_DIR/mcp-server.pid" until curl -fsS "http://127.0.0.1:$MCP_PORT/health" >/dev/null 2>&1; do sleep 1 done ( cd "$ROOT_DIR/apps/ui" node scripts/playwright-ui-server.js >"$LOG_DIR/ui-server.log" 2>&1 ) & echo $! > "$TMP_DIR/ui-server.pid" until curl -fsS "http://127.0.0.1:$UI_PORT/login" >/dev/null 2>&1; do sleep 1 done echo "Crank UI e2e stack is ready on http://127.0.0.1:$UI_PORT" while true; do sleep 1 done