--- name: chatto-plugin-update description: "Use when an installed Chatto plugin must catch up to its remote and the changes must go live in the running Hermes gateway." version: 1.2.0 author: Paul Klumpp license: MIT metadata: hermes: tags: [chatto, plugin, update, git, gateway] --- # Chatto-Plugin updaten und Changes aktivieren ## When to Use Eine installierte Chatto-Plugin-Instanz soll auf den Stand ihrer Quelle gebracht werden, und die Änderungen sollen im laufenden Hermes Gateway aktiv werden. Der Remote steht hier bewusst **nicht**: er gehört der Installation, nicht dem Plugin. `git remote -v` des Checkouts ist die Wahrheit, und für einen selbst geklonten Checkout ist das ein privater Remote, den kein mitgeliefertes Dokument kennen kann. ## Schritt 1: Wo liegt die Instanz, und welche Art ist sie? Nicht raten — die drei Fälle haben verschiedene Türen, und zwei davon lassen sich nicht mit git bedienen: ```bash ls -d ~/.hermes/plugins/chatto-platform \ ~/.hermes/plugins/platforms/hermes-chatto-plugin 2>/dev/null REPO= [ -d "$REPO/.git" ] && echo "hat git" || echo "kein git" ``` | Befund | Art | Tür | | --- | --- | --- | | `~/.hermes/plugins/chatto-platform/` mit `.git` und Provenance-Zeile | per `hermes plugins install` | `hermes plugins update chatto-platform` | | `~/.hermes/plugins/chatto-platform/` mit `.git`, ohne Zeile | selbst geklont | einmalig `hermes plugins adopt chatto-platform`, danach `hermes plugins update chatto-platform` | | `~/.hermes/plugins/platforms/hermes-chatto-plugin/` ohne `.git` | Dateien kopiert (README Option B) | **kein Pull möglich** — der User muss neu kopieren oder klonen | Im dritten Fall gibt es keinen Remote und kein `git log`: `hermes plugins update` verweigert hier ("no .git directory"). Das ist keine Störung, sondern der Zustand des Verzeichnisses — es zu umgehen hieße, den Zustand zu erfinden. Dem User sagen, dass er die Dateien neu holen muss, und dann bei Schritt 4 weitergehen. ## Ablauf 2. **Hermes-Tür benutzen, nicht git.** `hermes plugins update` ist der Weg, weil es mehr tut als `git pull`: ```bash hermes plugins update chatto-platform ``` Es zieht den Stand, verwirft veralteten Bytecode aus `__pycache__`, schreibt die neue Revision in die Install-Metadaten und fragt nach, wenn der neue Stand Capabilities mitbringt, die noch nicht freigegeben sind (fail closed: ohne Antwort bleiben sie nicht freigegeben). Zwei Fälle lehnt es ab und sagt es: ein **gepinnter** Checkout (dann `hermes plugins install --force --ref <40-stelliger SHA>`) und ein Verzeichnis **ohne** `.git`. Ein Katalog- Install wird auf die geprüfte SHA zurückgesetzt, nicht gepullt — deshalb hier ausdrücklich kein `git pull`. 3. **Statusbericht: erst fetchen, nie behaupten.** Für die Zusammenfassung in Schritt 4 wird der alte Stand gebraucht, also **vor** dem Update abgreifen: ```bash git -C "$REPO" fetch --all git -C "$REPO" status -sb git -C "$REPO" branch -avv ``` Aussagen wie „synchron" nur NACH einem `fetch` — `status -sb` ohne fetch zeigt ahead/behind nur gegen den zuletzt bekannten Remote-Stand. Den alten Commit aus `branch -avv` ablesen und festhalten, nicht raten. 4. **Commits zusammenfassen (Nutzersicht):** ```bash git -C "$REPO" log .. # oneline git -C "$REPO" log .. --stat # Datei-Umfang ``` `` aus Schritt 3, `` aus Schritt 2 (der Revision, die Hermes gemeldet hat, oder `HEAD` des Checkouts). Commits haben ausführliche Messages — daraus eine nutzerverständliche Zusammenfassung machen: WAS ändert sich für den Bot-Nutzer, nicht Implementierungsdetails. Für jede Änderung eine Quelle angeben (Commit-Hash). 5. **Gateway-Neustart ANBIETEN (nie selbst ausführen):** Plugin-Code-Änderungen werden erst nach einem Neustart des Hermes-Gateways aktiv — die laufende Session hält das alte Modul im Speicher. - **Einfachster Weg: `/restart` als Chat-Nachricht** (Gateway-Slash-Command, „Restart gateway after draining active runs"). Der User tippt es direkt im Channel/DM. IMMER zuerst diesen Weg nennen. - **Aus der laufenden Agent-Session heraus ist ein Restart UNMÖGLICH:** der Lifecycle-Guard blockiert jeden Versuch aus dieser Session, weil der Restart die eigene Session killt. Nicht umgehen versuchen; keine Restart-Skripte/Aliase bauen, wenn `/restart` genügt. - Ein `hermes gateway restart` oder `systemctl restart …` aus einer Bediener-Shell **außerhalb** des Gateway-Prozesses funktioniert — aber nur dort. Aus einem Tool-Aufruf dieser Session heraus ist es derselbe blockierte Fall. Bei benannten Profilen heißt der Unit `hermes-gateway-`, nicht `hermes-gateway.service`. - User fragen, ob jetzt neu gestartet werden soll (der laufende Bot ist dann kurz offline). 6. **Nach dem Neustart verifizieren:** Plugin-Tools live testen (`chatto_list_rooms` via tool_call), im Log prüfen, dass der Adapter sauber lädt. ## Fallstricke - `git -C` in JEDEM git-Kommando. `git pull` oder `git log` ohne `-C` trifft den Checkout der Session, nicht den Plugin-Checkout. - Aussagen über Sync-Status („synchron", „aktuell") NUR NACH `git fetch` treffen — ohne fetch ist der lokale Status wertlos. - `hermes plugins adopt` nur **einmal** und nur bei einem selbst geklonten Verzeichnis. Hat Hermes bereits eine Provenance-Zeile, lehnt der Befehl ab ("already has a provenance row") — das ist kein Fehler, sondern heißt: der Fall greift nicht. - Vendored Updates (chattolib) kommen als dist-info-Rename + RECORD-Änderungen mit — normal, und über den ganz normalen Neustart aus Schritt 5 hinaus ohne Handlungsbedarf. - Der Lifecycle-Guard prüft **den Inhalt** eines Skripts, sobald ein Shell-Interpreter es referenziert: `bash -n skript.sh` mit `hermes gateway restart` darin wird abgelehnt — auch unter einem anderen Dateinamen und auch als `sh -n`. `chmod`, `mv` und `cp` sind nicht betroffen. Ein Skript also nicht an den Interpreter geben, um es zu prüfen: Inhalt mit den Datei-Tools lesen. Es lohnt auch nicht, es umzubenennen — der Guard liest Bytes, nicht Namen. - Das Ausführen von `/dev/null` (oder `/dev/zero`, `/dev/fd/N`) lässt der Guard bewusst fehlschlagen. Das ist keine Störung, sondern das gewollte Verhalten. Eine Umleitung nach `> /dev/null` in einer Shell-Datei ist davon nicht betroffen — die wird maskiert.