# Preflight checks. Fail loud and early with actionable messages. check_docker() { if ! command -v docker >/dev/null 2>&1; then ui_err "$(t err_need_docker)"; exit 1 fi if ! docker info >/dev/null 2>&1; then ui_err "$(t err_docker_daemon)"; exit 1 fi if ! docker compose version >/dev/null 2>&1; then ui_err "$(t err_need_compose)"; exit 1 fi } check_openssl() { if ! command -v openssl >/dev/null 2>&1; then ui_err "$(t err_need_openssl)"; exit 1 fi } # is_port_free PORT — best effort; returns 0 if nothing seems to listen on it. is_port_free() { local port="$1" if command -v lsof >/dev/null 2>&1; then ! lsof -nP -iTCP:"$port" -sTCP:LISTEN >/dev/null 2>&1 elif command -v nc >/dev/null 2>&1; then ! nc -z localhost "$port" >/dev/null 2>&1 else return 0 # can't check — assume free fi } preflight() { check_docker check_openssl ui_ok "$(t preflight_ok)" }