phase1c: Deploy mit Rueckweg und Prueftor, tote Deploy-Dateien raus
- deploy.sh zweistufig: Sperre, laufende Update-Jobs verschieben den Deploy, fast-forward, dann laeuft die NEUE Fassung als Stufe 2 (Aenderungen am Skript wirken sofort). Stufe 2: Prueftor, Abhaengigkeiten, llama-swap-Config nur bei Aenderung des Abzugs in diesem Deploy (ohne Motor-Neustart, -watch-config reicht; 5 Sicherungen), alle Repo-Units und Drop-ins, Cron-Skripte nach ~/.hermes/scripts, Skills/Plugins, Neustart, Nachpruefung. Scheitert etwas: zurueck auf den alten Stand (inkl. llama-swap-Config), Dienste neu, dringende Meldung, Eintrag in /srv/models/mc2-deploy.log. - deploy/pruefen.sh ersetzt die tote CI-Ampel: Shell-/Python-Syntax, ruff, Importe, pytest. Laeuft am PC vor dem Push und auf der Box vor dem Umschalten (pytest via requirements-dev.txt). - Units, die nur auf der Box lagen, jetzt im Repo: projekte-sync.*, lucy-stimme.service, mission-control-2-Override. - Tot und entfernt: Werkstatt-/Projektstart-/Betrieb-SOULs, worker.sh, Agent-Hooks, Ampel-CI (samt .gitea-Workflow und Saat in gitea-repo-create.sh), gitea-pr, Governor-Plugin, Specs, Selbst-Inventur, Self-Smoke, venv-Audit, setup_autonomous_crons.sh (haette alte Jobs neu angelegt), Einmal-Skripte, alte Bench-Skripte, .agents/mcp_config.json, client/ide-skills, mcp/requirements.txt. Gitea-Host-Notizen nach docs/archiv/gitea-host. - morgenmeldung.sh begrenzt das Melde-Log (ueber 3 MB bleiben die letzten 2 MB). - AGENTS.md: Prueftor und neuer Deploy beschrieben. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
e9f488b56c
commit
4cd856bd34
+173
-100
@@ -1,106 +1,179 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
# deploy.sh — den Box-Wart auf der Box auf den Stand von origin/main bringen.
|
||||
#
|
||||
# Zweistufig (seit 24.09.2026):
|
||||
# Stufe 1: Sperre gegen zwei gleichzeitige Deploys, laufende Update-Jobs abwarten lassen,
|
||||
# alten Stand merken, main holen (nur fast-forward) — dann die NEUE Fassung dieses
|
||||
# Skripts als Stufe 2 starten. Änderungen an deploy.sh wirken damit sofort, nicht
|
||||
# erst beim nächsten Lauf (die alte Falle: bash lief nach dem Pull mit der alten Datei).
|
||||
# Stufe 2: Prüftor (deploy/pruefen.sh), Abhängigkeiten, llama-swap-Config nur, wenn sich der
|
||||
# Abzug in DIESEM Deploy geändert hat, Units/Drop-ins/Cron-Skripte/Skills/Plugins
|
||||
# ausspielen, Dienste neu starten, Nachprüfung. Scheitert irgendein Schritt: zurück auf
|
||||
# den alten Stand, Dienste neu starten, dringende Meldung.
|
||||
#
|
||||
# Aufruf auf der Box: bash ~/mission-control-v2/deploy/deploy.sh
|
||||
# Schalter: MC_DEPLOY_TROTZDEM=1 (auch bei laufenden Jobs), MC_DEPLOY_OHNE_TESTS=1 (Notfall),
|
||||
# MC_DEPLOY_SKIP_SWAP_CONFIG=1 (llama-swap-Config nie anfassen).
|
||||
set -euo pipefail
|
||||
|
||||
# ‼️ Das ganze Skript liegt in EINER Funktion — das ist Absicht, kein Stil.
|
||||
# Bash liest ein Skript haeppchenweise WAEHREND es laeuft. `git pull` unten ersetzt
|
||||
# genau diese Datei mitten im Lauf; danach liest bash am selben Byte-Offset im NEUEN
|
||||
# Text weiter und fuehrt zerschnittene Zeilen aus. Live erlebt am 27.08.2026: der Pull
|
||||
# brachte eine neue Fassung dieses Schrittes mit, ausgefuehrt wurde trotzdem die alte.
|
||||
# Eine Funktion wird komplett geparst, bevor sie startet -> der Lauf bleibt in sich
|
||||
# stimmig, und Aenderungen greifen ab dem naechsten Aufruf statt mittendrin.
|
||||
main() {
|
||||
cd "$HOME/mission-control-v2"
|
||||
export XDG_RUNTIME_DIR="${XDG_RUNTIME_DIR:-/run/user/$(id -u)}"
|
||||
API="http://127.0.0.1:9001"
|
||||
LSWAP_LIVE="/etc/llama-swap/config.yaml"
|
||||
DEPLOY_LOG="/srv/models/mc2-deploy.log"
|
||||
|
||||
echo "Starte MC2 Deployment..."
|
||||
# Units, die ganz dem Repo gehören (deploy.sh spielt sie aus). Aktiviert wird nur, was laufen soll:
|
||||
# Konsole und Spracherkennung schlafen seit 24.09.2026 (disable --now), ihre Units bleiben aber aktuell.
|
||||
UNITS="mission-control-2.service mc2-gateway.service mc2-steward.service lucy-stimme.service
|
||||
box-console.service voice-service.service
|
||||
mc2-radar.service mc2-radar.timer mc2-backup.service mc2-backup.timer
|
||||
mc2-morgenmeldung.service mc2-morgenmeldung.timer mc2-autoupdate.service mc2-autoupdate.timer
|
||||
projekte-sync.service projekte-sync.timer"
|
||||
AKTIV="mission-control-2.service mc2-gateway.service mc2-steward.service lucy-stimme.service
|
||||
mc2-radar.timer mc2-backup.timer mc2-morgenmeldung.timer mc2-autoupdate.timer projekte-sync.timer"
|
||||
# Skills, die abgelöst sind: aus Lucys Skill-Index nehmen (verschoben, nicht gelöscht). Dazu die
|
||||
# alten Bindestrich-Doppel der übrigen Skills (deploy.sh schreibt die Unterstrich-Fassung).
|
||||
SKILLS_ALT="autonomie konzept-fliessband llm-wiki morning-report orchestrator projekt-start pruefstand
|
||||
review trend-radar wartung konzept_fliessband llm_wiki morning_report projekt_start
|
||||
trend_radar betrieb-playbook pc-pfad-cache"
|
||||
|
||||
# 1. Neuesten Code holen
|
||||
git pull origin main
|
||||
|
||||
|
||||
# 2. Abhängigkeiten prüfen (falls sich was geändert hat)
|
||||
echo "Aktualisiere Python Abhängigkeiten..."
|
||||
backend/.venv/bin/pip install -r backend/requirements.txt
|
||||
|
||||
# 3. Llama-Swap Konfiguration prüfen und synchronisieren
|
||||
#
|
||||
# ‼️ ACHTUNG (27.08.2026): /etc/llama-swap/config.yaml ist die LEBENDE Wahrheit — MC2
|
||||
# schreibt sie selbst (backend/services/llamaswap.py::write_config), sobald jemand über
|
||||
# die Oberfläche ein Modell hinzufügt oder eine Rolle ändert. deploy/llama-swap.config.yaml
|
||||
# ist nur ein Abzug und hinkt regelmäßig hinterher (erlebt: der Coder-Vollkontext aus 34a9862
|
||||
# stand tagelang nur live, nicht im Abzug — ein Deploy hätte ihn zurückgesetzt).
|
||||
# Bis hierher wurde die Live-Datei kommentarlos mit dem Abzug überschrieben — alles per
|
||||
# UI Hinzugefügte war nach jedem Deploy weg. Jetzt: erst sichern, dann kopieren, und die
|
||||
# Abweichung sichtbar machen. MC_DEPLOY_SKIP_SWAP_CONFIG=1 überspringt den Schritt ganz.
|
||||
if ! cmp -s deploy/llama-swap.config.yaml /etc/llama-swap/config.yaml; then
|
||||
if [ "${MC_DEPLOY_SKIP_SWAP_CONFIG:-0}" = "1" ]; then
|
||||
echo "Llama-Swap Konfiguration weicht ab — uebersprungen (MC_DEPLOY_SKIP_SWAP_CONFIG=1)."
|
||||
else
|
||||
SWAP_BAK="/etc/llama-swap/config.yaml.bak-$(date +%Y%m%d-%H%M%S)"
|
||||
echo "Llama-Swap Konfiguration hat sich geändert."
|
||||
echo " Abweichung (live -> Repo-Abzug):"
|
||||
diff -u /etc/llama-swap/config.yaml deploy/llama-swap.config.yaml | head -40 || true
|
||||
echo " Sichere die laufende Datei nach $SWAP_BAK"
|
||||
# NOPASSWD für llama-swap Neustart ist vorausgesetzt (siehe AGENTS.md)
|
||||
sudo cp /etc/llama-swap/config.yaml "$SWAP_BAK"
|
||||
sudo cp deploy/llama-swap.config.yaml /etc/llama-swap/config.yaml
|
||||
sudo systemctl restart llama-swap
|
||||
echo " Rueckweg bei Verlust: sudo cp $SWAP_BAK /etc/llama-swap/config.yaml"
|
||||
fi
|
||||
fi
|
||||
|
||||
# 4. Systemd Units neu laden (falls sich .service Dateien geändert haben)
|
||||
# Das Modell-Radar (09/2026) ist die erste Unit, die deploy.sh selbst einspielt: Sie gehört ganz dem
|
||||
# Repo, auf der Box wird an ihr nichts von Hand gedreht. Die übrigen Units bleiben wie bisher Handarbeit.
|
||||
install -m 644 deploy/mc2-radar.service deploy/mc2-radar.timer "$HOME/.config/systemd/user/"
|
||||
# Morgenmeldung (24.09.2026): schickt um 07:00, was notify.sh nachts gesammelt hat.
|
||||
install -m 644 deploy/mc2-morgenmeldung.service deploy/mc2-morgenmeldung.timer "$HOME/.config/systemd/user/"
|
||||
# Updates am Sonntag (24.09.2026): eigener Timer statt Hermes-Cron.
|
||||
install -m 644 deploy/mc2-autoupdate.service deploy/mc2-autoupdate.timer "$HOME/.config/systemd/user/"
|
||||
# Warm-Set des Wächters (24.09.2026: nur noch das Hirn).
|
||||
install -D -m 644 deploy/mc2-steward.service.d-warmset.conf "$HOME/.config/systemd/user/mc2-steward.service.d/warmset.conf"
|
||||
systemctl --user daemon-reload
|
||||
systemctl --user enable --now mc2-radar.timer mc2-morgenmeldung.timer mc2-autoupdate.timer
|
||||
|
||||
# 4.5 Hermes Skills synchronisieren
|
||||
echo "Synchronisiere Hermes Skills..."
|
||||
mkdir -p ~/.hermes/skills
|
||||
# Kopiere alle Skills aus dem Repo, ersetze - durch _ in den Ordnernamen für Hermes Kompatibilität
|
||||
for skill_dir in deploy/skills/*; do
|
||||
if [ -d "$skill_dir" ]; then
|
||||
skill_name=$(basename "$skill_dir" | tr '-' '_')
|
||||
mkdir -p ~/.hermes/skills/"$skill_name"
|
||||
cp -r "$skill_dir"/* ~/.hermes/skills/"$skill_name"/
|
||||
fi
|
||||
done
|
||||
# Abgelöste Skills (24.09.2026) aus Lucys Skill-Index nehmen: verschoben nach
|
||||
# ~/.hermes/skills-archiv, nicht gelöscht. Dazu die alten Bindestrich-Doppel der übrigen Skills
|
||||
# (deploy.sh schreibt seit jeher die Unterstrich-Fassung).
|
||||
for alt in autonomie konzept-fliessband llm-wiki morning-report orchestrator projekt-start \
|
||||
pruefstand review trend-radar wartung konzept_fliessband llm_wiki morning_report \
|
||||
projekt_start trend_radar betrieb-playbook pc-pfad-cache; do
|
||||
if [ -d ~/.hermes/skills/"$alt" ]; then
|
||||
mkdir -p ~/.hermes/skills-archiv
|
||||
rm -rf ~/.hermes/skills-archiv/"$alt"
|
||||
mv ~/.hermes/skills/"$alt" ~/.hermes/skills-archiv/
|
||||
fi
|
||||
done
|
||||
|
||||
# 4.6 Hermes-Plugins aus dem Repo (09/2026: mc2-web-lesen, Seiten lokal lesen für web_extract).
|
||||
# Nur kopieren: Aktiviert wird ein Plugin einmalig von Hand (hermes plugins enable …), und neuer
|
||||
# Plugin-Code greift erst beim nächsten Neustart des Hermes-Gateways — den macht deploy.sh bewusst nicht.
|
||||
mkdir -p ~/.hermes/plugins
|
||||
for plugin_dir in deploy/hermes-plugins/*; do
|
||||
[ -d "$plugin_dir" ] && cp -r "$plugin_dir" ~/.hermes/plugins/
|
||||
done
|
||||
|
||||
# 5. Dienste neu starten
|
||||
# ‼️ mc2-steward gehoert hier dazu: er laeuft aus DEMSELBEN Checkout (backend/steward.py).
|
||||
# Ohne ihn lief der Waechter-Prozess nach jedem Deploy mit dem alten Code weiter — der
|
||||
# Neustart wurde 27.08.2026 nachgetragen. `--user restart` auf einer nicht installierten
|
||||
# Unit ist folgenlos, darum ohne Vorabpruefung.
|
||||
echo "Starte Backend neu..."
|
||||
systemctl --user restart mc2-gateway.service mission-control-2.service mc2-steward.service
|
||||
|
||||
echo "✅ Deployment erfolgreich abgeschlossen!"
|
||||
laufende_jobs() {
|
||||
curl -sf -m 5 "$API/api/jobs" 2>/dev/null \
|
||||
| python3 -c 'import json,sys; print(sum(1 for j in json.load(sys.stdin).get("jobs", []) if j.get("state") in ("running", "queued")))' \
|
||||
2>/dev/null || echo 0
|
||||
}
|
||||
|
||||
main "$@"
|
||||
stufe1() {
|
||||
exec 9>"${XDG_RUNTIME_DIR}/mc2-deploy.lock"
|
||||
flock -n 9 || { echo "Es läuft schon ein Deploy."; exit 1; }
|
||||
# Update- und Download-Jobs leben (noch) im MC2-Prozess: ein Neustart würde sie abwürgen.
|
||||
local n; n="$(laufende_jobs)"
|
||||
if [ "${n:-0}" -gt 0 ] && [ "${MC_DEPLOY_TROTZDEM:-0}" != "1" ]; then
|
||||
echo "Es laufen $n Job(s) (Update oder Download). Deploy verschoben — später erneut, oder MC_DEPLOY_TROTZDEM=1."
|
||||
exit 1
|
||||
fi
|
||||
local vorher; vorher="$(git rev-parse HEAD)"
|
||||
echo "Starte Deploy (vorher ${vorher:0:7})…"
|
||||
git fetch -q origin main
|
||||
git merge --ff-only -q origin/main
|
||||
# Ab hier die NEUE Fassung dieses Skripts. Die Sperre (fd 9) bleibt über exec erhalten.
|
||||
MC_DEPLOY_STUFE=2 MC_DEPLOY_VORHER="$vorher" exec bash deploy/deploy.sh "$@"
|
||||
}
|
||||
|
||||
stufe2() {
|
||||
local vorher="$MC_DEPLOY_VORHER" neu swap_bak=""
|
||||
neu="$(git rev-parse --short HEAD)"
|
||||
|
||||
zurueck() {
|
||||
trap - ERR
|
||||
echo "✗ Deploy von $neu gescheitert — zurück auf ${vorher:0:7}."
|
||||
git reset -q --hard "$vorher" || true
|
||||
if [ -n "$swap_bak" ] && [ -f "$swap_bak" ]; then
|
||||
cp "$swap_bak" "$LSWAP_LIVE" && echo " llama-swap-Config zurückgespielt."
|
||||
fi
|
||||
systemctl --user daemon-reload || true
|
||||
systemctl --user restart mc2-gateway.service mission-control-2.service mc2-steward.service || true
|
||||
echo "$(date -Is) GESCHEITERT $neu, zurück auf ${vorher:0:7}" >> "$DEPLOY_LOG" 2>/dev/null || true
|
||||
bash deploy/notify.sh -d -s "[Alarm] Deploy" \
|
||||
"Deploy von $neu ist gescheitert, die Box läuft wieder mit ${vorher:0:7}. Details: journalctl oder deploy-Ausgabe." || true
|
||||
exit 1
|
||||
}
|
||||
trap zurueck ERR
|
||||
|
||||
if [ "$neu" = "${vorher:0:7}" ]; then
|
||||
echo "Kein neuer Stand auf main — spiele trotzdem alles aus (Units, Skripte, Neustart)."
|
||||
fi
|
||||
|
||||
# 1. Abhängigkeiten (inkl. pytest fürs Prüftor)
|
||||
echo "Aktualisiere Python-Abhängigkeiten…"
|
||||
backend/.venv/bin/pip install -q -r backend/requirements.txt -r backend/requirements-dev.txt
|
||||
|
||||
# 2. Prüftor: vor jedem Umschalten. Rot = zurück auf den alten Stand.
|
||||
if [ "${MC_DEPLOY_OHNE_TESTS:-0}" = "1" ]; then
|
||||
echo "Prüftor übersprungen (MC_DEPLOY_OHNE_TESTS=1)."
|
||||
else
|
||||
bash deploy/pruefen.sh
|
||||
fi
|
||||
|
||||
# 3. llama-swap-Config: /etc/llama-swap/config.yaml ist die LEBENDE Wahrheit, MC2 schreibt sie
|
||||
# selbst (Oberfläche, Radar). Der Repo-Abzug überschreibt sie nur, wenn er sich in DIESEM Deploy
|
||||
# geändert hat — sonst würde jede Abweichung (z. B. ein per Oberfläche eingetragenes Modell)
|
||||
# zurückgedreht. Kein Neustart nötig: llama-swap läuft mit -watch-config.
|
||||
if [ "${MC_DEPLOY_SKIP_SWAP_CONFIG:-0}" != "1" ] && ! git diff --quiet "$vorher" HEAD -- deploy/llama-swap.config.yaml; then
|
||||
swap_bak="$LSWAP_LIVE.bak-$(date +%Y%m%d-%H%M%S)"
|
||||
echo "llama-swap-Abzug geändert — sichere $LSWAP_LIVE nach $swap_bak und spiele ihn ein."
|
||||
diff -u "$LSWAP_LIVE" deploy/llama-swap.config.yaml | head -40 || true
|
||||
cp "$LSWAP_LIVE" "$swap_bak"
|
||||
cp deploy/llama-swap.config.yaml "$LSWAP_LIVE.neu"
|
||||
mv "$LSWAP_LIVE.neu" "$LSWAP_LIVE"
|
||||
# Nur die letzten 5 Sicherungen behalten (ältere root-eigene bleiben notfalls liegen).
|
||||
ls -1t "$LSWAP_LIVE".bak-* 2>/dev/null | tail -n +6 | xargs -r rm -f 2>/dev/null || true
|
||||
elif ! cmp -s deploy/llama-swap.config.yaml "$LSWAP_LIVE"; then
|
||||
echo "Hinweis: Die lebende llama-swap-Config weicht vom Repo-Abzug ab (Änderung über die Oberfläche?) — nicht angefasst."
|
||||
fi
|
||||
|
||||
# 4. Units und Drop-ins (alle Repo-Units, damit Box und Repo nicht auseinanderlaufen)
|
||||
local ziel="$HOME/.config/systemd/user" u
|
||||
for u in $UNITS; do
|
||||
install -m 644 "deploy/$u" "$ziel/$u"
|
||||
done
|
||||
install -D -m 644 deploy/mc2-steward.service.d-warmset.conf "$ziel/mc2-steward.service.d/warmset.conf"
|
||||
install -D -m 644 deploy/mission-control-2.service.d-override.conf "$ziel/mission-control-2.service.d/override.conf"
|
||||
systemctl --user daemon-reload
|
||||
# shellcheck disable=SC2086
|
||||
systemctl --user enable $AKTIV >/dev/null 2>&1
|
||||
# shellcheck disable=SC2086
|
||||
systemctl --user start mc2-radar.timer mc2-backup.timer mc2-morgenmeldung.timer projekte-sync.timer
|
||||
# Den Update-Timer nur starten, wenn er nicht schon läuft: Mit Persistent=true holt ein frisch
|
||||
# gestarteter Timer einen verpassten Sonntagslauf sofort nach (so am 24.09.2026 passiert). Neu
|
||||
# gestartet wird die Box dabei ohnehin nur sonntags zwischen 04 und 07 Uhr (autoupdate.sh).
|
||||
systemctl --user is-active --quiet mc2-autoupdate.timer || systemctl --user start mc2-autoupdate.timer
|
||||
|
||||
# 5. Cron-Skripte für Hermes (~/.hermes/scripts ist die Vorgabe von `hermes cron --script`)
|
||||
mkdir -p "$HOME/.hermes/scripts"
|
||||
install -m 755 deploy/jobs/*.sh deploy/jobs/*.py "$HOME/.hermes/scripts/"
|
||||
|
||||
# 6. Skills und Plugins
|
||||
echo "Synchronisiere Hermes-Skills…"
|
||||
mkdir -p "$HOME/.hermes/skills"
|
||||
local d name alt
|
||||
for d in deploy/skills/*/; do
|
||||
name="$(basename "$d" | tr '-' '_')"
|
||||
mkdir -p "$HOME/.hermes/skills/$name"
|
||||
cp -r "$d". "$HOME/.hermes/skills/$name/"
|
||||
done
|
||||
for alt in $SKILLS_ALT; do
|
||||
if [ -d "$HOME/.hermes/skills/$alt" ]; then
|
||||
mkdir -p "$HOME/.hermes/skills-archiv"
|
||||
rm -rf "$HOME/.hermes/skills-archiv/$alt"
|
||||
mv "$HOME/.hermes/skills/$alt" "$HOME/.hermes/skills-archiv/"
|
||||
fi
|
||||
done
|
||||
# Plugins nur kopieren: aktiviert wird einmalig von Hand (hermes plugins enable …), neuer Code
|
||||
# greift beim nächsten Neustart des Hermes-Gateways — den macht deploy.sh bewusst nicht.
|
||||
mkdir -p "$HOME/.hermes/plugins"
|
||||
for d in deploy/hermes-plugins/*/; do
|
||||
cp -r "${d%/}" "$HOME/.hermes/plugins/"
|
||||
done
|
||||
|
||||
# 7. Neustart und Nachprüfung
|
||||
echo "Starte Gateway, Box-Wart und Wächter neu…"
|
||||
systemctl --user restart mc2-gateway.service mission-control-2.service mc2-steward.service
|
||||
local i ok=0
|
||||
for i in $(seq 1 30); do
|
||||
if curl -sf -m 3 "$API/api/health" >/dev/null && curl -sf -m 3 http://127.0.0.1:9010/gw/health >/dev/null \
|
||||
&& systemctl --user is-active --quiet mc2-steward.service; then
|
||||
ok=1; break
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
[ "$ok" = 1 ] || { echo "Nachprüfung: Dienste antworten nicht."; false; }
|
||||
|
||||
trap - ERR
|
||||
echo "$(date -Is) $neu (vorher ${vorher:0:7})" >> "$DEPLOY_LOG" 2>/dev/null || true
|
||||
echo "✅ Deploy $neu ist live (vorher ${vorher:0:7})."
|
||||
}
|
||||
|
||||
# Beides in Funktionen und ein exit direkt dahinter: bash liest ein Skript häppchenweise, und
|
||||
# git merge ersetzt diese Datei mitten im Lauf. So läuft nichts aus der neuen Datei unkontrolliert.
|
||||
if [ "${MC_DEPLOY_STUFE:-1}" = "2" ]; then stufe2 "$@"; else stufe1 "$@"; fi; exit $?
|
||||
|
||||
Reference in New Issue
Block a user