refactor: v2.0.0 als Verzeichnis-Package v2/index.js + v1/ eingefroren

E2E-Befund vm-test (2.0.16): Einzeldatei-Plugin-Einträge werden mit
'configured plugin path must be a directory' verworfen — V2 verlangt
Verzeichnis-Packages. Layout: v1/explain-permissions.js (1.3.0, Fleet-Pin,
SHA unverändert f02a153d…) + v2/index.js (2.0.0, getesteter Stand
fe2e78c0…). Event-Namen empirisch korrigiert: permission.asked/replied.
This commit is contained in:
m3ta-chiron
2026-09-25 10:01:58 +02:00
parent cbc1cb739f
commit 5be32a6fe6
3 changed files with 490 additions and 19 deletions
+36 -19
View File
@@ -2,9 +2,19 @@
Dieses Verzeichnis ist die **kanonische Quelle** für das opencode-Plugin
`explain-permissions`. Es lebt im Sammel-Repos
[`opencode-plugins`](../README.md) und besteht aus genau einer Plugin-Datei
(`explain-permissions.js`) plus dieser Doku. Wer das Plugin nutzt, bezieht es
von hier — es gibt bewusst keine zweiten Solo-Kopien.
[`opencode-plugins`](../README.md) und besteht aus dieser Doku plus je einer
Plugin-Fassung pro Major-API — es gibt bewusst keine zweiten Solo-Kopien:
| Pfad | Fassung | Status |
|---|---|---|
| `v1/explain-permissions.js` | 1.3.0 (V1-Plugin-API, Einzeldatei) | eingefroren — aktiver Fleet-Pin (ADR-0010) |
| `v2/index.js` | 2.0.0 (V2-Plugin-API, **Verzeichnis-Package**) | V2-only-Cut (az-fleet-7x8) — Pin aktiviert mit dem V2-Rollout |
opencode V2 (verifiziert 2.0.16, vm-test) lädt **keine Einzeldatei-Plugin-
Einträge** — `file:///…/<datei>.js` wird mit der Log-Warnung
`configured plugin path must be a directory` verworfen. `v2/` ist deshalb
ein Verzeichnis-Package mit `index.js` als Entrypoint (kein `package.json`
erforderlich); ausgerollt wird das Verzeichnis als Ganzes.
Konsumenten:
@@ -35,11 +45,11 @@ Menschen ohne Computer-Kenntnisse. Das Plugin:
## Installation
### Lokale Kiste (Checkout + Symlink)
### Lokale Kiste (Checkout + Symlink, V1)
```bash
git clone https://git.az-gruppe.com/AZ-Intec-GmbH/opencode-plugins.git ~/p/AZ/opencode-plugins
ln -sf ~/p/AZ/opencode-plugins/explain-permissions/explain-permissions.js ~/.config/opencode/plugins/explain-permissions.js
ln -sf ~/p/AZ/opencode-plugins/explain-permissions/v1/explain-permissions.js ~/.config/opencode/plugins/explain-permissions.js
```
Danach opencode neu starten (siehe unten). Wichtig: nur EINE Datei dieses
@@ -47,20 +57,21 @@ Namens im Plugin-Ordner — sonst lädt opencode das Plugin doppelt.
### opencode V2 (ab v2.0.0 — V2-only)
Die Datei exportiert `Plugin.define({id: "az.explain-permissions", setup})`
als Default-Export und wird in `opencode.json(c)` unter dem V2-Schlüssel
`plugins` referenziert (Einzel-Datei-Eintrag, absolute `file:///`-URL):
`v2/index.js` exportiert `Plugin.define({id: "az.explain-permissions", setup})`
als Default-Export. Referenziert wird das **Verzeichnis** `v2/` (umgenannt
nach Wunsch, z. B. `explain-permissions-v2/`) unter dem V2-Schlüssel
`plugins` mit absoluter `file:///`-URL:
```jsonc
{
"plugins": [{ "package": "file:///C:/ProgramData/opencode/plugins/explain-permissions.js" }]
"plugins": [{ "package": "file:///C:/ProgramData/opencode/plugins/explain-permissions-v2" }]
}
```
Alternativ läuft die Datei auch unverändert als Datei-Plugin in
`~/.config/opencode/plugins/` bzw. `.opencode/plugins/` (dort wird sie
automatisch entdeckt, kein Config-Eintrag nötig). Benötigt opencode V2
(Core 2.0.x); V1 (1.18.x) lädt sie bewusst NICHT (V2-only-Cut) — die V1-Fleet
Alternativ läuft das Verzeichnis auch unverändert als Plugin-Package in
`~/.config/opencode/plugins/` bzw. `.opencode/plugins/` (dort automatisch
entdeckt, kein Config-Eintrag nötig). Benötigt opencode V2 (Core 2.0.x);
V1 (1.18.x) lädt es bewusst NICHT (V2-only-Cut) — die V1-Fleet
bleibt auf der gepinnten v1.3.0.
### Fleet
@@ -138,7 +149,7 @@ laden automatisch neu.
| Config-Schlüssel `"plugin": ["file:///…"]` | `"plugins": [{"package": "file:///…"}]` (Einzel-Datei-Einträge unterstützt) |
| `hooks.config` (liest permission-Sektion) | entfallen — Config-Dateien direkt per `fs` gelesen (Managed-Verzeichnis, Global, Projekt, `OPENCODE_CONFIG`), **beide** Formate: V1-`permission`-Map + V2-`permissions`-Array; Action-Renames bash→shell, task→subagent, write/patch→edit; `lsp`/`doom_loop` sind in V2 tote Actions und werden verworfen |
| `permission.ask`-Hook + `permission.asked/updated`-Events | `ctx.permission.hook("evaluate")` — feuert für allow UND ask nach Regel-Evaluation, vor Dialog/Ausführung (explizites deny ruft den Hook nicht); Effect `ask` → `recordAsk` + `explainAndNotify` |
| `permission.replied`-Event | `permission.v2.replied` im öffentlichen Event-Stream (`ctx.event.subscribe`), Payload `{sessionID, requestID, reply}` |
| `permission.replied`-Event | `permission.replied` im öffentlichen Event-Stream (`ctx.event.subscribe`), Payload `{sessionID, requestID, reply}` — feuert nur bei echter Client-Antwort, NICHT bei Non-Interactive-Auto-Reject (vm-test 2.0.16) |
| `experimental.chat.system.transform` | `ctx.session.hook("context")` → `event.system.push({type: "text", text})` — Agent-Loop inkl. Tool-Continuations |
| `tool.execute.before` (ENFORCE) | `ctx.tool.hook("execute.before")` — Event `{tool, sessionID, callID, input}` |
| `client.session.messages({path:{id}})` | `ctx.session.context({sessionID})` — Tool-Parts tragen die Call-ID als `id` (matcht `source.id` der Permission-Evaluation) |
@@ -159,14 +170,20 @@ trotzdem aktiv, statt beim Laden der ganzen Datei zu werfen.
- `explain-permissions/v2.0.0` — V2-only-Port auf die V2-Plugin-API (Core
2.0.x, az-fleet-7x8): `Plugin.define`-Default-Export, Hooks via
`ctx.permission.hook("evaluate")` / `ctx.session.hook("context")` /
`ctx.tool.hook("execute.before")`, Event-Stream `permission.v2.asked` /
`permission.v2.replied`, Config-Lesung per `fs` mit V1+V2-Parser
`ctx.tool.hook("execute.before")`, Event-Stream `permission.asked` /
`permission.replied`, Config-Lesung per `fs` mit V1+V2-Parser
(JSONC-tolerant) statt `hooks.config`, Action-Namen auf V2
(bash→shell, task→subagent; lsp/doom_loop verworfen). KEIN V1-Export mehr
(V2-only-Cut, Entscheidung 25.09.) — V1-Fleet bleibt gepinnt auf v1.3.0.
(bash→shell, task→subagent; lsp/doom_loop verworfen). Layout:
**Verzeichnis-Package** `v2/index.js` — V2 (2.0.16) verwirft Einzeldatei-
Einträge („configured plugin path must be a directory", vm-test-Evidenz).
KEIN V1-Export mehr (V2-only-Cut, Entscheidung 25.09.) — V1-Fleet bleibt
gepinnt auf v1.3.0.
Verifikation: Mock-ctx-Tests 21/21 grün (Config-Parsing beider Formen,
System-Regel-Injektion, evaluate/ask-Pfad, Hook↔Event-Dedup, replied-Audit,
ENFORCE); E2E auf vm-test laut Issue az-fleet-7x8.
ENFORCE); E2E vm-test (2.0.16): Plugin-Load (plugin-loaded 2.0.0),
Config-Lesung Global+Managed+Projekt, System-Regel je Model-Request,
evaluate-Hook allow+ask mit V1-Config-Normalisierung (bash→shell),
ask-Audit + Notification-Pfad, Einzeldatei-Ablehnung reproduziert.
- `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