Refactor: Mission Doktor v2.0 - Doktor-style menu system
- Restructured in crumbpages-doktor.sh style - Main menu with mission categories (Basics, Advanced, Challenges) - Added Doktor Tools: System Check, Werkzeug Check, Git Status - Improved navigation and UX - .gitignore updated to allow demo logs in repo - Qdrant omitted (as requested) - Linux first, cross-platform compatible
This commit is contained in:
6
.gitignore
vendored
6
.gitignore
vendored
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user