#!/usr/bin/env bash # ============================================================================ # BSN Hermes Onboarding — Lokale Installation vollständig einrichten # ============================================================================ # Führt ALLE Schritte aus, damit dein lokaler Hermes Agent Zugang zu allen # BSN-Projekten, Coding-Standards und Git-Repositories hat. # # Ausführung: # chmod +x bsn-onboarding.sh # ./bsn-onboarding.sh # ============================================================================ set -euo pipefail RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; BLUE='\033[0;34m'; NC='\033[0m' info() { echo -e "${BLUE}ℹ${NC} $*"; } ok() { echo -e "${GREEN}✅${NC} $*"; } warn() { echo -e "${YELLOW}⚠️${NC} $*"; } err() { echo -e "${RED}❌${NC} $*"; } step() { echo -e "\n${BLUE}━━━${NC} $* ${BLUE}━━━${NC}"; } echo -e "${BLUE}" echo " ╔══════════════════════════════════════════════════╗" echo " ║ BSN Hermes Agent — Onboarding ║" echo " ║ Brettspiel-News Community Projekt ║" echo " ╚══════════════════════════════════════════════════╝" echo -e "${NC}" # ── Schritt 0: Basis-Checks ────────────────────────────────────────── step "Schritt 0/7: Basis-Checks" # Python if command -v python3 &>/dev/null; then PY=$(python3 --version 2>&1) ok "Python: $PY" else err "python3 nicht gefunden — bitte installieren" exit 1 fi # Hermes if command -v hermes &>/dev/null; then HERMES_VER=$(hermes --version 2>&1 | head -1) ok "Hermes: $HERMES_VER" elif [ -f "$HOME/venv/bin/hermes" ]; then export PATH="$HOME/venv/bin:$PATH" ok "Hermes gefunden unter ~/venv/bin/hermes" elif [ -f "$HOME/hermes-agent/hermes" ]; then warn "Hermes nur als Source-Repo gefunden — installiere..." curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash export PATH="$HOME/.local/bin:$PATH" ok "Hermes installiert" else err "Hermes nicht gefunden — installiere von https://github.com/NousResearch/hermes-agent" exit 1 fi # Git if command -v git &>/dev/null; then ok "Git: $(git --version)" else err "git nicht gefunden" exit 1 fi # ── Schritt 1: Python-Abhängigkeiten ────────────────────────────────── step "Schritt 1/7: Python-Toolchain installieren" pip install --quiet ruff mypy pre-commit pytest pytest-cov 2>&1 | tail -1 ok "ruff $(ruff --version 2>&1 | head -1 | cut -d' ' -f2)" ok "mypy $(mypy --version 2>&1 | head -1 | cut -d' ' -f2)" ok "pre-commit $(pre-commit --version 2>&1)" ok "pytest $(pytest --version 2>&1 | head -1 | cut -d' ' -f2)" # ── Schritt 2: SSH-Key für Gitea ───────────────────────────────────── step "Schritt 2/7: SSH-Zugang zu git.datenhimmel.work" if [ -f "$HOME/.ssh/id_ed25519.pub" ]; then ok "SSH-Key vorhanden: $(cat $HOME/.ssh/id_ed25519.pub | cut -d' ' -f1-2)..." else warn "Kein SSH-Key gefunden — erstelle einen..." ssh-keygen -t ed25519 -C "hermes@bsn-local" -f "$HOME/.ssh/id_ed25519" -N "" >/dev/null 2>&1 ok "SSH-Key erstellt: $(cat $HOME/.ssh/id_ed25519.pub | cut -d' ' -f1-2)..." echo -e "${YELLOW}" echo " ╔══════════════════════════════════════════════════════════╗" echo " ║ 🔑 DIESEN KEY in Gitea hinterlegen: ║" echo " ║ https://git.datenhimmel.work/user/settings/keys ║" echo " ║ ║" cat "$HOME/.ssh/id_ed25519.pub" echo " ║ ║" echo " ╚══════════════════════════════════════════════════════════╝" echo -e "${NC}" fi # ── Schritt 3: Git-Repositories klonen ─────────────────────────────── step "Schritt 3/7: BSN-Repositories klonen" WORKSPACE="$HOME/workspace" mkdir -p "$WORKSPACE" clone_repo() { local name=$1 repo=$2 dir="$WORKSPACE/$3" if [ -d "$dir/.git" ]; then ok "$name bereits vorhanden — pull..." (cd "$dir" && git pull --ff-only 2>/dev/null) || warn "$name: pull fehlgeschlagen" else info "Klone $name..." git clone "$repo" "$dir" 2>/dev/null && ok "$name geklont" || warn "$name: clone fehlgeschlagen (SSH-Key in Gitea hinterlegt?)" fi } clone_repo "BSN-Chatsystem" "git@git.datenhimmel.work:danielkrause/BSN-Chatsystem.git" "bsn-chatbot" # ── Schritt 4: Coding-Standards-Skill installieren ──────────────────── step "Schritt 4/7: BSN Coding Standards Skill einrichten" PROFILE_DIR="$HOME/.hermes/profiles/cody" SKILL_DIR="$PROFILE_DIR/skills/software-development/bsn-coding-standards" if [ -d "$SKILL_DIR" ] && [ -f "$SKILL_DIR/SKILL.md" ]; then ok "bsn-coding-standards Skill bereits installiert" else # Vom Server kopieren oder lokal aus dem Repo nehmen if [ -f "$WORKSPACE/bsn-chatbot/docs/bsn-coding-standards.html" ]; then info "Skill aus lokalem Repo erstellen..." mkdir -p "$SKILL_DIR/references" # Skill-MD aus dem Repo kopieren (falls vorhanden) oder neu erstellen if [ -f "$WORKSPACE/bsn-chatbot/CODING_STANDARDS.md" ]; then # Erstelle SKILL.md aus CODING_STANDARDS.md cat > "$SKILL_DIR/SKILL.md" << 'SKILLEOF' --- name: bsn-coding-standards description: Verbindliche Coding-Regeln für ALLE BSN-Projekte version: 1.0.0 category: software-development --- # BSN Coding Standards > Geltungsbereich: Sämtlicher Python-Code im Brettspiel-News-Community-Projekt. > Durchsetzung: Gitea Actions (.gitea/workflows/quality.yml) + pre-commit. > Vollständiges Dokument: docs/bsn-coding-standards.html ## 🔴 KRITISCHE REGELN 1. **Typ-Annotationen** — JEDE Funktion. `X | None`, nicht `Optional[X]`. 2. **Docstrings** — DEUTSCH, Google-Style. 3. **Secrets** — NIE im Code. `.env` + `.db` in `.gitignore`. 4. **Keine God-Files** — Max 500 Zeilen/Modul, max 50 Statements/Funktion. ## 🟡 CODE-STIL - Zeilenlänge max 100, 4 Leerzeichen, double quotes - Import-Reihenfolge: stdlib → third-party → projekt - Trailing Commas bei mehrzeiligen Collections ## 🟡 NAMEN - snake_case (Module, Funktionen, Variablen) - PascalCase (Klassen), UPPER_SNAKE_CASE (Konstanten) ## 🟡 SICHERHEIT - Keine asserts in Produktion, kein pickle, bcrypt/argon2 - Input-Validierung, parameterisierte Queries ## 🟡 FLASK - methods=[...] explizit, get_json(silent=True) mit None-Check - Response mit Statuscode, CSS immer inline, BSN-Blau #20228a ## 🟡 GIT - Conventional Commits: feat, fix, docs, chore, security - Vor jedem Commit: ruff check + mypy + pytest ## 🟢 TOOLS - ruff check . --fix && ruff format . - mypy . (im venv!) - pytest --cov --cov-fail-under=80 - Gitea Actions CI: .gitea/workflows/quality.yml SKILLEOF ok "Skill aus CODING_STANDARDS.md erstellt" else warn "CODING_STANDARDS.md nicht gefunden — Skill muss manuell erstellt werden" warn "Kopiere die SKILL.md vom Server: ~/.hermes/profiles/cody/skills/software-development/bsn-coding-standards/SKILL.md" fi fi fi # ── Schritt 5: Hermes-Profil konfigurieren ─────────────────────────── step "Schritt 5/7: Profil-Konfiguration" # Prüfen ob das cody-Profil existiert if [ -f "$PROFILE_DIR/config.yaml" ]; then ok "Profil 'cody' existiert" # Environment-Hint setzen HINT="Befolge die BSN Coding Standards. Lade sie mit skill_view('bsn-coding-standards'). Durchsetzung: Gitea Actions (.gitea/workflows/quality.yml) + pre-commit. Volles Regelwerk: docs/bsn-coding-standards.html" CURRENT=$(python3 -c " import yaml try: with open('$PROFILE_DIR/config.yaml') as f: c = yaml.safe_load(f) print(c.get('agent',{}).get('environment_hint','')) except: pass " 2>/dev/null) if [ "$CURRENT" = "$HINT" ]; then ok "environment_hint bereits korrekt" else hermes config set agent.environment_hint "$HINT" 2>/dev/null && \ ok "environment_hint gesetzt" || \ warn "environment_hint konnte nicht gesetzt werden — manuell in $PROFILE_DIR/config.yaml eintragen" fi else warn "Profil 'cody' existiert nicht — erstelle es mit: hermes profile create cody" warn "Dann diesen Schritt wiederholen" fi # ── Schritt 6: .env-Variablen prüfen ────────────────────────────────── step "Schritt 6/7: Umgebungsvariablen" ENV_FILE="$HOME/.hermes/.env" REQUIRED_VARS=("DEEPSEEK_API_KEY" "META_TOKEN" "TELEGRAM_TOKEN" "TAVILY_API_KEY") if [ -f "$ENV_FILE" ]; then ok ".env-Datei vorhanden: $ENV_FILE" for var in "${REQUIRED_VARS[@]}"; do if grep -q "^$var=" "$ENV_FILE" 2>/dev/null; then ok "$var gesetzt" else warn "$var FEHLT in .env" fi done else warn "Keine .env-Datei gefunden. Erstelle $ENV_FILE mit:" echo "" for var in "${REQUIRED_VARS[@]}"; do echo " $var=dein_key_hier" done echo "" fi # ── Schritt 7: Verifikation ────────────────────────────────────────── step "Schritt 7/7: Verifikation — alles grün?" FAILS=0 echo "" info "Prüfe: Hermes erreichbar..." hermes --version >/dev/null 2>&1 && ok "Hermes CLI" || { err "Hermes CLI"; FAILS=$((FAILS+1)); } info "Prüfe: Git-Zugang zu Gitea..." ssh -o StrictHostKeyChecking=no -o ConnectTimeout=5 -T git@git.datenhimmel.work 2>&1 | grep -q "successfully authenticated" && \ ok "SSH zu Gitea" || { warn "SSH zu Gitea — Key in Gitea hinterlegen: https://git.datenhimmel.work/user/settings/keys"; } info "Prüfe: Python-Tools..." ruff --version >/dev/null 2>&1 && ok "ruff" || { err "ruff"; FAILS=$((FAILS+1)); } mypy --version >/dev/null 2>&1 && ok "mypy" || { err "mypy"; FAILS=$((FAILS+1)); } pytest --version >/dev/null 2>&1 && ok "pytest" || { err "pytest"; FAILS=$((FAILS+1)); } info "Prüfe: BSN-Skill..." python3 -c " import os, sys skill_path = os.path.expanduser('$SKILL_DIR/SKILL.md') if os.path.exists(skill_path): sys.exit(0) else: sys.exit(1) " 2>/dev/null && ok "bsn-coding-standards Skill" || { warn "Skill fehlt — Schritt 4 wiederholen"; } echo "" if [ $FAILS -eq 0 ]; then echo -e "${GREEN} ✅✅✅ ALLE CHECKS BESTANDEN — Hermes ist BSN-bereit! ✅✅✅${NC}" else echo -e "${YELLOW} ⚠️ $FAILS Check(s) fehlgeschlagen — siehe oben.${NC}" fi echo "" echo -e "${BLUE} 🚀 Nächster Schritt:${NC}" echo " hermes # Interaktiver Chat" echo " hermes chat -q \"Bearbeite Aufgabe X\"" echo " hermes -s bsn-coding-standards # Mit BSN-Regeln starten" echo "" echo -e "${BLUE} 📚 Referenzen:${NC}" echo " Skill: skill_view('bsn-coding-standards')" echo " Volles Regelwerk: docs/bsn-coding-standards.html" echo " Testaufgabe: docs/bsn-agent-testaufgabe.md" echo " CI-Workflow: .gitea/workflows/quality.yml"