From bdeb27b7751e6f970e6dc964ab0ac6ed5c25ff99 Mon Sep 17 00:00:00 2001 From: m3ta-chiron Date: Fri, 18 Sep 2026 10:06:33 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20explain-permissions=20v1.3.0=20?= =?UTF-8?q?=E2=80=94=20Erkl=C3=A4rungen=20als=20Zitat-Block=20mit=20Zeilen?= =?UTF-8?q?struktur?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - SYSTEM_PROMPT_RULE: Erklärung als Markdown-Zitat-Block (>) mit fetten Labels, jeder Punkt (WAS passiert/WELCHE FOLGEN/WIE RISKANT) auf eigener Zeile — bessere Lesbarkeit + visuelle Hervorhebung in TUI und Desktop (beide rendern Blockquotes mit farbigem Balken; opencode 1.18.30 bietet keinen Anzeige-Transform-Hook, experimental.chat.messages.transform wirkt nur modellseitig — verifiziert) - Desktop-Notifications: neuer plainText()-Filter streicht Markdown-Marker (>, **) aus dem Toast-Text - EXPLAIN_FIRST_ERROR verweist auf das neue Block-Format - READMEs: Zweck + Versionierung ergänzt, Root-Tabelle auf v1.3.0 --- README.md | 2 +- explain-permissions/README.md | 14 +++++++- explain-permissions/explain-permissions.js | 42 +++++++++++++++------- 3 files changed, 44 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index b35bda0..135fae0 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Das Repos ist **anonym lesbar** (kein Token für Pulls nötig), Schreiben läuft | Plugin | Zweck | Version | |---|---|---| -| [`explain-permissions/`](explain-permissions/) | Erklärt jeden freigabepflichtigen Tool-Call laienverständlich (Was/Folgen/Risiko), Desktop-Notification + Audit-Log | v1.2.0 | +| [`explain-permissions/`](explain-permissions/) | Erklärt jeden freigabepflichtigen Tool-Call laienverständlich (Was/Folgen/Risiko) als hervorgehobener Zitat-Block, Desktop-Notification + Audit-Log | v1.3.0 | ## Struktur & Konventionen diff --git a/explain-permissions/README.md b/explain-permissions/README.md index d0a3b81..7de664b 100644 --- a/explain-permissions/README.md +++ b/explain-permissions/README.md @@ -20,7 +20,12 @@ Menschen ohne Computer-Kenntnisse. Das Plugin: 1. **Injiziert die Freigabe-Regel in den System-Prompt** (Was / Welche Folgen / Wie riskant, auf Deutsch, vor jedem freigabepflichtigen Call) — inklusive - der konkreten ask-/allow-Muster aus der opencode-Konfiguration. + der konkreten ask-/allow-Muster aus der opencode-Konfiguration. Seit v1.3.0 + mit festem Ausgabeformat: Zitat-Block (`>`) mit fetten Labels, jeder Punkt + auf eigener Zeile. TUI und OpenCode Desktop rendern das als abgesetzten + Kasten mit farbigem Balken — die Erklärung hebt sich damit klar vom restlichen + Chatverlauf ab, und die drei Punkte bleiben sauber untereinander lesbar. + Desktop-Notifications bekommen reinen Text (Markdown-Marker werden entfernt). 2. **Schickt eine Desktop-Notification**, wenn der Freigabe-Dialog erscheint — mit der deutschen Erklärung des Modells, Fallback: der Roh-Befehl. 3. **Schreibt ein JSONL-Audit-Log**: jeden Freigabe-Request (`ask`), die @@ -105,6 +110,13 @@ Chat-Session im laufenden Prozess reicht nicht. Der Audit-Log-Eintrag ## Versionierung +- `explain-permissions/v1.3.0` — Erklärungs-Format überarbeitet: Zitat-Block + (`>`) mit fetten Labels (`**WAS passiert:**` usw.), jeder Punkt auf eigener + Zeile — bessere Lesbarkeit und visuelle Hervorhebung in TUI und Desktop + (beide rendern Blockquotes mit farbigem Balken; verifiziert gegen opencode + 1.18.30, das keinen Anzeige-Transform-Hook bietet — `experimental.chat.messages.transform` + wirkt nur modellseitig). Desktop-Notifications erhalten reinen Text ohne + Markdown-Marker; `EXPLAIN_FIRST_ERROR` verweist auf das neue Format. - `explain-permissions/v1.2.0` — Cross-Platform-Notifications (Linux notify-send / macOS osascript / Windows PowerShell-Toast mit PowerShell-AUMID, keine App-Registrierung), fail-soft Spawn in Node- und Bun-Runtimes, diff --git a/explain-permissions/explain-permissions.js b/explain-permissions/explain-permissions.js index d920e15..7113cb0 100644 --- a/explain-permissions/explain-permissions.js +++ b/explain-permissions/explain-permissions.js @@ -1,7 +1,7 @@ // explain-permissions.js — opencode plugin // // Kanonische Quelle: git.az-gruppe.com/AZ-Intec-GmbH/opencode-plugins -// (Tag explain-permissions/v1.2.0). Fleet-Bezug: az-fleet vendort diese +// (Tag explain-permissions/v1.3.0). Fleet-Bezug: az-fleet vendort diese // Datei nach config/managed/plugins/ (Pin mit sha256 dort in // roles/managed_config — Byte-Gleichheit ist Vertragsgrundlage). // @@ -23,7 +23,9 @@ // 3. experimental.chat.system.transform: // → injiziert die Regel "Erst laienverständlich erklären (Was/Folgen/Risiko), // dann der Call" in den System-Prompt — in jeder Session, auch in Worktrees -// ohne eigenes AGENTS.md +// ohne eigenes AGENTS.md. Seit v1.3.0 mit festem Ausgabeformat: Zitat-Block +// (>) mit fetten Labels, jeder Punkt auf eigener Zeile — TUI und Desktop +// rendern das als klar abgesetzten Kasten mit farbigem Balken. // 4. Optional (env OPENCODE_EXPLAIN_ENFORCE=1): tool.execute.before wirft einen // Fehler, wenn das Modell einen berechtigungspflichtigen Call OHNE vorherige // Text-Erklärung im selben Message-Turn absetzt. Default: AUS (Dialog-Schleifen). @@ -63,7 +65,7 @@ import os from "node:os"; import { spawn } from "node:child_process"; const ENV = process.env; -const PLUGIN_VERSION = "1.2.0"; +const PLUGIN_VERSION = "1.3.0"; const NOTIFY = ENV.OPENCODE_EXPLAIN_NOTIFY !== "0"; const LOG = ENV.OPENCODE_EXPLAIN_LOG !== "0"; const INJECT = ENV.OPENCODE_EXPLAIN_INJECT !== "0"; @@ -82,22 +84,32 @@ function defaultLogPath() { const LOG_PATH = ENV.OPENCODE_EXPLAIN_LOG_PATH || defaultLogPath(); const SYSTEM_PROMPT_RULE = `## Tool-Call-Erklärungen (verpflichtend, laienverständlich) -Vor JEDEM Tool-Call, der eine Freigabe erfordert, schreibe unmittelbar davor eine Erklärung auf Deutsch, die ein Mensch ohne Computer-Kenntnisse versteht. Struktur: -- WAS passiert: in Alltagssprache — nicht wie der Befehl heißt, sondern was er bewirkt -- WELCHE FOLGEN: Was ist danach anders? Ist es rückgängig machbar? Sind eigene Dateien gefährdet? -- WIE RISKANT: harmlos / wiederherstellbar / dauerhaft +Vor JEDEM Tool-Call, der eine Freigabe erfordert, schreibe unmittelbar davor eine Erklärung auf Deutsch, die ein Mensch ohne Computer-Kenntnisse versteht. -Beispiel (gut): „Ich lösche jetzt den Ordner „foo" im temporären Bereich samt allem, was darin liegt. Das lässt sich nicht rückgängig machen — es betrifft aber nur diesen einen Ordner, deine anderen Dateien bleiben unberührt." -Beispiel (schlecht, zu technisch): „Ich führe rm -rf /tmp/foo aus." +Format — GENAU SO einhalten (dient der Lesbarkeit und Hebung im Chat): +- Die gesamte Erklärung als Zitat-Block: JEDE Zeile beginnt mit „> “ +- Jeder der drei Punkte auf EIGENER Zeile — nie alle hintereinander in einer Zeile +- Die Labels fettgedruckt + +> **WAS passiert:** in Alltagssprache — nicht wie der Befehl heißt, sondern was er bewirkt +> **WELCHE FOLGEN:** Was ist danach anders? Ist es rückgängig machbar? Sind eigene Dateien gefährdet? +> **WIE RISKANT:** harmlos / wiederherstellbar / dauerhaft + +Beispiel (gut): +> **WAS passiert:** Ich lege eine neue, leere Datei namens „Neue Textdatei.txt“ im Ordner „Documents\\Default Project“ an. +> **WELCHE FOLGEN:** Es gibt danach eine zusätzliche Datei im Arbeitsordner, die du jederzeit löschen kannst. Nichts Bestehendes wird verändert. +> **WIE RISKANT:** harmlos. + +Beispiel (schlecht, zu technisch): „Ich führe rm -rf /tmp/foo aus.“ Regeln: -- Der genaue Befehl darf NACH der Erklärung zusätzlich genannt werden, die Erklärung muss aber auch ohne ihn verständlich sein +- Der genaue Befehl darf NACH dem Erklärungs-Block zusätzlich genannt werden, die Erklärung muss aber auch ohne ihn verständlich sein - Kein Fachjargon (rm, rekursiv, force, Pipe, Exit-Code) ohne Umschreibung - Erst die Erklärung, dann der Call — niemals umgekehrt - Rein lesende, automatisch erlaubte Standard-Calls brauchen keine Extra-Erklärung - Im Zweifel, ob ein Call eine Freigabe braucht: immer erklären`; -const EXPLAIN_FIRST_ERROR = `EXPLAIN_FIRST: Du hast den Tool-Call ohne vorherige Erklärung abgesetzt. Schreibe zuerst 1-2 Sätze auf Deutsch, laienverständlich (kein Fachjargon): Was macht der Call, welche Folgen hat er, wie riskant ist er? Führe den Call danach erneut aus.`; +const EXPLAIN_FIRST_ERROR = `EXPLAIN_FIRST: Du hast den Tool-Call ohne vorherige Erklärung abgesetzt. Schreibe zuerst eine Erklärung auf Deutsch, laienverständlich (kein Fachjargon) — als Zitat-Block („> “), jeder Punkt auf eigener Zeile: **WAS passiert:** / **WELCHE FOLGEN:** / **WIE RISKANT:**. Führe den Call danach erneut aus.`; const PERMISSION_KEYS = [ "bash", @@ -200,6 +212,12 @@ function notify(title, body) { else runDetached("notify-send", ["-a", "opencode", "-i", "utilities-terminal", "-u", "normal", title, b]); } +// Desktop-Notifications render kein Markdown: Zitat-Marker (>) und Fett- +// Marker (**) aus der Erklärung entfernen, bevor sie in den Toast geht. +function plainText(s) { + return s.replace(/^[ \t]*>[ \t]?/gm, "").replace(/\*\*/g, ""); +} + function debugLog(source, payload) { if (!DEBUG) return; let serialized; @@ -376,7 +394,7 @@ async function explainAndNotify(client, p) { } const body = explanation - ? `${explanation}\n—\n${type}: ${rawCall}\n→ im opencode-UI antworten` + ? `${plainText(explanation)}\n—\n${type}: ${rawCall}\n→ im opencode-UI antworten` : `${rawCall}\n→ im opencode-UI antworten`; notify(`opencode · Freigabe nötig (${type})`, body); }