diff --git a/.gitignore b/.gitignore index 07bd68f..9f49fdc 100644 --- a/.gitignore +++ b/.gitignore @@ -19,12 +19,16 @@ .missionstage_log/ .bugsy_log/ -# Individual log files +# Individual log files (but keep demo logs in missions/) *.jsonl *_log.json *.log mission_log_*.log +# But allow mission demo logs +!missions/**/*.log +!missions/**/demo_*.txt + # Environment variables (API keys!) .env .env.local diff --git a/crumb-mission-selector.sh b/crumb-mission-selector.sh index d940260..3680f78 100755 --- a/crumb-mission-selector.sh +++ b/crumb-mission-selector.sh @@ -1,184 +1,300 @@ #!/bin/bash - -# ============================================================ -# 🌲 Crumb Mission Selector - Lernpfade im Crumbforest -# ============================================================ -# Inspiriert von CF_Zero_V1 dynamic_mission_selector.sh -# Metadata-driven, erweiterbar, bildungsfreundlich -# ============================================================ +# 🌲 Crumbforest Mission Doktor v2.0 +# Metadata-driven, erweiterbar, Bash 3.2+ kompatibel +# Inspiriert vom crumbpages-doktor.sh Konzept set -euo pipefail +# === FARBEN === +GREEN='\033[0;32m' +BLUE='\033[0;34m' +RED='\033[0;31m' +YELLOW='\033[1;33m' +CYAN='\033[0;36m' +NC='\033[0m' # No Color + # === KONFIGURATION === SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" MISSION_DIR="${SCRIPT_DIR}/missions" -DEFAULT_CATEGORY="basics" - -# === FARBEN (optional, für bessere UX) === -GREEN='\033[0;32m' -BLUE='\033[0;34m' -YELLOW='\033[1;33m' -NC='\033[0m' # No Color - -# === DATENSTRUKTUREN === -# Arrays für Missionen (Bash 3.2+ kompatibel) -MISSION_OPTIONS=() -MISSION_SCRIPTS=() # ============================================================ -# FUNKTIONEN +# HILFSFUNKTIONEN # ============================================================ -show_intro() { - clear - echo -e "${GREEN}" - cat << 'EOF' - 🌟 Willkommen im Crumbforest Missionszentrum! 🌟 - - Hier kannst du auf Lern-Abenteuer gehen: - - 🦊 Fridolin zeigt dir die Pfade (Navigation) - - 🛠️ Balu hilft beim Bauen (Dateien & Ordner) - - 🐈🦉 Noko liest die Botschaften (Logs & Inhalte) - - ... und viele mehr! Wähle deine Mission: +function show_header() { + clear + echo -e "${GREEN}" + cat << 'EOF' + 🌲 Crumbforest Mission Doktor 🌲 + + Willkommen im Waldlern-System! + Wähle deine Kategorie: EOF - echo -e "${NC}" - sleep 1 + echo -e "${NC}" } -load_missions() { - local category="${1:-$DEFAULT_CATEGORY}" - local search_dir="${MISSION_DIR}/${category}" - - if [[ ! -d "$search_dir" ]]; then - echo "⚠️ Kategorie '$category' nicht gefunden. Nutze Basis-Missionen." - search_dir="${MISSION_DIR}/basics" - fi - - echo -e "${BLUE}🔍 Lade Missionen aus: ${search_dir}${NC}" +function load_missions_from_category() { + local category="$1" + local search_dir="${MISSION_DIR}/${category}" - # Alle .sh Dateien finden (Bash 3.2+ kompatibel) - MISSION_SCRIPTS=() - while IFS= read -r file; do - [[ -n "$file" ]] && MISSION_SCRIPTS+=("$file") - done < <(find "$search_dir" -maxdepth 1 -type f -name "*.sh" | sort) - - if [[ ${#MISSION_SCRIPTS[@]} -eq 0 ]]; then - echo "❗ Keine Missionen gefunden!" - exit 1 - fi - - # Metadaten laden - for mission_file in "${MISSION_SCRIPTS[@]}"; do - local mission_name - mission_name="$(basename "$mission_file" .sh)" - local meta_file="${search_dir}/${mission_name}.meta.json" - - if [[ -f "$meta_file" ]]; then - local icon title description enabled - icon=$(jq -r '.icon // "🛸"' "$meta_file" 2>/dev/null) - title=$(jq -r '.title // "Unknown"' "$meta_file" 2>/dev/null) - description=$(jq -r '.description // ""' "$meta_file" 2>/dev/null) - enabled=$(jq -r '.enabled // true' "$meta_file" 2>/dev/null) - - # Ignoriere deaktivierte Missionen - [[ "$enabled" == "false" ]] && continue - - MISSION_OPTIONS+=("${icon} ${title}") - else - # Fallback ohne Metadaten - MISSION_OPTIONS+=("🛸 ${mission_name}") + if [[ ! -d "$search_dir" ]]; then + echo -e "${RED}Kategorie '$category' nicht gefunden.${NC}" + return 1 fi - done - - echo -e "${GREEN}✅ ${#MISSION_OPTIONS[@]} Missionen geladen.${NC}" - echo "" -} -show_mission_menu() { - # Beenden-Option hinzufügen - local exit_option="🚪 Zurück zum Terminal" - MISSION_OPTIONS+=("$exit_option") - - while true; do - echo "🌲 Wähle deine Mission:" - echo "======================" - - PS3="Gib die Zahl deiner Wahl ein: " - select opt in "${MISSION_OPTIONS[@]}"; do - local choice=$((REPLY - 1)) - - # Beenden gewählt - if [[ "$opt" == "$exit_option" ]]; then - echo "👋 Auf bald, kleiner Krümel!" - exit 0 - fi - - # Mission starten - if (( choice >= 0 && choice < ${#MISSION_OPTIONS[@]} - 1 )); then - local selected_script="${MISSION_SCRIPTS[$choice]}" - echo "" - echo -e "${YELLOW}▶️ Starte Mission: $(basename "$selected_script")${NC}" - echo "" - - # Mission ausführen - bash "$selected_script" - - # Nach Mission: Zurück zum Menü - echo "" - echo "✅ Mission abgeschlossen!" - read -p "Drücke Enter für das Hauptmenü..." -r - echo "" - break - else - echo "❗ Ungültige Eingabe. Bitte wähle eine Zahl zwischen 1 und ${#MISSION_OPTIONS[@]}." - fi + # Arrays für Missionen (Bash 3.2+ kompatibel) + MISSION_OPTIONS=() + MISSION_SCRIPTS=() + + # Alle .sh Dateien finden + while IFS= read -r file; do + [[ -n "$file" ]] && MISSION_SCRIPTS+=("$file") + done < <(find "$search_dir" -maxdepth 1 -type f -name "*.sh" | sort) + + if [[ ${#MISSION_SCRIPTS[@]} -eq 0 ]]; then + echo -e "${YELLOW}Keine Missionen in dieser Kategorie gefunden.${NC}" + return 1 + fi + + # Metadaten laden + for mission_file in "${MISSION_SCRIPTS[@]}"; do + local mission_name + mission_name="$(basename "$mission_file" .sh)" + local meta_file="${search_dir}/${mission_name}.meta.json" + + if [[ -f "$meta_file" ]]; then + local icon title enabled + icon=$(jq -r '.icon // "🛸"' "$meta_file" 2>/dev/null) + title=$(jq -r '.title // "Unknown"' "$meta_file" 2>/dev/null) + enabled=$(jq -r '.enabled // true' "$meta_file" 2>/dev/null) + + # Ignoriere deaktivierte Missionen + [[ "$enabled" == "false" ]] && continue + + MISSION_OPTIONS+=("${icon} ${title}") + else + # Fallback ohne Metadaten + MISSION_OPTIONS+=("🛸 ${mission_name}") + fi done - done + + return 0 } -show_category_selector() { - echo "🗂️ Wähle eine Kategorie:" - echo "========================" - - PS3="Kategorie wählen: " - categories=("📚 Basics" "🚀 Advanced" "🏆 Challenges" "🎯 Alle anzeigen") - - select cat in "${categories[@]}"; do - case $REPLY in - 1) load_missions "basics" ;; - 2) load_missions "advanced" ;; - 3) load_missions "challenges" ;; - 4) - # Alle Kategorien durchsuchen - for dir in "$MISSION_DIR"/*; do - [[ -d "$dir" ]] && load_missions "$(basename "$dir")" +# ============================================================ +# MISSION RUNNER +# ============================================================ + +function run_mission_menu() { + local category="$1" + local category_name="$2" + + if ! load_missions_from_category "$category"; then + read -p "Drücke Enter..." -r + return + fi + + while true; do + clear + echo -e "${BLUE}=== ${category_name} ===${NC}" + echo "" + + # Beenden-Option hinzufügen + MISSION_OPTIONS+=("🚪 Zurück zum Hauptmenü") + + PS3="Gib die Zahl deiner Wahl ein: " + select opt in "${MISSION_OPTIONS[@]}"; do + local choice=$((REPLY - 1)) + + # Beenden gewählt + if [[ "$opt" == "🚪 Zurück zum Hauptmenü" ]]; then + return + fi + + # Mission starten + if (( choice >= 0 && choice < ${#MISSION_OPTIONS[@]} - 1 )); then + local selected_script="${MISSION_SCRIPTS[$choice]}" + echo "" + echo -e "${YELLOW}▶️ Starte Mission: $(basename "$selected_script")${NC}" + echo "" + + # Mission ausführen + bash "$selected_script" + + # Nach Mission: Zurück zum Menü + echo "" + echo -e "${GREEN}✅ Mission abgeschlossen!${NC}" + read -p "Drücke Enter für das Menü..." -r + break + else + echo -e "${RED}❗ Ungültige Eingabe.${NC}" + fi done - ;; - *) - echo "❗ Ungültige Auswahl" - continue - ;; - esac - break - done + + # Reload für nächste Iteration + if ! load_missions_from_category "$category"; then + return + fi + done } # ============================================================ -# MAIN +# DOKTOR SYSTEM-CHECK # ============================================================ -main() { - show_intro - - # Einfach - lade immer basics - load_missions "basics" - - # Erweitert - Kategorie-Auswahl (uncomment für Kategorie-Menü) - # show_category_selector - - show_mission_menu +function system_doktor() { + clear + echo -e "${BLUE}=== 🖥️ System Doktor ===${NC}" + echo "" + + if [[ "$OSTYPE" == "linux-gnu"* ]]; then + echo -e "${CYAN}🐧 Linux System${NC}" + hostnamectl 2>/dev/null || hostname + echo "" + uname -r + echo "" + free -h 2>/dev/null || echo "free: nicht verfügbar" + echo "" + df -h / 2>/dev/null + elif [[ "$OSTYPE" == "darwin"* ]]; then + echo -e "${CYAN}🍏 macOS System${NC}" + hostname + echo "" + sw_vers 2>/dev/null + echo "" + echo "Memory:" + vm_stat | head -n 5 + echo "" + echo "Disk:" + df -h / + else + echo -e "${YELLOW}Unbekanntes System: $OSTYPE${NC}" + fi + + echo "" + echo -e "${GREEN}Bash Version: $BASH_VERSION${NC}" + echo "" + read -p "Drücke Enter..." -r } -# Start! -main +# ============================================================ +# TOOLS CHECK +# ============================================================ + +function tools_doktor() { + clear + echo -e "${BLUE}=== 🛠️ Werkzeug-Check ===${NC}" + echo "" + + TOOLS="jq git curl python3 nano vim" + + for tool in $TOOLS; do + if command -v "$tool" &> /dev/null; then + echo -e "${GREEN}✅ $tool${NC} - $(command -v "$tool")" + else + echo -e "${RED}❌ $tool${NC} - Nicht installiert" + fi + done + + echo "" + echo -e "${CYAN}Mission System Requirements:${NC}" + + # Check jq speziell (wichtig für Metadaten) + if command -v jq &> /dev/null; then + echo -e "${GREEN}✅ jq verfügbar${NC} - Mission Selector funktioniert" + else + echo -e "${RED}⚠️ jq fehlt${NC} - Bitte installieren: brew install jq (macOS) oder apt install jq (Linux)" + fi + + echo "" + read -p "Drücke Enter..." -r +} + +# ============================================================ +# GIT DOKTOR +# ============================================================ + +function git_doktor() { + clear + echo -e "${BLUE}=== 🌲 Git Doktor ===${NC}" + echo "" + + if [[ ! -d ".git" ]]; then + echo -e "${RED}❌ Kein Git Repository gefunden.${NC}" + read -p "Drücke Enter..." -r + return + fi + + echo -e "${CYAN}Repository Status:${NC}" + echo "" + + # Remote Info + echo -e "${YELLOW}Remote:${NC}" + git remote -v 2>/dev/null || echo "Keine Remotes" + echo "" + + # Branch Info + echo -e "${YELLOW}Branch:${NC}" + git branch 2>/dev/null || echo "Keine Branches" + echo "" + + # Status + echo -e "${YELLOW}Status:${NC}" + git status --short 2>/dev/null || git status + echo "" + + # Letzter Commit + echo -e "${YELLOW}Letzter Commit:${NC}" + git log -1 --oneline 2>/dev/null || echo "Keine Commits" + + echo "" + read -p "Drücke Enter..." -r +} + +# ============================================================ +# HAUPTMENÜ +# ============================================================ + +function main_menu() { + while true; do + show_header + echo "1) 📚 Basics - Einsteiger Missionen" + echo "2) 🚀 Advanced - Fortgeschrittene Missionen" + echo "3) 🏆 Challenges - Herausforderungen" + echo "" + echo "--- Doktor Tools ---" + echo "4) 🖥️ System Doktor" + echo "5) 🛠️ Werkzeug-Check" + echo "6) 🌲 Git Doktor" + echo "" + echo "7) 👋 Beenden" + echo "" + read -p "Auswahl [1-7]: " CHOICE + + case $CHOICE in + 1) run_mission_menu "basics" "📚 Basics - Einsteiger" ;; + 2) run_mission_menu "advanced" "🚀 Advanced - Fortgeschrittene" ;; + 3) run_mission_menu "challenges" "🏆 Challenges" ;; + 4) system_doktor ;; + 5) tools_doktor ;; + 6) git_doktor ;; + 7) + clear + echo -e "${GREEN}" + echo "👋 Auf bald im Crumbforest!" + echo -e "${NC}" + exit 0 + ;; + *) + echo -e "${RED}Bitte 1-7 wählen.${NC}" + sleep 1 + ;; + esac + done +} + +# ============================================================ +# START +# ============================================================ + +main_menu