#!/usr/bin/env bash # _common.sh — sourced by all dev-scripts. Do not run directly. set -euo pipefail # ── Colores ──────────────────────────────────────────────────────────────── RED='\033[0;31m' GRN='\033[0;32m' YLW='\033[0;33m' BLU='\033[0;34m' DIM='\033[2m' RST='\033[0m' ok() { echo -e "${GRN}✓${RST} $*"; } info() { echo -e "${BLU}→${RST} $*"; } warn() { echo -e "${YLW}!${RST} $*"; } fail() { echo -e "${RED}✗${RST} $*" >&2; exit 1; } dim() { echo -e "${DIM}$*${RST}"; } # ── Repo root ────────────────────────────────────────────────────────────── # Scripts can be called from any directory; we always operate from repo root. REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" cd "$REPO_ROOT" # ── .env loader ─────────────────────────────────────────────────────────── load_env() { local env_file="${1:-.env}" [[ -f "$env_file" ]] || fail ".env not found at $REPO_ROOT/$env_file — copy .env.example and fill it in" # Export only lines that are KEY=VALUE (skip comments and blanks) set -o allexport # shellcheck disable=SC1090 source <(grep -E '^[A-Z_][A-Z0-9_]*=.+' "$env_file") set +o allexport } # ── Go tooling ───────────────────────────────────────────────────────────── GO=${GO_BIN:-go} export PATH="$PATH:/usr/local/go/bin" command -v "$GO" &>/dev/null || fail "go not found — install Go or set GO_BIN" # ── Process helpers ──────────────────────────────────────────────────────── RUN_DIR="$REPO_ROOT/run" mkdir -p "$RUN_DIR" pid_file() { echo "$RUN_DIR/$1.pid"; } log_file() { echo "$RUN_DIR/$1.log"; } read_pid() { local f; f="$(pid_file "$1")" [[ -f "$f" ]] && cat "$f" || echo 0 } # Map agent ID to its config path by scanning agent directories. # Also scans agents/_specials/ for privileged system agents (e.g. father-bot). config_path_for() { local target_id="$1" for cfg in agents/*/config.yaml agents/_specials/*/config.yaml; do [[ -f "$cfg" ]] || continue local id # Strip quotes from value: handles both `id: foo` and `id: "foo"` id=$(grep -m1 '^ id:' "$cfg" | sed -E 's/^[^:]*:[[:space:]]*//; s/^"//; s/"$//; s/^'\''//; s/'\''$//') if [[ "$id" == "$target_id" ]]; then echo "$cfg" return fi done } # Find all PIDs of launcher processes for a given agent ID. # Searches for the actual config path in the process command line. # Returns newline-separated PIDs (may be empty). find_agent_pids() { local id="$1" local cfg; cfg="$(config_path_for "$id")" if [[ -z "$cfg" ]]; then return fi pgrep -f "launcher.*-c.*${cfg}" 2>/dev/null || true } is_running() { local id="$1" # First check PID file local pid; pid="$(read_pid "$id")" if [[ "$pid" -gt 0 ]] && kill -0 "$pid" 2>/dev/null; then return 0 fi # PID file is stale or missing — search for actual processes local pids; pids="$(find_agent_pids "$id")" if [[ -n "$pids" ]]; then # Update PID file with the first found process local first_pid; first_pid="$(echo "$pids" | head -1)" echo "$first_pid" > "$(pid_file "$id")" return 0 fi # Truly not running — clean up stale PID file [[ "$pid" -gt 0 ]] && rm -f "$(pid_file "$id")" return 1 } # Count how many instances of an agent are running. count_instances() { local id="$1" local pids; pids="$(find_agent_pids "$id")" if [[ -z "$pids" ]]; then echo 0 else echo "$pids" | wc -l fi } agent_status() { local id="$1" enabled="$2" if [[ "$enabled" != "true" ]]; then echo "disabled" elif is_launcher_running; then echo "running" else echo "stopped" fi } # ── Unified launcher helpers ─────────────────────────────────────────────── LAUNCHER_ID="launcher" launcher_pid_file() { echo "$RUN_DIR/$LAUNCHER_ID.pid"; } launcher_log_file() { echo "$RUN_DIR/$LAUNCHER_ID.log"; } read_launcher_pid() { local f; f="$(launcher_pid_file)" [[ -f "$f" ]] && cat "$f" || echo 0 } is_launcher_running() { local pid; pid="$(read_launcher_pid)" if [[ "$pid" -gt 0 ]] && kill -0 "$pid" 2>/dev/null; then return 0 fi # Fallback: search for launcher process without -c flag local pids; pids="$(pgrep -f 'launcher.*--log-level' 2>/dev/null || true)" if [[ -n "$pids" ]]; then local first_pid; first_pid="$(echo "$pids" | head -1)" echo "$first_pid" > "$(launcher_pid_file)" return 0 fi [[ "$pid" -gt 0 ]] && rm -f "$(launcher_pid_file)" return 1 } # ── Agent discovery ──────────────────────────────────────────────────────── # Prints: id|version|enabled|description (one line per agent) # Also scans agents/_specials/ for privileged system agents. list_agents_raw() { for cfg in agents/*/config.yaml agents/_specials/*/config.yaml; do [[ -f "$cfg" ]] || continue local id version enabled desc id=$(grep -m1 '^ id:' "$cfg" | awk '{print $2}') version=$(grep -m1 '^ version:' "$cfg" | awk '{print $2}' | tr -d '"') enabled=$(grep -m1 '^ enabled:' "$cfg" | awk '{print $2}') desc=$(grep -m1 '^ description:' "$cfg" | cut -d'"' -f2) [[ -n "$id" ]] && echo "${id}|${version}|${enabled}|${desc}|${cfg}" done } # ── Naming convention ───────────────────────────────────────────────────── # Normalizes an agent ID to an env-var suffix. # Convention: uppercase, hyphens → underscores. No stripping of suffixes. # "assistant-bot" → "ASSISTANT_BOT" # "asistente-2" → "ASISTENTE_2" # "devops-bot" → "DEVOPS_BOT" normalize_id() { echo "$1" | tr '[:lower:]-' '[:upper:]_' } # ── Usage helper ────────────────────────────────────────────────────────── need_arg() { [[ -n "${1:-}" ]] || { echo "Usage: $0 "; exit 1; } }