build:usb-image — Final USB image assembly script, Ventoy config, and Hermes agent runtime structure
- build/usb-image.sh: Main USB image assembler with artifact validation, ISO building, disk image creation, and USB write support - build/ventoy.json: Ventoy configuration for multi-boot USB - src/hermes/config.yaml: Portable Hermes agent configuration - src/hermes/autorun.sh: Auto-launch script with full diagnostic pipeline - Makefile: Build system with iso/image/check/clean/write targets Generates fallback stubs for any diagnostic modules whose upstream build tasks haven't completed yet, ensuring the image boots even during active development.
This commit is contained in:
Executable
+250
@@ -0,0 +1,250 @@
|
||||
#!/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)
|
||||
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 "$@"
|
||||
Reference in New Issue
Block a user