#!/bin/bash # 🌲 WaldwΓ€chter Library - AI Assistants for Crumbforest Missions # Source this file to make all AI characters available as commands # Determine the repo root directory (lib/ is inside repo root) # Support both bash and zsh if [[ -n "$BASH_VERSION" ]]; then # Bash: use BASH_SOURCE SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" elif [[ -n "$ZSH_VERSION" ]]; then # Zsh: use ${(%):-%x} to get the script path SCRIPT_DIR="$(cd "$(dirname "${(%):-%x}")" && pwd)" else # Fallback: use $0 (may not work when sourced) SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" fi WALDWAECHTER_DIR="$(dirname "$SCRIPT_DIR")" ROLES_DIR="${WALDWAECHTER_DIR}/crumbforest_roles" # Set logs directory in repo export CRUMB_LOGS_DIR="${WALDWAECHTER_DIR}/logs" mkdir -p "${CRUMB_LOGS_DIR}" # Load .env if it exists ENV_FILE="${WALDWAECHTER_DIR}/.env" if [[ -f "${ENV_FILE}" ]]; then set -a source "${ENV_FILE}" set +a fi # πŸ¦‰ Maya-Eule - Die weise Eule mit GedΓ€chtnis function mayaeule() { "${ROLES_DIR}/mayaeule_zero.sh" "$@" } # πŸ”§ Deepbit - Bash-ErklΓ€rer function deepbit() { "${ROLES_DIR}/deepbit_zero.sh" "$@" } # πŸ› Bugsy - Debugging-Helfer function bugsy() { "${ROLES_DIR}/bugsy_zero.sh" "$@" } # βœ‚οΈ Schnippsi - Shell-Helfer function schnippsi() { "${ROLES_DIR}/schnippsi_zero.sh" "$@" } # πŸ“„ Templatus - HTML/Template-Helfer function templatus() { "${ROLES_DIR}/templatus_zero.sh" "$@" } # πŸ“Š Tobi - JSON/Daten-Helfer function tobi() { "${ROLES_DIR}/tobi_zero.sh" "$@" } # πŸ”§ SchraubbΓ€r - Schweres GerΓ€t, Schweißen, Werkzeug function schraubaer() { "${ROLES_DIR}/schraubaer_zero_final.sh" "$@" } # 🐌 Schnecki - Elektronik-Bastler function schnecki() { "${ROLES_DIR}/schnecki_zero.sh" "$@" } # === DAS DREIECK === # 🐘 DumboSQL - Nie vergessend function dumbosql() { "${ROLES_DIR}/dumbosql_zero.sh" "$@" } # 🦊 FunkFox - Bash Rapper function funkfox() { "${ROLES_DIR}/funkfox_zero.sh" "$@" } # πŸ•ŠοΈ Taichi Taube - Balance & Spirale function taichitaube() { "${ROLES_DIR}/taichitaube_zero.sh" "$@" } # === DIE RESTLICHEN WALDWΓ„CHTER === # 🐍 SnakePy - Python Guide function snakepy() { "${ROLES_DIR}/snakepy_zero.sh" "$@" } # πŸ§“ PepperPHP - Structure Mentor function pepperphp() { "${ROLES_DIR}/pepperphp_zero.sh" "$@" } # πŸ¦€ CrabbyRust - Security Guardian function crabbyrust() { "${ROLES_DIR}/crabbyrust_zero.sh" "$@" } # πŸ•·οΈ Spider - Network Feeler function spider() { "${ROLES_DIR}/spider_zero.sh" "$@" } # 🧭 Vektor - Point-to-Point Guide function vektor() { "${ROLES_DIR}/vektor_zero.sh" "$@" } # πŸ‘Ύ ASCII-Monster - Terminal Artist function asciimonster() { "${ROLES_DIR}/asciimonster_zero.sh" "$@" } # === CREW COMMANDS === # πŸ“Š crew_tokens - Token-Verbrauch aller WaldwΓ€chter function crew_tokens() { # Force C locale for consistent number formatting export LC_NUMERIC=C echo "πŸ“Š CrumbCrew Token-Verbrauch" echo "" echo "" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" local total_tokens=0 local total_cost=0 local crew_count=0 # Alle token_log.json Dateien finden und auswerten for token_file in "${CRUMB_LOGS_DIR}"/*/token_log.json; do if [[ -f "$token_file" ]]; then local character=$(basename "$(dirname "$token_file")") # Tokens und Kosten aus JSON extrahieren (skip erste Zeile falls es [] ist) local char_tokens=$(grep -v '^\[\]$' "$token_file" | jq -s 'map(.usage.total_tokens // 0) | add // 0' 2>/dev/null || echo 0) local char_cost=$(grep -v '^\[\]$' "$token_file" | jq -s 'map(.usage.cost // 0) | add // 0' 2>/dev/null || echo 0) if [[ $char_tokens -gt 0 ]]; then printf " %-15s %8d tokens (~\$%.6f)\n" "$character:" "$char_tokens" "$char_cost" total_tokens=$((total_tokens + char_tokens)) total_cost=$(echo "$total_cost + $char_cost" | bc -l) crew_count=$((crew_count + 1)) fi fi done echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" if [[ $total_tokens -gt 0 ]]; then printf " Gesamt: %d Tokens (~\$%.6f)\n" "$total_tokens" "$total_cost" printf " %d WaldwΓ€chter aktiv 🌲\n" "$crew_count" else echo " Gesamt: 0 Tokens" echo " Jede Frage ist wertvoll 🌲" fi echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" # Restore locale unset LC_NUMERIC } # πŸ“‹ crew_status - Status aller WaldwΓ€chter function crew_status() { echo "πŸ“‹ CrumbCrew Status (17 WaldwΓ€chter)" echo "" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" local chars=("mayaeule" "deepbit" "bugsy" "schnippsi" "templatus" "tobi" "schraubaer" "schnecki" "dumbosql" "funkfox" "taichitaube" "snakepy" "pepperphp" "crabbyrust" "spider" "vektor" "asciimonster") for char in "${chars[@]}"; do local token_file="${CRUMB_LOGS_DIR}/${char}/token_log.json" if [[ -f "$token_file" ]] && grep -q -v '^\[\]$' "$token_file" 2>/dev/null; then local last_used=$(grep -v '^\[\]$' "$token_file" | tail -1 | jq -r '.zeit // "unknown"' 2>/dev/null || echo "unknown") printf " βœ… %-15s (zuletzt: %s)\n" "$char" "$last_used" else printf " βšͺ %-15s (noch nicht genutzt)\n" "$char" fi done echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" } # 🧠 crew_memory - Erinnerungen durchsuchen function crew_memory() { local query="$1" if [[ -z "$query" ]]; then echo "🧠 Crew Memory - Log-basiertes GedΓ€chtnis" echo "" echo "Verwendung: crew_memory " echo "" echo "Beispiele:" echo " crew_memory 'LED'" echo " crew_memory 'sensor'" echo "" echo "Durchsucht alle WaldwΓ€chter-Logs nach dem Begriff." return fi echo "🧠 Suche nach: '$query'" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" local found=0 for history_file in "${CRUMB_LOGS_DIR}"/*/*_history.json; do if [[ -f "$history_file" ]]; then local character=$(basename "$(dirname "$history_file")") # Suche mit jq direkt in der JSON-Struktur (case-insensitive) local matches=$(jq -r --arg query "$query" '.[] | select(.content | test($query; "i")) | .content' "$history_file" 2>/dev/null) if [[ -n "$matches" ]]; then echo "" echo "πŸ“ $character:" # Zeige maximal die ersten 3 Zeilen jedes Matches mit EinrΓΌckung echo "$matches" | head -5 | sed 's/^/ /' found=$((found + 1)) fi fi done echo "" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" if [[ $found -gt 0 ]]; then echo " Gefunden in $found WaldwΓ€chter-Logs" else echo " Keine Treffer gefunden" fi } # 🩺 crew_doctor - System-Diagnose function crew_doctor() { echo "🩺 CrumbCrew System-Diagnose" echo "" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "" local issues=0 # 1. Waldwaechter.sh Version Check echo "πŸ“‹ Checking waldwaechter.sh..." local lib_file="${WALDWAECHTER_DIR}/lib/waldwaechter.sh" if [[ -f "$lib_file" ]]; then local lib_mtime=$(stat -f "%m" "$lib_file" 2>/dev/null || stat -c "%Y" "$lib_file" 2>/dev/null) local loaded_check_var="WALDWAECHTER_LOADED_${lib_mtime}" # Indirect variable expansion (bash: ${!var}, zsh: ${(P)var}) local loaded_value="" if [[ -n "$BASH_VERSION" ]]; then loaded_value="${!loaded_check_var}" elif [[ -n "$ZSH_VERSION" ]]; then loaded_value="${(P)loaded_check_var}" fi if [[ -z "$loaded_value" ]]; then echo " ⚠️ waldwaechter.sh wurde aktualisiert!" echo " β†’ Bitte neu laden: source lib/waldwaechter.sh" issues=$((issues + 1)) else echo " βœ… waldwaechter.sh ist aktuell" fi else echo " ❌ waldwaechter.sh nicht gefunden!" issues=$((issues + 1)) fi # 2. CRUMB_LOGS_DIR Check echo "" echo "πŸ“‚ Checking CRUMB_LOGS_DIR..." if [[ -d "$CRUMB_LOGS_DIR" ]]; then echo " βœ… $CRUMB_LOGS_DIR existiert" # PrΓΌfe ob es der richtige Pfad ist (sollte im Repo sein) if [[ "$CRUMB_LOGS_DIR" == *"CF_Zero_V1/logs"* ]]; then echo " βœ… Pfad sieht korrekt aus" else echo " ⚠️ Pfad sieht ungewΓΆhnlich aus: $CRUMB_LOGS_DIR" echo " Erwartet: .../CF_Zero_V1/logs" issues=$((issues + 1)) fi else echo " ❌ $CRUMB_LOGS_DIR existiert nicht!" issues=$((issues + 1)) fi # 3. Character Scripts Check echo "" echo "🌲 Checking 17 WaldwΓ€chter Scripts..." local expected_chars=("mayaeule" "deepbit" "bugsy" "schnippsi" "templatus" "tobi" "schraubaer" "schnecki" "dumbosql" "funkfox" "taichitaube" "snakepy" "pepperphp" "crabbyrust" "spider" "vektor" "asciimonster") local missing_count=0 for char in "${expected_chars[@]}"; do local script="${ROLES_DIR}/${char}_zero.sh" [[ "$char" == "schraubaer" ]] && script="${ROLES_DIR}/schraubaer_zero_final.sh" if [[ ! -f "$script" ]]; then echo " ❌ $char Script fehlt!" missing_count=$((missing_count + 1)) fi done if [[ $missing_count -eq 0 ]]; then echo " βœ… Alle 17 WaldwΓ€chter Scripts vorhanden" else echo " ❌ $missing_count Scripts fehlen!" issues=$((issues + 1)) fi # 4. Dependencies Check echo "" echo "πŸ”§ Checking Dependencies..." local deps_ok=0 for cmd in jq bc curl; do if command -v "$cmd" &> /dev/null; then echo " βœ… $cmd verfΓΌgbar" deps_ok=$((deps_ok + 1)) else echo " ❌ $cmd fehlt!" issues=$((issues + 1)) fi done # 5. Token-Logging Check echo "" echo "πŸ“Š Checking Token-Logging..." local scripts_with_logging=$(grep -l "token_log.json" "${ROLES_DIR}"/*.sh 2>/dev/null | wc -l | tr -d ' ') if [[ $scripts_with_logging -eq 17 ]]; then echo " βœ… Alle 17 Scripts haben Token-Logging" else echo " ⚠️ Nur $scripts_with_logging/17 Scripts haben Token-Logging" issues=$((issues + 1)) fi # 6. API Key Check echo "" echo "πŸ”‘ Checking API Key..." if [[ -n "$OPENROUTER_API_KEY" ]]; then echo " βœ… OPENROUTER_API_KEY gesetzt" else echo " ⚠️ OPENROUTER_API_KEY nicht gesetzt" echo " β†’ Bitte in .env konfigurieren" issues=$((issues + 1)) fi # Summary echo "" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" if [[ $issues -eq 0 ]]; then echo " βœ… Alle Checks bestanden! System gesund πŸ’š" else echo " ⚠️ $issues Problem(e) gefunden" echo " Bitte oben genannte Punkte beheben" fi echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" } # πŸ” crew_syntax - Syntax Check aller Scripts function crew_syntax() { echo "πŸ” CrumbCrew Syntax Check" echo "" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "" local errors=0 local checked=0 echo "PrΓΌfe WaldwΓ€chter Scripts..." echo "" # Check lib/waldwaechter.sh if bash -n "${WALDWAECHTER_DIR}/lib/waldwaechter.sh" 2>/dev/null; then echo " βœ… lib/waldwaechter.sh" else echo " ❌ lib/waldwaechter.sh - SYNTAX ERROR!" bash -n "${WALDWAECHTER_DIR}/lib/waldwaechter.sh" errors=$((errors + 1)) fi checked=$((checked + 1)) # Check all character scripts for script in "${ROLES_DIR}"/*_zero*.sh; do if [[ -f "$script" ]]; then local name=$(basename "$script") if bash -n "$script" 2>/dev/null; then echo " βœ… $name" else echo " ❌ $name - SYNTAX ERROR!" echo "" bash -n "$script" 2>&1 | sed 's/^/ /' echo "" errors=$((errors + 1)) fi checked=$((checked + 1)) fi done # Check mission scripts (optional) echo "" echo "PrΓΌfe Mission Scripts..." echo "" for script in "${WALDWAECHTER_DIR}/missions"/*/*.sh; do if [[ -f "$script" ]]; then local name=$(basename "$script") if bash -n "$script" 2>/dev/null; then echo " βœ… $name" else echo " ❌ $name - SYNTAX ERROR!" errors=$((errors + 1)) fi checked=$((checked + 1)) fi done echo "" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" if [[ $errors -eq 0 ]]; then echo " βœ… $checked Scripts geprΓΌft - Keine Syntax-Fehler! πŸ’š" else echo " ❌ $errors von $checked Scripts haben Syntax-Fehler" fi echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" } # ❓ crew_help - Hilfe fΓΌr Crew-Befehle function crew_help() { cat << 'EOF' 🌲 CrumbCrew Befehle ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Crew-Verwaltung: crew_help Diese Hilfe anzeigen crew_status Status aller 17 WaldwΓ€chter crew_tokens Token-Verbrauch ALLER Charaktere (Input) crew_memo Kreative KrΓΌmel anzeigen (Output) crew_memory Erinnerungen durchsuchen crew_doctor System-Diagnose (Version, Pfade, Dependencies) crew_syntax Syntax Check aller Scripts KrΓΌmel-Tracking: crumb_memo Kreativen Link festhalten (Mixcloud, Git, etc.) crew_memo Alle kreativen KrΓΌmel anzeigen Einzelne WaldwΓ€chter: πŸ”Ί Das Dreieck (Foundation): dumbosql SQL & Datenstrukturen funkfox Bash im Beat taichitaube Balance & Spirale πŸ”§ Hardware-Team: tobi Elektronik-Theorie (CapaciTobi) schnecki Elektronik-Basteln schraubaer Mechanik & Werkzeug πŸ’» Code-Team: snakepy Python Guide pepperphp Structure Mentor crabbyrust Security Guardian spider Network Feeler 🎨 UI-Team: schnippsi CSS & Styling templatus Template-Master asciimonster Terminal Artist 🧭 System-Team: mayaeule Weise Eule deepbit Bash-ErklΓ€rer bugsy Debugging-Helfer vektor Navigation ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Beispiele: funkfox "ErklΓ€re mir Pipes im Flow!" crew_tokens crew_memory "LED" "Was kostet die Frage eines Kindes?" πŸ’š EOF } # πŸ“ crumb_memo - Kreative Output-KrΓΌmel festhalten function crumb_memo() { local link="$1" local notiz="${2:-}" if [[ -z "$link" ]]; then echo "πŸ“ Crumb Memo - Kreative Output-KrΓΌmel" echo "" echo "Verwendung: crumb_memo [notiz]" echo "" echo "Beispiele:" echo " crumb_memo \"https://mixcloud.com/digfafunk/new-mix\"" echo " crumb_memo \"https://github.com/user/repo\" \"Neues Feature\"" echo " crumb_memo \"https://soundcloud.com/artist/track\"" echo " crumb_memo \"https://youtube.com/watch?v=xyz\" \"Tutorial\"" echo "" echo "Zeige alle KrΓΌmel mit: crew_memo" return fi # Memo-Datei local memo_file="${CRUMB_LOGS_DIR}/crumb_memo.json" mkdir -p "${CRUMB_LOGS_DIR}" # Initialisiere Datei wenn nicht vorhanden if [[ ! -f "$memo_file" ]]; then echo "[]" > "$memo_file" fi # Erkenne Typ aus URL local typ="link" if [[ "$link" =~ mixcloud\.com ]]; then typ="mixcloud" elif [[ "$link" =~ soundcloud\.com ]]; then typ="soundcloud" elif [[ "$link" =~ (youtube\.com|youtu\.be) ]]; then typ="youtube" elif [[ "$link" =~ (github\.com|gitlab\.com) ]]; then typ="git" fi # Zeitstempel local zeit=$(date '+%Y-%m-%d %H:%M:%S') # Erstelle JSON-Eintrag local entry=$(jq -n \ --arg zeit "$zeit" \ --arg link "$link" \ --arg typ "$typ" \ --arg notiz "$notiz" \ '{zeit: $zeit, link: $link, typ: $typ, notiz: $notiz}') # FΓΌge zur Datei hinzu (append) if [[ -s "$memo_file" ]]; then # Datei hat Inhalt - fΓΌge zum Array hinzu jq ". += [$entry]" "$memo_file" > "${memo_file}.tmp" && mv "${memo_file}.tmp" "$memo_file" else # Datei ist leer - erstelle Array echo "[$entry]" > "$memo_file" fi # Icon je nach Typ local icon="πŸ”—" case "$typ" in mixcloud) icon="🎧" ;; soundcloud) icon="πŸ”Š" ;; youtube) icon="πŸ“Ή" ;; git) icon="πŸ’Ύ" ;; esac echo "$icon KrΓΌmel gespeichert: $typ" echo " $link" if [[ -n "$notiz" ]]; then echo " πŸ“ $notiz" fi } # πŸ“œ crew_memo - Zeige alle kreativen KrΓΌmel function crew_memo() { local memo_file="${CRUMB_LOGS_DIR}/crumb_memo.json" echo "πŸ“œ Crumb Memo - Deine kreativen KrΓΌmel" echo "" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" if [[ ! -f "$memo_file" ]] || [[ ! -s "$memo_file" ]]; then echo " Noch keine KrΓΌmel gespeichert." echo "" echo " FΓΌge welche hinzu mit:" echo " crumb_memo \"https://mixcloud.com/digfafunk/...\"" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" return fi # ZΓ€hle EintrΓ€ge pro Typ local total=$(jq 'length' "$memo_file") local mixcloud=$(jq '[.[] | select(.typ == "mixcloud")] | length' "$memo_file") local soundcloud=$(jq '[.[] | select(.typ == "soundcloud")] | length' "$memo_file") local youtube=$(jq '[.[] | select(.typ == "youtube")] | length' "$memo_file") local git=$(jq '[.[] | select(.typ == "git")] | length' "$memo_file") # Zeige letzte 10 EintrΓ€ge echo "" jq -r '.[-10:] | reverse | .[] | if .typ == "mixcloud" then " 🎧" elif .typ == "soundcloud" then " πŸ”Š" elif .typ == "youtube" then " πŸ“Ή" elif .typ == "git" then " πŸ’Ύ" else " πŸ”—" end + " " + .zeit + " - " + .typ + (if .notiz != "" then "\n πŸ“ " + .notiz else "" end) + "\n " + .link' "$memo_file" echo "" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" printf " Gesamt: %d KrΓΌmel" "$total" if [[ $mixcloud -gt 0 ]]; then printf " | 🎧 %d" "$mixcloud"; fi if [[ $soundcloud -gt 0 ]]; then printf " | πŸ”Š %d" "$soundcloud"; fi if [[ $youtube -gt 0 ]]; then printf " | πŸ“Ή %d" "$youtube"; fi if [[ $git -gt 0 ]]; then printf " | πŸ’Ύ %d" "$git"; fi echo "" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "" echo "πŸ’‘ Output-Transparenz: Was habe ich geschaffen? πŸ’š" } # πŸ’° check_token_budget - PrΓΌft ob Token-Budget noch verfΓΌgbar ist function check_token_budget() { local role_name="${1:-unknown}" # Wenn kein Budget gesetzt oder 0, dann unbegrenzt if [[ -z "${DAILY_TOKEN_BUDGET}" ]] || [[ "${DAILY_TOKEN_BUDGET}" -eq 0 ]]; then return 0 # Erlaubt fi # Berechne heutigen Token-Verbrauch local today=$(date '+%Y-%m-%d') local total_today=0 for token_file in "${CRUMB_LOGS_DIR}"/*/token_log.json; do if [[ -f "$token_file" ]]; then # Summiere nur Tokens von heute (robuster Ansatz fΓΌr verschiedene Log-Formate) local tokens=$(grep "$today" "$token_file" 2>/dev/null | grep -v '^\[\]$' | while read line; do # Versuche total_tokens zu extrahieren (unterstΓΌtzt usage als String oder Objekt) echo "$line" | jq -r ' if .usage | type == "string" then .usage | fromjson | .total_tokens // 0 else .usage.total_tokens // 0 end ' 2>/dev/null || echo 0 done | awk '{sum+=$1} END {print sum+0}') # Nur addieren wenn tokens eine gΓΌltige Zahl ist if [[ "$tokens" =~ ^[0-9]+$ ]]; then total_today=$((total_today + tokens)) fi fi done # PrΓΌfe ob Budget ΓΌberschritten if [[ $total_today -ge ${DAILY_TOKEN_BUDGET} ]]; then echo "" echo "🌲 WaldwΓ€chter-Nachricht 🌲" echo "" echo " Liebes Kind, heute hast du schon ${total_today} Tokens verwendet." echo " Das Tages-Budget liegt bei ${DAILY_TOKEN_BUDGET} Tokens." echo "" echo " πŸ’š Jede Frage ist wertvoll - aber auch Pausen sind wichtig." echo " πŸ’­ Vielleicht kannst du selbst nach der Antwort suchen?" echo " πŸŒ™ Morgen sind die WaldwΓ€chter wieder fΓΌr dich da!" echo "" return 1 # Blockiert fi # Warnung wenn Budget knapp wird local remaining=$((DAILY_TOKEN_BUDGET - total_today)) if [[ "${ENABLE_TOKEN_TRACKING:-true}" == "true" ]] && [[ $remaining -lt ${TOKEN_WARNING_THRESHOLD:-1000} ]]; then echo "⚠️ ${role_name}: Noch ${remaining} Tokens heute verfΓΌgbar" >&2 fi return 0 # Erlaubt } # Export functions so they're available in subshells # Note: export -f works in bash, but not in zsh # In zsh, functions are automatically available in the current shell # For bash compatibility, we still do export -f, but it's optional in zsh if [[ -n "$BASH_VERSION" ]]; then # Bash: use export -f export -f mayaeule export -f deepbit export -f bugsy export -f schnippsi export -f templatus export -f tobi export -f schraubaer export -f schnecki export -f dumbosql export -f funkfox export -f taichitaube export -f snakepy export -f pepperphp export -f crabbyrust export -f spider export -f vektor export -f asciimonster export -f crew_tokens export -f crew_status export -f crew_memory export -f crew_doctor export -f crew_syntax export -f crew_help export -f crumb_memo export -f crew_memo export -f check_token_budget fi # In zsh, functions are available without export -f # Set version marker for crew_doctor to detect reloads if [[ -f "${WALDWAECHTER_DIR}/lib/waldwaechter.sh" ]]; then WALDWAECHTER_LIB_MTIME=$(stat -f "%m" "${WALDWAECHTER_DIR}/lib/waldwaechter.sh" 2>/dev/null || stat -c "%Y" "${WALDWAECHTER_DIR}/lib/waldwaechter.sh" 2>/dev/null) export "WALDWAECHTER_LOADED_${WALDWAECHTER_LIB_MTIME}=1" fi