#!/bin/sh # ============================================================================== # Hermes Portable Rescue — Auto-Launch Script (Source) # ============================================================================== # # This is the master auto-launch script for the Hermes Portable Rescue USB. # It runs when the rescue environment boots and orchestrates the entire # diagnostic workflow. # # Design: # - Detects the boot filesystem and mounts the Hermes partition # - Creates a report directory and starts logging # - Runs diagnostics in dependency order (inventory → analysis → fix) # - Launches the Hermes agent for LLM-powered interpretation # - Falls back to a diagnostic shell if the agent isn't available # # Environment variables (set by build/usb-image.sh or the boot environment): # HERMES_DIR — Root of the Hermes runtime filesystem # CONFIG — Path to config.yaml # REPORT_DIR — Where to save diagnostic reports # BOOT_MODE — 'live' (default), 'safe', 'recovery' # # ============================================================================== set -e # ─── Configuration ──────────────────────────────────────────────────────────── HERMES_DIR="${HERMES_DIR:-/hermes}" CONFIG="${CONFIG:-${HERMES_DIR}/config.yaml}" REPORT_DIR="${REPORT_DIR:-${HERMES_DIR}/reports}" LOG_FILE="${LOG_FILE:-${REPORT_DIR}/session.log}" BOOT_MODE="${BOOT_MODE:-live}" # ─── Utility Functions ──────────────────────────────────────────────────────── timestamp() { date "+%Y-%m-%d %H:%M:%S" } log() { local level="$1" shift echo "[$(timestamp)] [${level}] $*" | tee -a "${LOG_FILE}" } info() { log "INFO" "$@"; } warn() { log "WARN" "$@" >&2; } error() { log "ERROR" "$@" >&2; } # ─── Banner ──────────────────────────────────────────────────────────────────── print_banner() { cat << 'BANNER' ╔═══════════════════════════════════════════════════════════════╗ ║ ║ ║ ██╗ ██╗███████╗██████╗ ███╗ ███╗ ║ ║ ██║ ██║██╔════╝██╔══██╗████╗ ████║ ║ ║ ███████║█████╗ ██████╔╝██╔████╔██║ ║ ║ ██╔══██║██╔══╝ ██╔══██╗██║╚██╔╝██║ ║ ║ ██║ ██║███████╗██║ ██║██║ ╚═╝ ██║ ║ ║ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝ ║ ║ ║ ║ ┌─────────┐ ┌──────────┐ ┌──────────────────┐ ║ ║ │ SCAN │→ │ ANALYZE │→ │ RECOMMEND/FIX │ ║ ║ └─────────┘ └──────────┘ └──────────────────┘ ║ ║ ║ ║ Hermes Portable Rescue v1.0.0 ║ ║ AI-driven Windows PC diagnostic & repair toolkit ║ ║ ║ ╚═══════════════════════════════════════════════════════════════╝ BANNER } # ─── Filesystem Setup ───────────────────────────────────────────────────────── mount_windows_partition() { local windows_mount="/mnt/c" mkdir -p "${windows_mount}" 2>/dev/null || true # Try common Windows partitions for device in /dev/sda1 /dev/sda2 /dev/nvme0n1p1 /dev/nvme0n1p2 /dev/mmcblk0p1; do if [ -b "${device}" ]; then local fstype fstype="$(blkid -o value -s TYPE "${device}" 2>/dev/null || echo '')" case "${fstype}" in ntfs) if mount -t ntfs-3g "${device}" "${windows_mount}" 2>/dev/null; then info "Mounted Windows partition: ${device} → ${windows_mount}" return 0 fi ;; ext4|vfat) # Not a Windows partition (or could be EFI system partition) ;; esac fi done warn "No Windows partition found." return 1 } # ─── Diagnostic Pipeline ────────────────────────────────────────────────────── run_script() { local script="$1" local report_name="$2" local report_file="${REPORT_DIR}/${report_name}" if [ ! -f "${script}" ]; then warn "Script not found: ${script}" return 1 fi info "Running: ${script}" if python3 "${script}" > "${report_file}" 2>&1; then info " ✓ ${report_name} complete (exit 0)" return 0 else local rc=$? if [ "${rc}" -eq 1 ]; then # Component unavailable (stub) info " ∼ ${report_name}: component unavailable" elif [ "${rc}" -eq 2 ]; then # Error during diagnosis warn " ✗ ${report_name}: diagnostic error (exit ${rc})" else warn " ✗ ${report_name}: failed with exit code ${rc}" fi return ${rc} fi } run_diagnostics() { info "Starting diagnostic pipeline..." echo "───────────────────────────────────────────────────────" >> "${LOG_FILE}" # Phase 1: Hardware inventory (independent, runs first) run_script "${HERMES_DIR}/scripts/hardware.py" "01-hardware.txt" # Phase 2: BSOD analysis (needs hardware inventory context) run_script "${HERMES_DIR}/scripts/bsod.py" "02-bsod-analysis.txt" # Phase 3: Driver update check (needs hardware inventory) run_script "${HERMES_DIR}/scripts/drivers.py" "03-drivers.txt" # Phase 4: Stress testing (manual/safe mode only) if [ "${BOOT_MODE}" = "recovery" ]; then info "Skipping stress tests in recovery mode." elif grep -q '"enabled": true' "${CONFIG}" 2>/dev/null || [ -n "${RUN_STRESS_TESTS}" ]; then run_script "${HERMES_DIR}/scripts/stress.py" "04-stress.txt" else info "Stress tests disabled (enable in config or set RUN_STRESS_TESTS=1)" fi # Phase 5: Backup/restore (manual activation) — stub placeholder # if [ -n "${RUN_BACKUP}" ]; then # run_script "${HERMES_DIR}/scripts/backup.py" "05-backup.txt" # fi echo "───────────────────────────────────────────────────────" >> "${LOG_FILE}" info "Diagnostic pipeline complete." } # ─── Agent Launch ───────────────────────────────────────────────────────────── launch_agent() { info "Starting Hermes agent..." if [ -f "${HERMES_DIR}/agent/hermes" ]; then exec "${HERMES_DIR}/agent/hermes" --config "${CONFIG}" elif command -v hermes &>/dev/null; then exec hermes --config "${CONFIG}" else error "Hermes agent not found on PATH or in ${HERMES_DIR}/agent/." return 1 fi } start_diagnostic_shell() { cat << 'SHELL' ╔═══════════════════════════════════════════════════════════════╗ ║ DIAGNOSTIC SHELL ║ ║ Hermes agent not available — running in manual mode. ║ ╚═══════════════════════════════════════════════════════════════╝ Available diagnostic scripts: python3 /hermes/scripts/hardware.py — Hardware inventory python3 /hermes/scripts/bsod.py — BSOD minidump analysis python3 /hermes/scripts/drivers.py — Driver scanner python3 /hermes/scripts/stress.py — Stress testing python3 /hermes/scripts/backup.py — Backup/restore Reports saved to: /hermes/reports/ Type 'exit' to shut down. SHELL exec /bin/sh } # ─── Main ───────────────────────────────────────────────────────────────────── main() { print_banner # Ensure report dir exists mkdir -p "${REPORT_DIR}" info "Hermes Portable Rescue v1.0.0 — Boot mode: ${BOOT_MODE}" info "Config: ${CONFIG}" info "Reports: ${REPORT_DIR}" info "Log: ${LOG_FILE}" echo "" # Optional: mount Windows partition for access to minidumps, etc. if [ "${MOUNT_WINDOWS}" != "no" ]; then mount_windows_partition || true fi # Run diagnostic pipeline if [ "${SKIP_DIAGNOSTICS}" != "1" ]; then run_diagnostics fi # Print report summary if [ -d "${REPORT_DIR}" ]; then echo "" info "Diagnostic reports:" for report in "${REPORT_DIR}"/*.txt; do if [ -f "${report}" ]; then local rname rname=$(basename "${report}") echo " ${rname} ($(wc -l < "${report}") lines)" fi done echo "" fi # Launch agent or fall back to diagnostic shell if ! launch_agent; then start_diagnostic_shell fi } main "$@"