feat: BSN Hermes Onboarding-Script für lokale Installation
This commit is contained in:
Executable
+287
@@ -0,0 +1,287 @@
|
|||||||
|
#!/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"
|
||||||
Reference in New Issue
Block a user