#!/usr/bin/env bash # Portable AetherForge / forge-mesh command deck launcher (USB edition). # Starts optional cloudflared sidecar, sets AF_TUNNEL_EXTERNAL=1, opens the deck UI, # and runs forge-mesh-server against ./data. set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" if [[ "$(basename "$SCRIPT_DIR")" == "scripts" ]]; then ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" else ROOT="$SCRIPT_DIR" fi cd "$ROOT" DATA_DIR="${AF_DATA_DIR:-$ROOT/data}" CONFIG="${AF_CONFIG:-$DATA_DIR/config.json}" SERVER_BIN="${AF_SERVER_BIN:-$ROOT/bin/forge-mesh-server}" DECK_URL="${AF_DECK_URL:-http://localhost:8989}" CLOUDFLARED_PID="" cleanup() { if [[ -n "$CLOUDFLARED_PID" ]] && kill -0 "$CLOUDFLARED_PID" 2>/dev/null; then kill "$CLOUDFLARED_PID" 2>/dev/null || true wait "$CLOUDFLARED_PID" 2>/dev/null || true fi } trap cleanup EXIT INT TERM resolve_cloudflared() { if command -v cloudflared >/dev/null 2>&1; then command -v cloudflared return 0 fi for candidate in "$ROOT/bin/cloudflared" "$ROOT/cloudflared"; do if [[ -x "$candidate" ]]; then echo "$candidate" return 0 fi done return 1 } read_tunnel_token() { if [[ -n "${AF_TUNNEL_TOKEN:-}" ]]; then printf '%s' "$AF_TUNNEL_TOKEN" return 0 fi local token_file="$DATA_DIR/cloudflared-token.txt" if [[ -f "$token_file" ]]; then tr -d '[:space:]' <"$token_file" return 0 fi return 1 } start_tunnel_sidecar() { local token cf_bin token="$(read_tunnel_token)" || return 0 cf_bin="$(resolve_cloudflared)" || { echo "WARN: tunnel token present but cloudflared not found (PATH or $ROOT/bin/cloudflared)" >&2 return 0 } echo "Starting cloudflared sidecar..." "$cf_bin" tunnel --no-autoupdate run --token "$token" & CLOUDFLARED_PID=$! export AF_TUNNEL_EXTERNAL=1 echo "AF_TUNNEL_EXTERNAL=1 (cloudflared pid $CLOUDFLARED_PID)" } open_browser() { local url="$1" if [[ -n "${AF_NO_BROWSER:-}" ]]; then echo "AF_NO_BROWSER set; deck at $url" return 0 fi for opener in xdg-open sensible-browser x-www-browser gnome-open kde-open; do if command -v "$opener" >/dev/null 2>&1; then "$opener" "$url" >/dev/null 2>&1 & return 0 fi done echo "Open your browser to $url" } ensure_server_binary() { if [[ -x "$SERVER_BIN" ]]; then return 0 fi if command -v forge-mesh-server >/dev/null 2>&1; then SERVER_BIN="$(command -v forge-mesh-server)" return 0 fi echo "ERROR: forge-mesh-server not found. Build with 'make server' or place binary in $ROOT/bin/" >&2 exit 1 } mkdir -p "$DATA_DIR" if [[ ! -f "$CONFIG" ]]; then echo "ERROR: missing config at $CONFIG" >&2 exit 1 fi start_tunnel_sidecar ensure_server_binary open_browser "$DECK_URL" echo "Starting forge-mesh-server (config: $CONFIG)" exec "$SERVER_BIN" -config "$CONFIG"