From dc2768af71c46ec09da5b8ebdcfc609a84ed62a6 Mon Sep 17 00:00:00 2001 From: Tom Date: Tue, 27 Oct 2026 23:04:51 +0100 Subject: [PATCH] Erweiterung und Anpassung Demo --- README.md | 4 +- TESTEN.md | 63 ++++++++++++++----- .../packages/pub-commit-text/1.0.0/COMMAND.md | 10 +++ .../packages/pub-commit-text/1.0.0/hugin.yaml | 7 +++ .../packages/pub-doku-pruefer/1.0.0/AGENT.md | 11 ++++ .../pub-doku-pruefer/1.0.0/hugin.yaml | 12 ++++ .../pub-doku-schreiben/1.0.0/SKILL.md | 30 +++++++++ .../pub-doku-schreiben/1.0.0/hugin.yaml | 11 ++++ .../packages/pub-erklaeren/1.0.0/COMMAND.md | 8 +++ .../packages/pub-erklaeren/1.0.0/hugin.yaml | 8 +++ .../packages/pub-fehlersuche/1.0.0/SKILL.md | 34 ++++++++++ .../packages/pub-fehlersuche/1.0.0/hugin.yaml | 10 +++ .../packages/pub-grill-me/1.0.0/SKILL.md | 31 +++++++++ .../packages/pub-grill-me/1.0.0/hugin.yaml | 11 ++++ .../packages/pub-plan/1.0.0/COMMAND.md | 10 +++ .../packages/pub-plan/1.0.0/hugin.yaml | 8 +++ .../packages/pub-recherche/1.0.0/AGENT.md | 11 ++++ .../packages/pub-recherche/1.0.0/hugin.yaml | 12 ++++ .../packages/pub-schlank/1.0.0/SKILL.md | 26 ++++++++ .../packages/pub-schlank/1.0.0/hugin.yaml | 11 ++++ .../pub-sicherheits-review/1.0.0/AGENT.md | 12 ++++ .../pub-sicherheits-review/1.0.0/hugin.yaml | 12 ++++ scripts/demo.sh | 36 +++++++---- scripts/tool-smoke-test.sh | 14 ++--- server/tests/test_linter.py | 3 + 25 files changed, 369 insertions(+), 36 deletions(-) create mode 100644 contract/examples/packages/pub-commit-text/1.0.0/COMMAND.md create mode 100644 contract/examples/packages/pub-commit-text/1.0.0/hugin.yaml create mode 100644 contract/examples/packages/pub-doku-pruefer/1.0.0/AGENT.md create mode 100644 contract/examples/packages/pub-doku-pruefer/1.0.0/hugin.yaml create mode 100644 contract/examples/packages/pub-doku-schreiben/1.0.0/SKILL.md create mode 100644 contract/examples/packages/pub-doku-schreiben/1.0.0/hugin.yaml create mode 100644 contract/examples/packages/pub-erklaeren/1.0.0/COMMAND.md create mode 100644 contract/examples/packages/pub-erklaeren/1.0.0/hugin.yaml create mode 100644 contract/examples/packages/pub-fehlersuche/1.0.0/SKILL.md create mode 100644 contract/examples/packages/pub-fehlersuche/1.0.0/hugin.yaml create mode 100644 contract/examples/packages/pub-grill-me/1.0.0/SKILL.md create mode 100644 contract/examples/packages/pub-grill-me/1.0.0/hugin.yaml create mode 100644 contract/examples/packages/pub-plan/1.0.0/COMMAND.md create mode 100644 contract/examples/packages/pub-plan/1.0.0/hugin.yaml create mode 100644 contract/examples/packages/pub-recherche/1.0.0/AGENT.md create mode 100644 contract/examples/packages/pub-recherche/1.0.0/hugin.yaml create mode 100644 contract/examples/packages/pub-schlank/1.0.0/SKILL.md create mode 100644 contract/examples/packages/pub-schlank/1.0.0/hugin.yaml create mode 100644 contract/examples/packages/pub-sicherheits-review/1.0.0/AGENT.md create mode 100644 contract/examples/packages/pub-sicherheits-review/1.0.0/hugin.yaml diff --git a/README.md b/README.md index 8adec65..29758bf 100644 --- a/README.md +++ b/README.md @@ -23,8 +23,8 @@ Voraussetzungen: `uv`, Go ≥ 1.26, `zip`, `curl`. Für die Browser-Prüfungen G scripts/demo.sh # Server mit Beispieldaten auf http://127.0.0.1:8080; Keys stehen in .demo/keys.txt ``` -In der Weboberfläche mit einem der Keys anmelden, z. B. als Bert (Prüfer): unter „Prüfungen“ wartet -`pub-munin-nutzen 1.5.0`. Als Anna (Autorin) hochladen, als Shop-Admin Personen und Keys anlegen, +In der Weboberfläche mit einem der Keys anmelden, z. B. als „Prüfer“: unter „Prüfungen“ wartet +`pub-munin-nutzen 1.5.0`. Als „Autor“ hochladen, als Shop-Admin Personen und Keys anlegen, als Plattform-Admin (`demo-admin`) die Systemseite. Mit dem CLI ein Repo abgleichen: diff --git a/TESTEN.md b/TESTEN.md index 4a66755..95a6155 100644 --- a/TESTEN.md +++ b/TESTEN.md @@ -19,8 +19,10 @@ Im Browser mit einem Key aus `.demo/keys.txt` anmelden: | Key | Rolle | Was ausprobieren | |---|---|---| -| Bert Prüfer | Prüfer | unter „Prüfungen“ wartet `pub-munin-nutzen 1.5.0` | -| Anna Autorin | Autorin | Pakete anlegen und hochladen | +| Prüfer | Prüfer | unter „Prüfungen“ wartet `pub-munin-nutzen 1.5.0` | +| Prüfer 2 | Prüfer | zweite Freigabe bei Risiko „Skripte“ oder „Rechte“ | +| Admin | Prüfer + Tenant-Admin (Tenant plattform) | Freigabe bei Risiko „Rechte“ | +| Autor | Autor | Pakete anlegen und hochladen | | Shop-Admin | Tenant-Admin | Projekte, Personen und Keys anlegen | | `demo-admin` | Plattform-Admin | Systemseite, Audit, alle Tenants | @@ -65,11 +67,40 @@ opencode # oder: claude > /pub-release-notiz 2.0 Kunden ``` +**Pakete für den Alltag:** Die Demo veröffentlicht außerdem diese Pakete (Quellen in +`contract/examples/packages/`), alle mit Risiko „Text“: + +| Paket | Art | Ausprobieren | +|---|---|---| +| `pub-schlank` | Skill | „Bau das minimal: …“ | +| `pub-doku-schreiben` | Skill | „Schreib eine README für diesen Ordner“ | +| `pub-grill-me` | Skill | „Grill me: ich will … bauen“ – eine Frage nach der anderen | +| `pub-fehlersuche` | Skill | einen fehlschlagenden Test zeigen | +| `pub-erklaeren` | Befehl | `/pub-erklaeren src/` | +| `pub-plan` | Befehl | `/pub-plan "Login per SSO"` | +| `pub-commit-text` | Befehl | nach `git add` einfach `/pub-commit-text` | +| `pub-recherche` | Subagent (lesen, Netz) | „Lass recherchieren, ab welcher Version …“ | +| `pub-doku-pruefer` | Subagent (lesen) | „Prüf die Doku gegen den Code“ | +| `pub-sicherheits-review` | Subagent (lesen) | „Sicherheitsreview der letzten Änderungen“ | + +Mit dem Integrations-Key „Softwareverteilung“ (Tenant shop) holen, ohne `hugin`: + +```sh +export HUGIN_KEY= +curl -s http://127.0.0.1:8080/api/v1/delivery/packages -H "Authorization: Bearer $HUGIN_KEY" +curl -s -X POST http://127.0.0.1:8080/api/v1/delivery/bundle -H "Authorization: Bearer $HUGIN_KEY" \ + -H 'Content-Type: application/json' -o bundle.zip \ + -d '{"packages":["pub-grill-me","pub-plan","pub-recherche"],"tools":{"claude":"2.1.302","opencode":"1.19.4"}}' +``` + +Unter Windows dasselbe mit `hugin-install.ps1 -Packages pub-grill-me,pub-plan,pub-recherche` +([Integrationen und PowerShell](http://127.0.0.1:8080/help/integration)). + **Was sich zu testen lohnt:** - Eine verwaltete Datei von Hand ändern, dann `hugin sync` → Befund „Handänderung“; `hugin sync --overwrite` setzt sie zurück. -- Als Bert `pub-munin-nutzen 1.5.0` freigeben, dann `hugin check` (meldet die neue +- Als „Prüfer“ `pub-munin-nutzen 1.5.0` freigeben, dann `hugin check` (meldet die neue Version) und `hugin sync`. - Ein Paket aus `packages` entfernen und `hugin sync` → seine Dateien verschwinden. - Claude Code fragt beim ersten Start, ob es den MCP-Server aus `.mcp.json` nutzen darf. @@ -78,7 +109,7 @@ opencode # oder: claude ```sh cd /tmp -export HUGIN_KEY= HUGIN_SERVER=http://127.0.0.1:8080 +export HUGIN_KEY= HUGIN_SERVER=http://127.0.0.1:8080 hugin new skill pub-mein-test ``` @@ -94,7 +125,7 @@ hugin try --remove # wieder aufräumen cd /tmp && hugin upload --submit pub-mein-test # hochladen und zur Prüfung einreichen ``` -Danach als Bert im Browser unter „Prüfungen“ freigeben. +Danach als „Prüfer“ im Browser unter „Prüfungen“ freigeben. **Linter ausprobieren:** @@ -160,7 +191,7 @@ Hand lohnt es trotzdem einmal, um das Verhalten zu kennen. | Version `1.4.0` öffnen, Tab „Inhalt“ anklicken, dann ← → Pos1 Ende | Tabs wechseln per Tastatur ⚙ | | „Mein Projekt“ | Repos gruppiert; Filter „Alle“ / „Mit neuerer Version“; „Gemeldet“ als relative Zeit („vor 2 Tagen“), genaue Zeit im Tooltip | -### 5.3 Als Bert (Prüfer) und Carla (Prüferin + Tenant-Admin) +### 5.3 Als „Prüfer“ und „Admin“ (Prüfer + Tenant-Admin) | Schritt | Erwartung | |---|---| @@ -168,10 +199,10 @@ Hand lohnt es trotzdem einmal, um das Verhalten zu kennen. | Version öffnen → „Prüfen“ → ohne Kommentar „Zurückgeben“ | Browser verlangt einen Kommentar, nichts wird abgeschickt ⚙ | | Mit Kanal „stabil“ freigeben | zurück in „Prüfungen“; danach meldet im Test-Repo `hugin check` die neue Version | | Danach als Shop-Admin „Überblick“ → Karte „Veraltete Installationen“ | springt zur Tabelle der Repos mit alter Version | -| Rechte-Paket: als Anna eine Skill-Version mit `extra: {claude: {allowed-tools: [Bash]}}` hochladen und einreichen, Bert gibt frei | Bert sieht im Dialog kein Kanal-Feld, sondern „Den Kanal wählt die letzte nötige Freigabe“; danach sieht Carla in „Prüfungen“ „Freigaben 1 von 2“ und „Tenant-Admin nötig“ | -| Carla gibt frei | Kanal-Feld mit Hinweis zum Risiko; danach freigegeben | +| Rechte-Paket: als „Autor“ eine Skill-Version mit `extra: {claude: {allowed-tools: [Bash]}}` hochladen und einreichen, „Prüfer“ gibt frei | „Prüfer“ sieht im Dialog kein Kanal-Feld, sondern „Den Kanal wählt die letzte nötige Freigabe“; danach sieht „Admin“ in „Prüfungen“ „Freigaben 1 von 2“ und „Tenant-Admin nötig“ | +| „Admin“ gibt frei | Kanal-Feld mit Hinweis zum Risiko; danach freigegeben | -### 5.4 Als Anna (Autorin) +### 5.4 Als „Autor“ | Schritt | Erwartung | |---|---| @@ -246,7 +277,7 @@ lässt diesen Eintrag in Ruhe): | „Richte pub-release-notiz dauerhaft in diesem Repo ein.“ | trägt `pub-release-notiz` in `.hugin.yaml` ein und führt `hugin sync` aus (OpenCode fragt vorher nach Erlaubnis für den Befehl); **schreibt nicht selbst** nach `.opencode/commands/` | | Danach `hugin status` und `cat hugin.lock` | `pub-release-notiz` steht in beiden; die Datei `.opencode/commands/pub-release-notiz.md` hat Hugin geschrieben | | OpenCode neu starten, `/pub-release-notiz 2.0 Kunden` | der Befehl läuft | -| Als Anna eine neue Version von `pub-release-notiz` hochladen, Bert gibt frei; dann `hugin check` | meldet die neue Version (das geht nur, weil `hugin sync` installiert hat) | +| Als „Autor“ eine neue Version von `pub-release-notiz` hochladen, „Prüfer“ gibt frei; dann `hugin check` | meldet die neue Version (das geht nur, weil `hugin sync` installiert hat) | Gegenprobe ohne `hugin` im `PATH` (z. B. `env PATH=/usr/bin:/bin opencode`): Der Agent soll melden, dass `hugin` fehlt, und **nichts selbst schreiben**. Schreibt er die Datei @@ -265,7 +296,7 @@ Der automatische Test dazu: `scripts/tool-smoke-test.sh`, Prüfungen „Installi ### 5.9 Lokaler MCP-Server (Python) -Das Beispiel `pub-zeit-lokal` braucht nur die Standardbibliothek. Als Anna im Test-Repo +Das Beispiel `pub-zeit-lokal` braucht nur die Standardbibliothek. Als „Autor“ im Test-Repo aus Abschnitt 3 (mit `tools: [opencode]` oder `[claude, opencode]`): ```sh @@ -285,8 +316,8 @@ hugin try ~/repos/dev/hugin/contract/examples/packages/pub-zeit-lokal/1.0.0 | `hugin try --remove`, dann `hugin mcp prune --dry-run` | „würde löschen pub-zeit-lokal 1.0.0“ | | `mkdir -p /tmp/hugin-mcp/eigener && hugin mcp prune` | löscht nur das Hugin-Paket; `eigener` bleibt | -Freigabe und Verteilung: als Anna `hugin upload --submit` (persönlicher Key nötig, H043 -beim Projekt-Key), Risiko „Skripte“, also zwei Freigaben (Bert und Carla). Die +Freigabe und Verteilung: als „Autor“ `hugin upload --submit` (persönlicher Key nötig, H043 +beim Projekt-Key), Risiko „Skripte“, also zwei Freigaben („Prüfer“ und „Prüfer 2“). Die Versionsseite zeigt „Lokaler Server“ mit Ablage. Danach im Repo `pub-zeit-lokal` unter `packages` eintragen und `hugin sync`; `hugin check` meldet, wenn der Server auf dem Rechner fehlt. @@ -298,7 +329,7 @@ lehnt der Linter mit H037 ab. ### 5.10 OpenCode-Plugin -Das Beispiel `pub-specht-plugin` gibt OpenCode das Werkzeug `specht_marke`. Als Anna im +Das Beispiel `pub-specht-plugin` gibt OpenCode das Werkzeug `specht_marke`. Als „Autor“ im Test-Repo (`tools: [opencode]` oder `[claude, opencode]`): ```sh @@ -318,8 +349,8 @@ hugin try ~/repos/dev/hugin/contract/examples/packages/pub-specht-plugin/1.0.0 | `targets` auf `[claude, opencode]`, `hugin validate` | H038 | | `hugin try --remove` | Ordner und Startdatei weg | -Freigabe: `hugin upload --submit`, dann Bert und **Carla** (Tenant-Admin); mit Bert und -Dora allein bleibt es bei „Tenant-Admin nötig“. Danach abonnieren und `hugin sync`. +Freigabe: `hugin upload --submit`, dann „Prüfer“ und **„Admin“** (Tenant-Admin); mit „Prüfer“ und +„Prüfer 2“ allein bleibt es bei „Tenant-Admin nötig“. Danach abonnieren und `hugin sync`. ### 5.11 Windows (von Hand) diff --git a/contract/examples/packages/pub-commit-text/1.0.0/COMMAND.md b/contract/examples/packages/pub-commit-text/1.0.0/COMMAND.md new file mode 100644 index 0000000..f28a640 --- /dev/null +++ b/contract/examples/packages/pub-commit-text/1.0.0/COMMAND.md @@ -0,0 +1,10 @@ +Schlage eine Commit-Nachricht für die vorgemerkten Änderungen (git diff --cached) +vor. Committe nicht selbst. + +- Erste Zeile höchstens 72 Zeichen, im Imperativ, ohne Punkt am Ende. +- Danach eine Leerzeile und ein kurzer Text: warum die Änderung nötig ist und + was sich für Nutzer ändert. Das Was steht im Diff. +- Halte dich an die Form der letzten Commits im Repo, falls sie einheitlich ist. +- Mischt der Diff mehrere Themen, schlag vor, ihn aufzuteilen. + +Weitere Wünsche: $ARGUMENTS diff --git a/contract/examples/packages/pub-commit-text/1.0.0/hugin.yaml b/contract/examples/packages/pub-commit-text/1.0.0/hugin.yaml new file mode 100644 index 0000000..a076ff1 --- /dev/null +++ b/contract/examples/packages/pub-commit-text/1.0.0/hugin.yaml @@ -0,0 +1,7 @@ +id: pub-commit-text +kind: command +version: 1.0.0 +owner: kern +scope: public +description: Schlägt eine Commit-Nachricht für die vorgemerkten Änderungen vor. +license: intern diff --git a/contract/examples/packages/pub-doku-pruefer/1.0.0/AGENT.md b/contract/examples/packages/pub-doku-pruefer/1.0.0/AGENT.md new file mode 100644 index 0000000..d476064 --- /dev/null +++ b/contract/examples/packages/pub-doku-pruefer/1.0.0/AGENT.md @@ -0,0 +1,11 @@ +Du prüfst Dokumentation gegen den Code. Du änderst nichts, du schreibst nur Befunde. + +Prüfe: +- Befehle, Optionen, Umgebungsvariablen und Felder: gibt es sie im Code so? +- Beispiele: passen Aufrufe und Ausgaben zum aktuellen Verhalten? +- Verweise auf Dateien, Abschnitte und Adressen: gibt es das Ziel? +- Widersprüche zwischen zwei Stellen der Dokumentation. + +Für jeden Befund: Datei und Zeile der Dokumentation, was nicht stimmt, die +Stelle im Code als Beleg und ein Vorschlag für den neuen Text. Ohne Befund +sag kurz, was du geprüft hast. diff --git a/contract/examples/packages/pub-doku-pruefer/1.0.0/hugin.yaml b/contract/examples/packages/pub-doku-pruefer/1.0.0/hugin.yaml new file mode 100644 index 0000000..cb8cee6 --- /dev/null +++ b/contract/examples/packages/pub-doku-pruefer/1.0.0/hugin.yaml @@ -0,0 +1,12 @@ +id: pub-doku-pruefer +kind: subagent +version: 1.0.0 +owner: kern +scope: public +description: > + Prüft, ob Dokumentation und Code zusammenpassen: veraltete Befehle, Optionen, + Beispiele und Verweise. Nach Änderungen an Befehlen, Schnittstellen oder + Konfiguration einsetzen, bevor ein Pull Request entsteht. +capability: read +model: fast +license: intern diff --git a/contract/examples/packages/pub-doku-schreiben/1.0.0/SKILL.md b/contract/examples/packages/pub-doku-schreiben/1.0.0/SKILL.md new file mode 100644 index 0000000..1c9d995 --- /dev/null +++ b/contract/examples/packages/pub-doku-schreiben/1.0.0/SKILL.md @@ -0,0 +1,30 @@ +# Dokumentation schreiben + +## Vor dem Schreiben + +1. Kläre, wer liest: Nutzer, Entwicklerinnen im Team, Betrieb. Jede Gruppe + bekommt eigene Abschnitte, keine Mischung. +2. Suche, wo das Thema schon steht. Eine Sache steht an genau einer Stelle; + anderswo wird darauf verwiesen. + +## Beim Schreiben + +- Erst das Ergebnis, dann der Weg: Was kann man danach, welcher Befehl, was + kommt heraus. +- Jedes Beispiel muss so funktionieren, wie es dasteht. Befehle und Ausgaben + vorher ausprobieren oder aus dem Code ableiten. +- Kurze Sätze, aktive Form, ein Gedanke pro Absatz. Tabellen für Vergleiche, + Listen für Schritte. +- Fachbegriffe beim ersten Auftreten erklären oder auf das Glossar verweisen. + +## Kommentare im Code + +Kommentare erklären das Warum, nicht das Was: Annahmen, Grenzen, Gründe für +einen ungewöhnlichen Weg. Was der Code selbst sagt, kommt nicht in einen +Kommentar. + +## Nach Code-Änderungen + +Suche nach Namen von geänderten Befehlen, Optionen, Feldern und Fehlermeldungen +in der Dokumentation und passe jede Fundstelle an. Nenne am Ende, welche Dateien +du geändert hast und welche du geprüft, aber gelassen hast. diff --git a/contract/examples/packages/pub-doku-schreiben/1.0.0/hugin.yaml b/contract/examples/packages/pub-doku-schreiben/1.0.0/hugin.yaml new file mode 100644 index 0000000..2ece935 --- /dev/null +++ b/contract/examples/packages/pub-doku-schreiben/1.0.0/hugin.yaml @@ -0,0 +1,11 @@ +id: pub-doku-schreiben +kind: skill +version: 1.0.0 +owner: kern +scope: public +description: > + Dokumentation schreiben und pflegen: README, Anleitungen, Kommentare und + Änderungshinweise. Nutze diesen Skill, wenn du Dokumentation anlegst oder + änderst, oder wenn eine Code-Änderung Verhalten ändert, das irgendwo + beschrieben ist. +license: intern diff --git a/contract/examples/packages/pub-erklaeren/1.0.0/COMMAND.md b/contract/examples/packages/pub-erklaeren/1.0.0/COMMAND.md new file mode 100644 index 0000000..24c9042 --- /dev/null +++ b/contract/examples/packages/pub-erklaeren/1.0.0/COMMAND.md @@ -0,0 +1,8 @@ +Erkläre {{pfad}} für jemanden, der neu im Projekt ist. Ändere nichts. + +1. Wozu ist es da: ein bis zwei Sätze. +2. Wie hängt es mit dem Rest zusammen: wer ruft es auf, was ruft es auf. +3. Der Ablauf an einem typischen Beispiel, mit Verweisen auf Datei und Zeile. +4. Stolperstellen: Ungewöhnliches, Annahmen, bekannte Grenzen. + +Weitere Wünsche: $ARGUMENTS diff --git a/contract/examples/packages/pub-erklaeren/1.0.0/hugin.yaml b/contract/examples/packages/pub-erklaeren/1.0.0/hugin.yaml new file mode 100644 index 0000000..76e2f47 --- /dev/null +++ b/contract/examples/packages/pub-erklaeren/1.0.0/hugin.yaml @@ -0,0 +1,8 @@ +id: pub-erklaeren +kind: command +version: 1.0.0 +owner: kern +scope: public +description: Erklärt Code, eine Datei oder einen Ordner für jemanden, der neu im Projekt ist. +arguments: [pfad] +license: intern diff --git a/contract/examples/packages/pub-fehlersuche/1.0.0/SKILL.md b/contract/examples/packages/pub-fehlersuche/1.0.0/SKILL.md new file mode 100644 index 0000000..79d4ae0 --- /dev/null +++ b/contract/examples/packages/pub-fehlersuche/1.0.0/SKILL.md @@ -0,0 +1,34 @@ +# Fehlersuche + +## 1. Nachstellen + +Finde den kürzesten Weg, den Fehler auszulösen: ein Test, ein Befehl, eine +Eingabe. Ohne verlässliches Nachstellen gibt es keine verlässliche Behebung. + +## 2. Eingrenzen + +- Lies die vollständige Fehlermeldung und den Stacktrace, von unten nach oben. +- Vergleiche mit einem Zustand, in dem es ging: anderer Commit, andere Eingabe, + anderer Rechner. +- Halbiere den Suchraum: Eingabe verkleinern, Schritte weglassen, Ausgaben an + Zwischenstellen. + +## 3. Ursache belegen + +Formuliere eine Vermutung und prüfe sie mit einem Experiment, bevor du etwas +änderst. Eine Vermutung ist erst die Ursache, wenn sie das beobachtete Verhalten +vollständig erklärt. + +## 4. Beheben + +- Behebe die Ursache, nicht das Symptom. +- Schreibe, wo möglich, zuerst einen Test, der den Fehler zeigt, und mache ihn + dann grün. +- Prüfe, ob derselbe Fehler an anderen Stellen steckt. + +## Nicht + +- Mehrere Dinge auf einmal ändern. +- Fehler unterdrücken, Tests abschalten oder Wartezeiten einbauen, ohne die + Ursache zu kennen. +- Nach dem zweiten erfolglosen Versuch weiterraten: dann zurück zu Schritt 2. diff --git a/contract/examples/packages/pub-fehlersuche/1.0.0/hugin.yaml b/contract/examples/packages/pub-fehlersuche/1.0.0/hugin.yaml new file mode 100644 index 0000000..1d47574 --- /dev/null +++ b/contract/examples/packages/pub-fehlersuche/1.0.0/hugin.yaml @@ -0,0 +1,10 @@ +id: pub-fehlersuche +kind: skill +version: 1.0.0 +owner: kern +scope: public +description: > + Fehler systematisch finden statt raten: nachstellen, eingrenzen, Ursache + belegen, dann beheben. Nutze diesen Skill bei Fehlermeldungen, fehlschlagenden + Tests, falschem Verhalten oder wenn ein erster Behebungsversuch nicht gewirkt hat. +license: intern diff --git a/contract/examples/packages/pub-grill-me/1.0.0/SKILL.md b/contract/examples/packages/pub-grill-me/1.0.0/SKILL.md new file mode 100644 index 0000000..848e508 --- /dev/null +++ b/contract/examples/packages/pub-grill-me/1.0.0/SKILL.md @@ -0,0 +1,31 @@ +# Plan löchern + +Du bist ein kritisches, aber wohlwollendes Gegenüber. Ziel ist ein gemeinsames, +lückenloses Verständnis des Vorhabens, bevor jemand Code schreibt. + +## Ablauf + +1. Lass dir das Vorhaben in wenigen Sätzen beschreiben, falls es noch nicht + dasteht. Lies vorhandene Unterlagen und den betroffenen Code selbst, statt + danach zu fragen. +2. Stelle **eine Frage pro Nachricht**. Warte die Antwort ab. +3. Gib zu jeder Frage deine eigene Empfehlung mit kurzer Begründung. Die Person + soll bestätigen oder widersprechen können, statt bei null anzufangen. +4. Geh dem Entscheidungsbaum nach: Klärt eine Antwort einen Zweig, frage in + diesem Zweig weiter, bis er erledigt ist, dann der nächste. +5. Hör auf, wenn keine offene Entscheidung mehr übrig ist, nicht nach einer + festen Zahl von Fragen. + +## Worauf du fragst + +- Ziel und Erfolg: Woran merkt man, dass es fertig und gut ist? +- Grenzen: Was gehört ausdrücklich nicht dazu? +- Randfälle, Fehlerfälle, Last, gleichzeitige Zugriffe. +- Daten: woher, wohin, wem gehören sie, was passiert mit alten Daten? +- Betrieb: Rollout, Rückweg, Überwachung, Rechte. +- Annahmen, die niemand geprüft hat. + +## Am Ende + +Fasse zusammen: getroffene Entscheidungen, bewusst offene Punkte, nächste +Schritte. Keine Umsetzung, solange die Person nicht ausdrücklich darum bittet. diff --git a/contract/examples/packages/pub-grill-me/1.0.0/hugin.yaml b/contract/examples/packages/pub-grill-me/1.0.0/hugin.yaml new file mode 100644 index 0000000..9ec9735 --- /dev/null +++ b/contract/examples/packages/pub-grill-me/1.0.0/hugin.yaml @@ -0,0 +1,11 @@ +id: pub-grill-me +kind: skill +version: 1.0.0 +owner: kern +scope: public +description: > + Einen Plan, ein Konzept oder eine Idee gründlich löchern, bevor gebaut wird: + eine Frage nach der anderen, bis alle Lücken geklärt sind. Nutze diesen + Skill, wenn die Person „grill me“, „lös mich“, „stell mir Fragen“ oder „prüf + meinen Plan“ sagt, oder um ein Vorhaben vor der Umsetzung abzuklopfen. +license: intern diff --git a/contract/examples/packages/pub-plan/1.0.0/COMMAND.md b/contract/examples/packages/pub-plan/1.0.0/COMMAND.md new file mode 100644 index 0000000..cf89447 --- /dev/null +++ b/contract/examples/packages/pub-plan/1.0.0/COMMAND.md @@ -0,0 +1,10 @@ +Plane die folgende Aufgabe, setze sie aber noch nicht um: {{aufgabe}} + +1. Lies den betroffenen Code und nenne die Dateien, die sich ändern. +2. Beschreibe die Änderung in Schritten, die einzeln prüfbar sind. +3. Nenne Risiken, offene Fragen und was du bewusst weglässt. +4. Sag, wie man am Ende prüft, dass es funktioniert (Tests, Befehle). + +Warte danach auf Zustimmung oder Änderungswünsche. + +Weitere Wünsche: $ARGUMENTS diff --git a/contract/examples/packages/pub-plan/1.0.0/hugin.yaml b/contract/examples/packages/pub-plan/1.0.0/hugin.yaml new file mode 100644 index 0000000..f676b28 --- /dev/null +++ b/contract/examples/packages/pub-plan/1.0.0/hugin.yaml @@ -0,0 +1,8 @@ +id: pub-plan +kind: command +version: 1.0.0 +owner: kern +scope: public +description: Plant eine Aufgabe, bevor Code entsteht, und legt den Plan zur Abstimmung vor. +arguments: [aufgabe] +license: intern diff --git a/contract/examples/packages/pub-recherche/1.0.0/AGENT.md b/contract/examples/packages/pub-recherche/1.0.0/AGENT.md new file mode 100644 index 0000000..5176c14 --- /dev/null +++ b/contract/examples/packages/pub-recherche/1.0.0/AGENT.md @@ -0,0 +1,11 @@ +Du recherchierst eine Frage und änderst nichts. + +1. Suche zuerst im Projekt: Code, Dokumentation, Konfiguration. +2. Suche danach im Netz, bevorzugt in offizieller Dokumentation und in den + Quellen der Bibliothek. Achte auf die Version, die das Projekt nutzt. +3. Trenne Belegtes von Vermutetem. + +Antworte knapp: +- **Antwort:** zwei bis fünf Sätze. +- **Belege:** Datei und Zeile oder Adresse, je Aussage. +- **Offen:** was du nicht klären konntest. diff --git a/contract/examples/packages/pub-recherche/1.0.0/hugin.yaml b/contract/examples/packages/pub-recherche/1.0.0/hugin.yaml new file mode 100644 index 0000000..2660a8c --- /dev/null +++ b/contract/examples/packages/pub-recherche/1.0.0/hugin.yaml @@ -0,0 +1,12 @@ +id: pub-recherche +kind: subagent +version: 1.0.0 +owner: kern +scope: public +description: > + Recherchiert eine Frage im Code und im Netz und liefert eine knappe Antwort mit + Quellen. Einsetzen für Fragen zu Bibliotheken, Versionen, Fehlermeldungen oder + wie etwas im Projekt gelöst ist, damit der Hauptkontext schlank bleibt. +capability: [read, web] +model: standard +license: intern diff --git a/contract/examples/packages/pub-schlank/1.0.0/SKILL.md b/contract/examples/packages/pub-schlank/1.0.0/SKILL.md new file mode 100644 index 0000000..ffde2c8 --- /dev/null +++ b/contract/examples/packages/pub-schlank/1.0.0/SKILL.md @@ -0,0 +1,26 @@ +# Schlank umsetzen + +Ziel ist die kleinste Änderung, die die Aufgabe vollständig löst. + +## Vorgehen + +1. Formuliere in einem Satz, was nach der Änderung anders ist. Passt es nicht in + einen Satz, ist die Aufgabe zu groß; schlage eine Aufteilung vor. +2. Suche, was es schon gibt: vorhandene Funktionen, Bibliotheken des Projekts, + bestehende Muster. Wiederverwenden schlägt neu schreiben. +3. Ändere nur, was die Aufgabe verlangt. Kein Aufräumen nebenbei, kein + Umbenennen, keine Formatierung fremder Zeilen. +4. Prüfe am Ende jede neue Zeile: Würde etwas fehlen, wenn sie weg wäre? + +## Lass weg + +- Optionen, Parameter und Konfiguration, die heute niemand braucht. +- Abstraktionen für einen einzigen Fall (Interface mit einer Umsetzung, Fabrik + für ein Objekt). +- Fehlerbehandlung für Fälle, die nicht eintreten können. +- Neue Abhängigkeiten, wenn die Standardbibliothek reicht. + +## Sag es + +Siehst du sinnvolle Erweiterungen, nenne sie am Ende in einer kurzen Liste +„Bewusst weggelassen“, statt sie einzubauen. diff --git a/contract/examples/packages/pub-schlank/1.0.0/hugin.yaml b/contract/examples/packages/pub-schlank/1.0.0/hugin.yaml new file mode 100644 index 0000000..0cf55a3 --- /dev/null +++ b/contract/examples/packages/pub-schlank/1.0.0/hugin.yaml @@ -0,0 +1,11 @@ +id: pub-schlank +kind: skill +version: 1.0.0 +owner: kern +scope: public +description: > + Schlank umsetzen: die kleinste Änderung, die die Aufgabe löst, ohne Vorrat für + später. Nutze diesen Skill, wenn du Code schreibst oder änderst und die Person + „minimal“, „lean“, „einfach“ oder „nur das Nötige“ sagt, oder wenn eine Lösung + größer wird als die Aufgabe. +license: intern diff --git a/contract/examples/packages/pub-sicherheits-review/1.0.0/AGENT.md b/contract/examples/packages/pub-sicherheits-review/1.0.0/AGENT.md new file mode 100644 index 0000000..b4adab1 --- /dev/null +++ b/contract/examples/packages/pub-sicherheits-review/1.0.0/AGENT.md @@ -0,0 +1,12 @@ +Du prüfst Änderungen auf Sicherheitslücken. Du änderst nichts, du schreibst nur Befunde. + +Achte besonders auf: +- Eingaben von außen: Injection (SQL, Shell, Pfade), fehlende Prüfung, Größen. +- Anmeldung und Rechte: fehlende Prüfungen, Rechte ausweiten, fremde Daten lesen. +- Geheimnisse: Keys im Code, in Logs oder Fehlermeldungen. +- Dateien und Befehle: Pfade außerhalb des erlaubten Ordners, Ausführen von Eingaben. +- Abhängigkeiten: neue Pakete, unsichere Versionen. + +Für jeden Befund: Datei und Zeile, Schweregrad (hoch, mittel, niedrig), ein +konkretes Angriffsszenario und ein Vorschlag zur Behebung. Melde nur, was du am +Code belegen kannst; Vermutungen kennzeichnest du als solche. diff --git a/contract/examples/packages/pub-sicherheits-review/1.0.0/hugin.yaml b/contract/examples/packages/pub-sicherheits-review/1.0.0/hugin.yaml new file mode 100644 index 0000000..59a790d --- /dev/null +++ b/contract/examples/packages/pub-sicherheits-review/1.0.0/hugin.yaml @@ -0,0 +1,12 @@ +id: pub-sicherheits-review +kind: subagent +version: 1.0.0 +owner: kern +scope: public +description: > + Prüft Änderungen auf Sicherheitslücken: Eingaben, Rechte, Geheimnisse, + Abhängigkeiten. Einsetzen vor dem Merge von Änderungen an Anmeldung, Rechten, + Schnittstellen nach außen oder beim Umgang mit Dateien und Befehlen. +capability: read +model: thorough +license: intern diff --git a/scripts/demo.sh b/scripts/demo.sh index 1e4ea17..36d3d2f 100755 --- a/scripts/demo.sh +++ b/scripts/demo.sh @@ -11,6 +11,13 @@ # veröffentlicht die Beispielpakete und schreibt alle Keys nach .demo/keys.txt. set -euo pipefail +RESET="" +case "${1:-}" in + "") ;; + --neu|--new) RESET=1 ;; + *) echo "Unbekannt: $1 (erlaubt: --neu)"; exit 2 ;; +esac + ROOT="$(cd "$(dirname "$0")/.." && pwd)" DEMO="$ROOT/.demo" PORT="${PORT:-8080}" @@ -19,12 +26,12 @@ mkdir -p "$DEMO" if [[ -n "${HUGIN_DATABASE_URL:-}" ]]; then # Eigene Datenbank (z. B. PostgreSQL): die Keys gehören zu dieser Datenbank KEYS="$DEMO/keys-$(printf '%s' "$HUGIN_DATABASE_URL" | shasum | cut -c1-8).txt" - if [[ "${1:-}" == "--neu" ]]; then + if [[ -n "$RESET" ]]; then echo "--neu mit eigener Datenbank: Daten dort selbst löschen, z. B. docker compose down -v"; exit 2 fi else # Nur die SQLite-Demo verwerfen; Keys anderer Datenbanken (keys-*.txt) bleiben - [[ "${1:-}" == "--neu" ]] && rm -f "$DEMO"/hugin.db* "$DEMO/keys.txt" "$DEMO/server.log" + [[ -n "$RESET" ]] && rm -f "$DEMO"/hugin.db* "$DEMO/keys.txt" "$DEMO/server.log" export HUGIN_DATABASE_URL="sqlite:///$DEMO/hugin.db" KEYS="$DEMO/keys.txt" fi @@ -61,9 +68,10 @@ else done person() { api "${ADMIN[@]}" "$URL/api/v1/admin/tenants/$1/people" -d "$2" | field key; } key() { api "${ADMIN[@]}" "$URL/api/v1/admin/tenants/$1/keys" -d "$2" | field key; } - ANNA=$(person plattform '{"name":"Anna Autorin","mail":"anna@firma.de","project":"kern","roles":["pub_author"]}') - BERT=$(person plattform '{"name":"Bert Prüfer","mail":"bert@firma.de","roles":["pub_reviewer"]}') - CARLA=$(person plattform '{"name":"Carla Admin","mail":"carla@firma.de","roles":["pub_reviewer","tenant_admin"]}') + AUTHOR=$(person plattform '{"name":"Autor","mail":"autor@firma.de","project":"kern","roles":["pub_author"]}') + REVIEWER=$(person plattform '{"name":"Prüfer","mail":"pruefer@firma.de","roles":["pub_reviewer"]}') + REVIEWER2=$(person plattform '{"name":"Prüfer 2","mail":"pruefer2@firma.de","roles":["pub_reviewer"]}') + ADMIN_PERSON=$(person plattform '{"name":"Admin","mail":"admin@firma.de","roles":["pub_reviewer","tenant_admin"]}') SHOP_ADMIN=$(key shop '{"kind":"tenant","name":"Shop-Admin"}') SHOP_CI=$(key shop '{"kind":"project","name":"Shop CI","project":"api"}') SHOP_INT=$(key shop '{"kind":"integration","name":"Softwareverteilung"}') @@ -71,14 +79,19 @@ else publish() { local zip="$DEMO/package.zip" rm -f "$zip"; (cd "$ROOT/contract/examples/packages/$1" && zip -qr "$zip" .) - curl -fsS -H "Authorization: Bearer $ANNA" -H "Content-Type: application/zip" --data-binary "@$zip" "$URL/api/v1/drafts" >/dev/null + curl -fsS -H "Authorization: Bearer $AUTHOR" -H "Content-Type: application/zip" --data-binary "@$zip" "$URL/api/v1/drafts" >/dev/null local base="$URL/api/v1/packages/${1%/*}/versions/${1#*/}" - api -H "Authorization: Bearer $ANNA" -X POST "$base/submit" >/dev/null - [[ "${2:-}" == "open" ]] || api -H "Authorization: Bearer $BERT" "$base/approve" -d '{"comment":"Demo"}' >/dev/null + api -H "Authorization: Bearer $AUTHOR" -X POST "$base/submit" >/dev/null + [[ "${2:-}" == "open" ]] || api -H "Authorization: Bearer $REVIEWER" "$base/approve" -d '{"comment":"Demo"}' >/dev/null } for p in pub-munin-nutzen/1.4.0 pub-hausregeln/1.0.0 pub-munin-anbindung/1.0.0 pub-release-notiz/1.0.0 pub-code-review/1.0.0; do publish "$p" done + # Pakete für den Alltag: Skills, Befehle und Subagenten zum Ausprobieren + for p in pub-schlank pub-doku-schreiben pub-grill-me pub-fehlersuche pub-erklaeren pub-plan pub-commit-text \ + pub-recherche pub-doku-pruefer pub-sicherheits-review; do + publish "$p/1.0.0" + done publish pub-munin-nutzen/1.5.0 open # liegt bei den Prüfungen curl -fsS "${ADMIN[@]}" -X PUT -H "Content-Type: application/json" "$URL/api/v1/admin/mandatory/pub-munin-anbindung" -d '{"tenant":null}' api -H "Authorization: Bearer $SHOP_CI" "$URL/api/v1/usage" \ @@ -89,9 +102,10 @@ Hugin-Demo — Keys zum Anmelden unter $URL (nur für diese lokale Demo; .demo/ löschen oder scripts/demo.sh --neu) Plattform-Admin (alles, System) $HUGIN_ADMIN_TOKEN -Anna Autorin (pub_author, Person) $ANNA -Bert Prüfer (pub_reviewer, Person) $BERT -Carla Admin (Prüferin + Admin, Person) $CARLA +Autor (pub_author, Person) $AUTHOR +Prüfer (pub_reviewer, Person) $REVIEWER +Prüfer 2 (pub_reviewer, Person) $REVIEWER2 +Admin (Prüfer + Tenant-Admin, Person) $ADMIN_PERSON Shop-Admin (Tenant shop) $SHOP_ADMIN Shop CI (Projekt shop/api, lesen) $SHOP_CI Softwareverteilung (Integration shop) $SHOP_INT diff --git a/scripts/tool-smoke-test.sh b/scripts/tool-smoke-test.sh index 4ce380e..7d6a7bb 100755 --- a/scripts/tool-smoke-test.sh +++ b/scripts/tool-smoke-test.sh @@ -61,10 +61,10 @@ AUTHOR=$(api "${ADMIN[@]}" "$URL/api/v1/admin/tenants/plattform/keys" -d '{"kind REVIEWER=$(api "${ADMIN[@]}" "$URL/api/v1/admin/tenants/plattform/keys" -d '{"kind":"project","name":"pruefer","project":"kern","roles":["pub_reviewer"]}' | key) READER=$(api "${ADMIN[@]}" "$URL/api/v1/admin/tenants/plattform/keys" -d '{"kind":"project","name":"leser","project":"kern"}' | key) # Lokaler Server hat Risiko „Skripte“: persönlicher Key, zwei Freigaben von Personen -# Plugin hat Risiko „Rechte“: eine der zwei Freigaben vom Tenant-Admin (Carla) +# Plugin hat Risiko „Rechte“: eine der zwei Freigaben vom Tenant-Admin person() { api "${ADMIN[@]}" "$URL/api/v1/admin/tenants/plattform/people" -d "{\"name\":\"$1\",\"mail\":\"$1@smoke.test\",\"project\":\"kern\",\"roles\":$2}" | key; } -ANNA=$(person anna '["pub_author"]'); BERT=$(person bert '["pub_reviewer"]'); DORA=$(person dora '["pub_reviewer"]') -CARLA=$(person carla '["pub_reviewer","tenant_admin"]') +PERSON_AUTHOR=$(person autor '["pub_author"]'); PERSON_REVIEWER=$(person pruefer '["pub_reviewer"]') +PERSON_REVIEWER2=$(person pruefer2 '["pub_reviewer"]'); PERSON_ADMIN=$(person admin '["pub_reviewer","tenant_admin"]') # MCP-Paket zeigt auf diesen Hugin selbst; so lässt sich auch die Verbindung prüfen PACKAGES="$WORK/packages" @@ -95,8 +95,8 @@ publish() { publish_example() { local zip="$WORK/package.zip" id=$1 base="$URL/api/v1/packages/$1/versions/1.0.0"; shift rm -f "$zip"; (cd "$ROOT/contract/examples/packages/$id/1.0.0" && zip -qr "$zip" .) - curl -fsS -H "Authorization: Bearer $ANNA" -H "Content-Type: application/zip" --data-binary "@$zip" "$URL/api/v1/drafts" >/dev/null - api -H "Authorization: Bearer $ANNA" -X POST "$base/submit" >/dev/null + curl -fsS -H "Authorization: Bearer $PERSON_AUTHOR" -H "Content-Type: application/zip" --data-binary "@$zip" "$URL/api/v1/drafts" >/dev/null + api -H "Authorization: Bearer $PERSON_AUTHOR" -X POST "$base/submit" >/dev/null for r in "$@"; do api -H "Authorization: Bearer $r" "$base/approve" -d '{"comment":"Rauchtest"}' >/dev/null; done } @@ -105,9 +105,9 @@ IDS=(pub-smoke-skill pub-smoke-manual pub-smoke-rules pub-smoke-command pub-smok for id in "${IDS[@]}"; do publish "$id"; done # Lokaler MCP-Server (Python, nur Standardbibliothek): hugin sync installiert ihn nach # HUGIN_MCP_HOME, die Werkzeuge starten ihn über hugin mcp run -publish_example pub-zeit-lokal "$BERT" "$DORA"; IDS+=(pub-zeit-lokal) +publish_example pub-zeit-lokal "$PERSON_REVIEWER" "$PERSON_REVIEWER2"; IDS+=(pub-zeit-lokal) # OpenCode-Plugin mit eigenem Werkzeug; Claude Code bekommt davon nichts -publish_example pub-specht-plugin "$BERT" "$CARLA"; IDS+=(pub-specht-plugin) +publish_example pub-specht-plugin "$PERSON_REVIEWER" "$PERSON_ADMIN"; IDS+=(pub-specht-plugin) export HUGIN_MCP_HOME="$WORK/mcp" ZEIT_ZONE_HINWEIS=smoke (cd "$ROOT/cli" && go build -o "$WORK/bin/hugin" ./cmd/hugin) ln -s "$WORK/bin/hugin" "$WORK/hugin" diff --git a/server/tests/test_linter.py b/server/tests/test_linter.py index ae9a35b..2b51e4b 100644 --- a/server/tests/test_linter.py +++ b/server/tests/test_linter.py @@ -23,6 +23,9 @@ def ids(p: Package, context: Context = Context()) -> list[str]: @pytest.mark.parametrize("name", [ "pub-munin-nutzen/1.4.0", "pub-munin-nutzen/1.5.0", "pub-hausregeln/1.0.0", "pub-munin-anbindung/1.0.0", "pub-release-notiz/1.0.0", "pub-code-review/1.0.0", "pub-zeit-lokal/1.0.0", "pub-specht-plugin/1.0.0", + "pub-schlank/1.0.0", "pub-doku-schreiben/1.0.0", "pub-grill-me/1.0.0", "pub-fehlersuche/1.0.0", + "pub-erklaeren/1.0.0", "pub-plan/1.0.0", "pub-commit-text/1.0.0", + "pub-recherche/1.0.0", "pub-doku-pruefer/1.0.0", "pub-sicherheits-review/1.0.0", ]) def test_examples_are_error_free(name): assert error_free(validate(example(name)))