#!/usr/bin/env bash # scripts/lib/common.sh — shared helpers for all host scripts # Sourced by bootstrap.sh, install.sh, and stage scripts. # Do not execute directly. set -euo pipefail # ── Colours (auto-disable when not a tty) ────────────────────────────────── if [[ -t 2 ]]; then RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m' BOLD='\033[1m'; NC='\033[0m' else RED=''; GREEN=''; YELLOW=''; BOLD=''; NC='' fi # ── Logging ──────────────────────────────────────────────────────────────── # Use printf to avoid echo -e interpreting escape sequences in arguments. log_info() { printf "${GREEN}[INFO]${NC} %s\n" "$*"; } log_warn() { printf "${YELLOW}[WARN]${NC} %s\n" "$*" >&2; } log_error() { printf "${RED}[ERROR]${NC} %s\n" "$*" >&2; } log_section() { printf "\n${BOLD}═══ %s ═══${NC}\n" "$*"; } # ── Repo root (works from any subdirectory) ──────────────────────────────── REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || echo "$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)")" # ── Env loading ──────────────────────────────────────────────────────────── # NOTE: Sources .env directly as shell code. This is a known pattern with a # theoretical injection surface if .env contains shell commands. In practice, # .env is created from .env.example (controlled by this repo) and edited by # the operator. Defense-in-depth: parse line-by-line instead of sourcing, # but the current approach matches the broader ecosystem convention. load_env() { local env_file="${1:-${REPO_ROOT}/.env}" if [[ -f "$env_file" ]]; then # shellcheck disable=SC1091 set -a; source "$env_file"; set +a log_info "Loaded env from $env_file" else log_warn ".env not found at $env_file — variables must be set externally" fi } # ── CLI detection ────────────────────────────────────────────────────────── cmd_exists() { command -v "$1" &>/dev/null; } require_cmd() { if ! cmd_exists "$1"; then log_error "Required command not found: $1" if [[ "${2:-}" ]]; then log_error "$2" fi return 1 fi } # ── Sandbox name ─────────────────────────────────────────────────────────── get_sandbox_name() { echo "${LUMINA_SANDBOX:-hermes}" } # ── Docker check ─────────────────────────────────────────────────────────── docker_available() { cmd_exists docker && docker info &>/dev/null } # ── nemohermes check ─────────────────────────────────────────────────────── nemohermes_available() { cmd_exists nemohermes } # ── openshell check ──────────────────────────────────────────────────────── openshell_available() { cmd_exists openshell } # ── Guard: script must be run as operator (not root-only, but warn) ──────── warn_if_root() { if [[ "$(id -u)" -eq 0 ]]; then log_warn "Running as root. Some host scripts work better as a regular user with sudo access." fi }