Tasks liste + liste_filtern; MCP: task_list, task_doc, task_search, workflow_lint

This commit is contained in:
erik
2026-07-08 17:19:46 +02:00
parent b6e48c3ebb
commit b652759bfc
3 changed files with 149 additions and 0 deletions
+19
View File
@@ -1,5 +1,24 @@
# Changelog
## 2026-07-08 (Listen-Tasks + MCP-Katalog)
- **Neu: Task `liste`** — Tabelle direkt im Editor pflegen (freie Spalten, z. B. name/mail/rolle).
Ergebnis ist eine Liste aus Zeilen-Objekten: `{{var}}` (loop_foreach), `{{var}}_json`,
`{{var}}_anzahl`, `{{var}}_leer` und je Spalte `{{var}}_<spalte>_liste` (fertiger Mail-Verteiler).
Zellen dürfen Platzhalter enthalten.
- **Neu: Task `liste_filtern`** — Zeilen nach Bedingungen auswählen (`ist`, `enthaelt`, `endet_auf`,
`groesser`, `in`, … ; `und`/`oder`). Quelle ist jede Liste (Task `liste`, `person_pick`,
`json_transform`, JSON-String oder Komma-Liste). Zusätzlich `{{var}}_entfernt`.
- **Editor: neuer Feldtyp `table`** — echtes Zeilenraster, feste oder dynamische Spalten
(`columnsFrom`); Kopfzeile zieht nach, wenn `spalten` geändert wird.
- **MCP: vier neue Werkzeuge** (token-sparsam entworfen):
- `task_list` — alle Task-Typen mit Einzeiler, optional Volltextfilter; `interaktiv=true` markiert
Tasks, die `<assign_to>` brauchen.
- `task_doc` — Doku zu MEHREREN Tasks in EINEM Aufruf; `format=xml|kurz|md` (≈1/10, 1/3, voll).
- `task_search` — findet den passenden Task zu einer Aufgabenbeschreibung.
- `workflow_lint` — statische Prüfung: unbekannte Task-Typen, doppelte ids, fehlende
Pflichtparameter, interaktive Tasks ohne `<assign_to>`. Fängt ab, was sonst erst beim Start auffällt.
## 2026-07-08 (Bauakte-Vergabe: Stempelauswahl, Ordnerfilter, Docroot-Fix)
- **`pdf_stamp_interactive`: Stempelart zur Laufzeit wählbar.** Neue Parameter `stempel_auswahl`
+73
View File
@@ -0,0 +1,73 @@
# `liste` — Tabelle im Editor pflegen
**Zweck:** Definiert eine feste Liste (Tabelle) direkt im Task-Editor — Spalten frei wählbar, z. B. `name`, `mail`, `rolle`. Das Ergebnis ist eine **Liste im Workflow-Sinn**: ein Array aus Zeilen-Objekten. Damit lässt sie sich ohne Umweg in `loop_foreach` durchlaufen (personalisierte Anrede), mit `liste_filtern` einschränken oder als fertiger Mail-Verteiler verwenden.
**Parameter**
| Name | Pflicht? | Default | Beschreibung |
|---|---|---|---|
| `spalten` | ja | — | Komma-Liste der Spaltennamen, z. B. `name,mail,rolle`. Nur Buchstaben, Ziffern, `_`. |
| `zeilen` | nein | *(leer)* | Container mit `<zeile>`-Elementen; ein Attribut je Spalte. Zellen dürfen `{{variablen}}` enthalten. |
| `output_var` | ja | `liste` | Präfix der Ergebnisvariablen. |
Zeilen, die in **allen** Spalten leer sind, werden verworfen. Fehlende Spalten einer Zeile werden als leerer String ergänzt, damit alle Zeilen dieselbe Form haben. Attribute, die nicht in `spalten` stehen, werden ignoriert.
**Eingangswerte:** beliebige Kontextvariablen in den Zellen.
**Ausgangswerte** (Präfix = `output_var`, hier `empfaenger`)
| Variable | Beschreibung |
|---|---|
| `{{empfaenger}}` | Array der Zeilen — direkt als `<items>` für `loop_foreach` |
| `{{empfaenger_json}}` | dieselbe Liste als JSON-String |
| `{{empfaenger_anzahl}}` | Anzahl der Zeilen |
| `{{empfaenger_leer}}` | `1`, wenn die Liste leer ist (praktisch für `<task type="if">`) |
| `{{empfaenger_<spalte>_liste}}` | Komma-Liste aller Werte dieser Spalte, z. B. `{{empfaenger_mail_liste}}` = fertiger Verteiler |
```xml
<task type="liste" id="empfaenger">
<config>
<spalten>name,mail,rolle</spalten>
<output_var>empfaenger</output_var>
<zeilen>
<zeile name="Max Mustermann" mail="max@vlnsachsen.de" rolle="Vorstand"/>
<zeile name="Erika Muster" mail="erika@extern.de" rolle="Mitglied"/>
</zeilen>
</config>
</task>
```
**Personalisierte Anrede** — die Liste in `loop_foreach` durchlaufen; jedes Feld steht als `{{p.feld}}` und `{{p_feld}}` bereit:
```xml
<task type="loop_foreach" id="anschreiben">
<items>{{empfaenger}}</items>
<as>p</as>
<task type="email" id="brief">
<config>
<an>{{p.mail}}</an>
<titel>Einladung</titel>
<text>Sehr geehrte(r) {{p.name}},
als {{p.rolle}} laden wir Sie ein …</text>
</config>
</task>
</task>
```
**Sammel-Mail an alle** — ohne Schleife, über die Spalten-Komma-Liste:
```xml
<task type="email" id="rundmail">
<config>
<an>{{empfaenger_mail_liste}}</an>
<titel>Information</titel>
<text></text>
</config>
</task>
```
**Fallen / Hinweise**
- Spaltennamen werden Teil von Variablennamen — daher nur `[A-Za-z_][A-Za-z0-9_]*`.
- Im visuellen Editor erscheint die Tabelle als echtes Zeilenraster; die Kopfzeile zieht nach, sobald `spalten` geändert wird.
- Für dynamische Listen (aus Auswahl-Tasks, Webhooks, JSON) ist der Task nicht nötig — `liste_filtern`, `loop_foreach` und `json_transform` arbeiten auf derselben Struktur.
+57
View File
@@ -0,0 +1,57 @@
# `liste_filtern` — Zeilen einer Liste auswählen
**Zweck:** Schränkt eine Liste anhand von Bedingungen ein, z. B. „nur Vorstände" oder „nur interne Mailadressen". Quelle ist jede Liste im Workflow-Sinn — aus `liste`, `person_pick`, `json_transform`, einem Webhook oder einer Komma-Liste. Das Ergebnis hat dieselbe Form wie die Quelle und lässt sich direkt weiterverwenden (`loop_foreach`, Mail-Verteiler, erneut filtern).
**Parameter**
| Name | Pflicht? | Default | Beschreibung |
|---|---|---|---|
| `liste` | ja | — | Quelle: `{{empfaenger}}`, JSON-String oder Komma-Liste. |
| `bedingungen` | nein | *(keine)* | Container mit `<bedingung spalte="…" operator="…" wert="…"/>`. Ohne Bedingung bleibt die Liste unverändert. |
| `verknuepfung` | nein | `und` | `und` = alle Bedingungen müssen zutreffen, `oder` = mindestens eine. |
| `output_var` | ja | `gefiltert` | Präfix der Ergebnisvariablen. |
**Operatoren**
| Operator | Bedeutung |
|---|---|
| `ist`, `ist_nicht` | exakter Vergleich (case-insensitiv) |
| `enthaelt`, `enthaelt_nicht` | Teilstring |
| `beginnt_mit`, `endet_auf` | Präfix / Suffix — z. B. `endet_auf @vlnsachsen.de` |
| `leer`, `nicht_leer` | Zelle ohne bzw. mit Inhalt (`wert` wird ignoriert) |
| `groesser`, `kleiner`, `groesser_gleich`, `kleiner_gleich` | numerischer Vergleich; deutsches Format (`1.234,50`) wird verstanden |
| `in`, `nicht_in` | `wert` ist eine Komma-Liste erlaubter Werte |
Ein unbekannter Operator ist ein Fehler (kein stilles Durchreichen). Vergleiche sind case-insensitiv.
**Eingangswerte:** die Liste unter `liste`; Platzhalter in `spalte` und `wert` werden gerendert.
**Ausgangswerte** (Präfix = `output_var`, hier `vorstand`)
| Variable | Beschreibung |
|---|---|
| `{{vorstand}}` | gefilterte Zeilen (Array) |
| `{{vorstand_json}}` | dieselbe Liste als JSON |
| `{{vorstand_anzahl}}` | Zeilen nach dem Filter |
| `{{vorstand_entfernt}}` | Zahl der aussortierten Zeilen |
| `{{vorstand_leer}}` | `1`, wenn nichts übrig blieb |
| `{{vorstand_<spalte>_liste}}` | Komma-Liste je Spalte, z. B. `{{vorstand_mail_liste}}` |
```xml
<task type="liste_filtern" id="nur_vorstand">
<config>
<liste>{{empfaenger}}</liste>
<verknuepfung>und</verknuepfung>
<output_var>vorstand</output_var>
<bedingungen>
<bedingung spalte="rolle" operator="ist" wert="Vorstand"/>
<bedingung spalte="mail" operator="endet_auf" wert="@vlnsachsen.de"/>
</bedingungen>
</config>
</task>
```
**Fallen / Hinweise**
- Eine Komma-Liste als Quelle (`a@x.de, b@y.de`) wird zu Zeilen mit der einen Spalte `wert`.
- Verschachtelte Werte (Arrays/Objekte in einer Zelle) werden verworfen — Listen sind bewusst flach.
- Leeres Ergebnis ist kein Fehler; mit `{{<var>_leer}}` in einem `if` abfangen, bevor eine Mail an niemanden geht.