#!/usr/bin/env bash set -euo pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" VENV_DIR="${FGAI_VENV_DIR:-$ROOT_DIR/.venv}" PORT="${FGAI_SYSLOG_PORT:-5514}" HOST="${FGAI_SYSLOG_HOST:-0.0.0.0}" LOG_FILE="${FGAI_SYSLOG_FILE:-$ROOT_DIR/logs/fg_syslog.jsonl}" LISTENER_LOG="${FGAI_LISTENER_LOG:-$ROOT_DIR/logs/fgai-listener.log}" PID_FILE="${FGAI_PID_FILE:-$ROOT_DIR/run/fgai-listener.pid}" usage() { printf 'Usage: %s [start|stop|restart|status|tail|analyze|install]\n' "$0" printf '\nDefault action: start\n' printf '\nEnvironment overrides:\n' printf ' FGAI_SYSLOG_PORT=%s\n' "$PORT" printf ' FGAI_SYSLOG_HOST=%s\n' "$HOST" printf ' FGAI_SYSLOG_FILE=%s\n' "$LOG_FILE" printf ' FGAI_LISTENER_LOG=%s\n' "$LISTENER_LOG" } activate_venv_for_script() { # Activation here affects this script process. It cannot modify the parent shell prompt. # Use "source .venv/bin/activate" manually if you want your interactive prompt to show it. # shellcheck disable=SC1091 source "$VENV_DIR/bin/activate" } install_deps() { if [ ! -x "$VENV_DIR/bin/python" ]; then printf 'Creating venv: %s\n' "$VENV_DIR" python3 -m venv "$VENV_DIR" fi activate_venv_for_script printf 'Installing/updating fgAI dependencies...\n' python -m pip install --upgrade pip python -m pip install -e "$ROOT_DIR" } is_running() { [ -f "$PID_FILE" ] && ps -p "$(cat "$PID_FILE")" >/dev/null 2>&1 } needs_privileged_port() { [ "$PORT" -lt 1024 ] && [ "${EUID:-$(id -u)}" -ne 0 ] } listener_command() { "$VENV_DIR/bin/fgai" listen-syslog \ --host "$HOST" \ --port "$PORT" \ --output "$LOG_FILE" \ --quiet } start_listener() { install_deps mkdir -p "$(dirname "$LOG_FILE")" "$(dirname "$LISTENER_LOG")" "$(dirname "$PID_FILE")" touch "$LOG_FILE" if is_running; then printf 'fgAI syslog listener already running, pid %s\n' "$(cat "$PID_FILE")" return 0 fi if needs_privileged_port; then printf 'Port %s needs elevated privileges; starting listener with sudo.\n' "$PORT" sudo nohup "$VENV_DIR/bin/fgai" listen-syslog \ --host "$HOST" \ --port "$PORT" \ --output "$LOG_FILE" \ --quiet > "$LISTENER_LOG" 2>&1 & else nohup "$VENV_DIR/bin/fgai" listen-syslog \ --host "$HOST" \ --port "$PORT" \ --output "$LOG_FILE" \ --quiet > "$LISTENER_LOG" 2>&1 & fi printf '%s\n' "$!" > "$PID_FILE" printf 'Started fgAI syslog listener, pid %s\n' "$(cat "$PID_FILE")" printf 'Input: udp://%s:%s\n' "$HOST" "$PORT" printf 'Syslog file: %s\n' "$LOG_FILE" printf 'Process log: %s\n' "$LISTENER_LOG" } stop_listener() { if ! is_running; then printf 'fgAI syslog listener is not running\n' rm -f "$PID_FILE" return 0 fi if ! kill "$(cat "$PID_FILE")" 2>/dev/null; then sudo kill "$(cat "$PID_FILE")" fi rm -f "$PID_FILE" printf 'Stopped fgAI syslog listener\n' } status_listener() { if is_running; then printf 'fgAI syslog listener running, pid %s\n' "$(cat "$PID_FILE")" printf 'Input: udp://%s:%s\n' "$HOST" "$PORT" printf 'Syslog file: %s\n' "$LOG_FILE" if command -v ss >/dev/null 2>&1; then ss -lunp 2>/dev/null | awk -v port=":$PORT" '$0 ~ port {print}' fi return 0 fi printf 'fgAI syslog listener is not running\n' return 1 } command="${1:-start}" case "$command" in start) start_listener ;; stop) stop_listener ;; restart) stop_listener start_listener ;; status) status_listener ;; tail) mkdir -p "$(dirname "$LOG_FILE")" touch "$LOG_FILE" tail -f "$LOG_FILE" ;; analyze) install_deps fgai analyze-logs --logs "$LOG_FILE" ;; install) install_deps ;; -h|--help|help) usage ;; *) usage exit 2 ;; esac