ソースを参照

Fix the update skill's facts, and drop the guard-evasion recipe it shipped

Two things the review of 0190bc3 called blocking, and the reviewer's finding on
the second was right in a way the file did not anticipate: the recipe does not
even work.

The Fallstricke told an agent that the lifecycle guard also blocks commands that
merely *reference* a restart script (chmod, bash -n, mv), and that a syntax check
therefore copies the script under another name first. Measured against the real
guard: chmod, mv and cp are not blocked at all, and bash -n on a byte-identical
copy under a different name is still blocked — it reads the file's contents, not
its name. So the premise is wrong and the remedy is a no-op, while the pattern it
teaches — duplicate an artifact under a new name so a safety guard cannot
recognise it — would ship to every installer with that agent's privileges, and
contradicts the file's own "Nicht umgehen versuchen" three lines up. Replaced
with what is true: only interpreter invocations are scanned, chmod/mv/cp are
fine, and a script is checked with the file tools rather than handed to a shell.

The hardcoded private remote went with it. It is the maintainer's installation
fact in a document every installer receives, and the commit message said such
facts stay out. `git remote -v` of the checkout is the truth and the file now
says so. That also forced the honest answer to the case the skill could never
have worked for: a `hermes plugins install` instance belongs to Hermes, its
checkout's revision is recorded in install metadata, and the door is
`hermes plugins update chatto-platform` — a raw git pull bypasses all of it and
cannot work on a manual copy at all. Both layouts are now resolved in step 1
instead of one being hardcoded, and every command carries `git -C "$REPO"`,
since steps 2 and 3 previously ran git in the session's cwd — the destructive one
included.

Also corrected while there: the systemctl alternative is marked as an operator's
shell outside the gateway (it contradicted the "impossible" bullet right below)
and its unit name qualified for named profiles; "kein Handlungsbedarf" for a
vendor refresh no longer contradicts the restart step; and the /dev/null entry
describes the behaviour that actually exists (executing a character device
fails closed, a redirect in a shell file is masked) rather than blaming bashrc
sourcing.

Version 1.1.0, author aligned with the sibling skill.
Paul Klumpp 2 週間 前
親
コミット
6349c0e9b0
1 ファイル変更、89 行追加、24 行削除
  1. 89 24
      skills/chatto-plugin-update/SKILL.md

+ 89 - 24
skills/chatto-plugin-update/SKILL.md

@@ -1,8 +1,8 @@
 ---
 name: chatto-plugin-update
-description: "Use when the local Chatto plugin repo must catch up to its remote and the changes must go live in the running Hermes gateway."
-version: 1.0.0
-author: Hermes Agent
+description: "Use when a local Chatto plugin checkout maintained with git must catch up to its remote and the changes must go live in the running Hermes gateway."
+version: 1.1.0
+author: Paul Klumpp
 license: MIT
 metadata:
   hermes:
@@ -13,34 +13,99 @@ metadata:
 
 ## When to Use
 
-Das lokale Chatto-Plugin-Repo auf den Remote-Stand bringen (git fetch/pull) und die neuen Commits im laufenden Hermes Gateway aktivieren (Neustart). Repo: `~/.hermes/plugins/chatto-platform/`, Remote `ssh://gogs.netdome.biz:10022/paul/hermes-chatto-plugin.git`.
+Ein lokaler Chatto-Plugin-Checkout, der mit **git gepflegt** wird, soll auf den
+Stand seines eigenen Remotes 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.
+
+**Nicht anwendbar auf eine per `hermes plugins install` installierte Instanz.**
+Deren Checkout gehört Hermes, nicht dem User; dort ist `hermes plugins update
+chatto-platform` der Weg (Schritt 2b). Ein `git pull` darin umgeht die
+Install-Metadaten, die den eingespielten Stand festhalten.
 
 ## Ablauf
 
-1. **Remote-Status PRÜFEN, nie behaupten:**
+1. **Checkout auflösen.** Es gibt zwei dokumentierte Layouts; welches zutrifft,
+   lässt sich nicht raten, also prüfen:
+   ```bash
+   ls -d ~/.hermes/plugins/chatto-platform \
+         ~/.hermes/plugins/platforms/hermes-chatto-plugin 2>/dev/null
+   ```
+   `REPO` auf den existierenden Pfad setzen und **in allen folgenden Schritten
+   mit `git -C "$REPO"` arbeiten** — ohne das laufen die Kommandos im cwd der
+   Session, im schlimmsten Fall in einem fremden Repository.
+2. **Remote-Status PRÜFEN, nie behaupten:**
+   ```bash
+   git -C "$REPO" fetch --all
+   git -C "$REPO" status -sb
+   git -C "$REPO" branch -avv
+   git -C "$REPO" remote -v        # der Remote, von dem gepullt wird
+   ```
+   Erst fetchen, dann Sync-Status (ahead/behind) reporten. Aussagen wie
+   „synchron" nur NACH einem `fetch` — der lokale `status -sb` ohne fetch zeigt
+   ahead/behind nur gegen den zuletzt bekannten Remote-Stand. Aktueller Branch:
+   `git -C "$REPO" branch --show-current`. Den alten Stand aus `branch -avv`
+   ablesen und für Schritt 3 festhalten.
+3. **Zusammenführen.** Bei einem selbst geklonten Checkout: `git -C "$REPO" pull`
+   (Fast-forward). Bei Divergenz: mit dem User abklären, NICHT automatisch
+   mergen/rebasen.
+   Bei einer per `hermes plugins install` installierten Instanz stattdessen:
    ```bash
-   git -C ~/.hermes/plugins/chatto-platform fetch --all
-   git -C ~/.hermes/plugins/chatto-platform status -sb
-   git -C ~/.hermes/plugins/chatto-platform branch -avv
+   hermes plugins update chatto-platform
    ```
-   Erst fetchen, dann Sync-Status (ahead/behind) reporten. Aussagen wie "synchron" nur NACH einem `fetch` — der lokale `status -sb` ohne fetch zeigt ahead/behind nur gegen den zuletzt bekannten Remote-Stand. Aktueller Branch: `git branch --show-current`.
-2. **Pull ausführen:** `git pull` (Fast-forward). Bei Divergenz: mit dem User abklären, NICHT automatisch mergen/rebasen.
-3. **Commits zusammenfassen (Nutzersicht):**
+4. **Commits zusammenfassen (Nutzersicht):**
    ```bash
-   git log <alter_stand>..<neuer_stand>          # oneline
-   git log <alter_stand>..<neuer_stand> --stat   # Datei-Umfang
+   git -C "$REPO" log <alter_stand>..<neuer_stand>          # oneline
+   git -C "$REPO" log <alter_stand>..<neuer_stand> --stat   # Datei-Umfang
    ```
-   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).
-4. **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"). User tippt es direkt im Channel/DM. IMMER zuerst diesen Weg nennen.
-   - Alternative (separate Shell auf dem Host): `hermes gateway restart` oder `systemctl restart hermes-gateway.service`.
-   - **Aus der laufenden Agent-Session heraus ist ein Restart UNMÖGLICH:** der Lifecycle-Guard blockiert jeden Versuch (direkt, via Skript, `at`, `systemd-run`, Aliase/Wrapper), weil der Restart die eigene Session killt. Nicht umgehen versuchen; keine Restart-Skripte/Aliase bauen, wenn `/restart` genügt.
-   - User fragen, ob jetzt neu gestartet werden soll (der laufende Bot ist dann kurz offline).
-5. **Nach dem Neustart verifizieren:** Plugin-Tools live testen (`chatto_list_rooms` via tool_call), im Log prüfen, dass der Adapter sauber lädt.
+   `<alter_stand>`/`<neuer_stand>` sind aus Schritt 2 — den alten Stand dort
+   abgelesen, nicht geraten, sonst zeigt das Log einen leeren oder zu großen
+   Bereich. 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-<profil>`, 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
 
-- Aussagen über Sync-Status ("synchron", "aktuell") NUR NACH `git fetch` treffen — ohne fetch ist der lokale Status wertlos.
-- Vendored Updates (chattolib) kommen als dist-info-Rename + RECORD-Änderungen im Pull — normal, kein Handlungsbedarf.
-- Der Lifecycle-Guard blockiert auch Kommandos, die eine Restart-Skript-Datei nur REFERENZIEREN (chmod, bash -n, mv auf den Pfad). Syntax prüfen, indem das Skript vorher unter anderem Namen ins Scratch-Verzeichnis kopiert und dort geprüft wird.
-- Lifecycle-Guard scheitert auch am Scannen von `/dev/null`-Referenzen (z.B. beim Sourcen der `~/.bashrc` im Terminal) — Änderungen an Shell-Dateien stattdessen über Datei-Tools (search_files/patch) verifizieren.
+- Aussagen über Sync-Status („synchron", „aktuell") NUR NACH `git fetch` treffen —
+  ohne fetch ist der lokale Status wertlos.
+- **`git -C` in JEDEM Kommando.** `git pull` ohne `-C` trifft den Checkout der
+  Session, nicht den Plugin-Checkout.
+- Vendored Updates (chattolib) kommen als dist-info-Rename + RECORD-Änderungen
+  im Pull — 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.