#!/usr/bin/env bash set -euo pipefail LABEL="local.nodedc.launcher-bff" PLIST="$HOME/Library/LaunchAgents/${LABEL}.plist" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REPO_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)" NODE_BIN="${NODE_BIN:-$(command -v node)}" LOG_OUT="/tmp/nodedc-launcher-bff.out.log" LOG_ERR="/tmp/nodedc-launcher-bff.err.log" USER_ID="$(id -u)" if [[ -z "${NODE_BIN}" || ! -x "${NODE_BIN}" ]]; then echo "Node.js executable not found. Set NODE_BIN=/absolute/path/to/node and retry." >&2 exit 1 fi mkdir -p "$(dirname "${PLIST}")" launchctl bootout "gui/${USER_ID}/${LABEL}" >/dev/null 2>&1 || true launchctl bootout "gui/${USER_ID}" "${PLIST}" >/dev/null 2>&1 || true if command -v lsof >/dev/null 2>&1; then while IFS= read -r PID_ON_PORT; do [[ -z "${PID_ON_PORT}" ]] && continue COMMAND_LINE="$(ps -p "${PID_ON_PORT}" -o command= 2>/dev/null || true)" if [[ "${COMMAND_LINE}" == *"server/dev-server.mjs"* ]]; then kill "${PID_ON_PORT}" >/dev/null 2>&1 || true fi done < <(lsof -tiTCP:5173 -sTCP:LISTEN 2>/dev/null || true) fi cat > "${PLIST}" < Label ${LABEL} ProgramArguments ${NODE_BIN} ${REPO_DIR}/server/dev-server.mjs WorkingDirectory ${REPO_DIR} RunAtLoad KeepAlive SuccessfulExit EnvironmentVariables PATH $(dirname "${NODE_BIN}"):/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin StandardOutPath ${LOG_OUT} StandardErrorPath ${LOG_ERR} PLIST launchctl bootstrap "gui/${USER_ID}" "${PLIST}" launchctl enable "gui/${USER_ID}/${LABEL}" >/dev/null 2>&1 || true launchctl kickstart -k "gui/${USER_ID}/${LABEL}" >/dev/null 2>&1 || true for _ in {1..20}; do if curl -fsS --max-time 2 http://launcher.local.nodedc/healthz >/dev/null 2>&1; then echo "NODE.DC launcher BFF is running via LaunchAgent: ${LABEL}" echo "Health: http://launcher.local.nodedc/healthz" echo "Logs: ${LOG_OUT} / ${LOG_ERR}" exit 0 fi sleep 0.5 done echo "LaunchAgent installed, but health check failed." >&2 echo "Check logs: ${LOG_OUT} / ${LOG_ERR}" >&2 exit 1