Files
claude-ai-control/archive/design/2026-07-22_1626-modul-system-fuer-aicentral-entwurf.md
T
2026-07-24 21:42:30 +02:00

223 lines
9.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: "Modul-System für aICentral — Entwurf"
project: ai-control
created: 2026-07-22T16:26:08Z
source: ai-control
description: "Modul-System für aICentral: Deskriptoren, Registry, Enablement, Migration in 5 Schritten, Plugin-Ausblick"
tags: ["design", "module", "plugin", "panel", "architektur"]
---
# Modul-System für aICentral — Entwurf
Stand 2026-07-22. Grundlage: panel-wiring.ts, commands-view.ts, mcp.rs,
terminal.rs, app.rs, domain/project.rs (Stand 513e1a7).
## 1. Ziel und Abgrenzung
Alle Panel-Funktionen werden zu- und abwählbare **Module**; die anstehenden
Features (ToDo-Liste, Commit-Dialog, Archiv-Ausbau, Authoring-Ansicht)
entstehen direkt als Module. Ein System für **fremde Plugins** (zur Laufzeit
geladener Code) wird jetzt nicht gebaut — der Entwurf legt aber die
Schnittstellen so, dass es später ohne Umbau andockt (Abschnitt 9).
## 2. Bestandsaufnahme — was schon Modulform hat
Die vier Panel-Ansichten folgen bereits einem einheitlichen Muster, es ist
nur nicht als Schnittstelle benannt:
| Baustein | draft | commands | search | wiki |
|---|---|---|---|---|
| Pufferdatei (Env an MCP) | AI_CONTROL_PANEL | …_COMMANDS | …_SEARCH | …_WIKI |
| Watcher-Event | panel-update | commands-update | search-update | wiki-update |
| View-Interface | set/flush | set/empty | set/empty | set/empty |
| Read-Command | panel_read | commands_read | search_read | wiki_read |
| MCP-Tools | write_panel | write/show_commands | search_archive | show_archive, archive_panel |
Der Datenfluss ist überall gleich: MCP-Server oder Command schreibt die
Pufferdatei → Datei-Watcher im Terminal-Prozess emittiert `<x>-update`
View rendert. Es gibt auch schon ein abwählbares Modul: `archiveHome: null`
blendet Wiki-/Suche-Tab und Archiv-Werkzeuge aus (panel-wiring.ts:45).
Das Modul-System verallgemeinert genau diese zwei Präzedenzfälle.
## 3. Modulbegriff
Ein Modul ist ein benannter Funktionsblock mit bis zu vier Beiträgen:
1. **Panel-Tab** mit View (Kachel- oder Dokumentansicht)
2. **MCP-Tools** (Angebot an claude)
3. **Pufferdatei + Watcher-Event** (der Transportweg dazwischen)
4. optional **Fenster/Dialoge** (z. B. Commit-Dialog)
Geplanter Zuschnitt:
| Modul | Tab | MCP-Tools | abwählbar |
|---|---|---|---|
| `draft` (Entwurf) | ja | write_panel | nein — Kern |
| `commands` | ja | write_commands, show_commands | ja |
| `archive` | Wiki + Suche | archive_panel, show_archive, search_archive | ja (heute: archiveHome) |
| `todo` (neu) | ja | write_todos, show_todos | ja |
| `commit` (neu) | nein, eigener Dialog | — | ja |
| `authoring` (später) | ja | … | ja |
`draft` bleibt Kern: Titel, Editier-Modus, flush und das Archivieren hängen
daran; ohne Entwurf ist das Panel leer. Alles andere ist abschaltbar.
## 4. Backend: Deskriptoren und eine Durchsetzungsstelle
Neu `domain/modules.rs`:
```rust
pub(crate) struct ModuleDesc {
pub id: &'static str, // "commands", "todo", ...
pub default_enabled: bool,
/// Modul setzt ein konfiguriertes archiveHome voraus.
pub requires_archive: bool,
pub mcp_tools: &'static [&'static str],
/// Pufferdatei-Name im Projekt-Runtime-Ordner, None = kein Puffer.
pub buffer: Option<&'static str>,
}
pub(crate) const MODULES: &[ModuleDesc] = &[ /* draft, commands, archive, todo, … */ ];
/// Die eine Quelle für „was ist in diesem Projekt an?“.
pub(crate) fn enabled_modules_in(paths: &Paths, project: &str)
-> Result<Vec<&'static str>, String>
```
`enabled_modules_in` = MODULES, gefiltert durch Projekt-Config und
`requires_archive` (Archiv-Module fallen ohne archiveHome automatisch weg —
das ersetzt die heutige Sonderbehandlung, statt eine zweite daneben zu
stellen). Genau drei Aufrufer:
1. **Tauri-Command `enabled_modules(project)`** — das Frontend fragt einmal
beim Verdrahten.
2. **mcp.rs `tools/list`** — die Tool-Liste wird aus
`MODULES[…].mcp_tools` der aktiven Module gebaut (Projekt kommt wie
heute über `AI_CONTROL_PROJECT`). claude sieht Tools abgeschalteter
Module gar nicht erst.
3. **mcp.rs `tools/call`** — Guard vor dem Dispatch: Tool eines inaktiven
Moduls → Fehler „Modul X ist in diesem Projekt abgeschaltet". Nötig,
weil eine laufende claude-Session die Tool-Liste vom Start behält.
Verallgemeinert wird außerdem:
- **terminal.rs**: die vier `spawn_file_watcher`-Zeilen werden eine Schleife
über die aktiven Module mit Puffer; Event-Name per Konvention
`<id>-update`, Env-Name `AI_CONTROL_<ID>`.
- **Read-Commands**: `panel_read/commands_read/search_read/wiki_read`
verschmelzen zu `module_read(project, module)` (alle vier sind
„Pufferdatei als String"). `panel_set` bleibt eigenständig, es ist der
einzige Rückkanal.
Statisch bleiben: `generate_handler!` (Commands aller Module sind kompiliert
registriert; Abwahl wirkt auf Sichtbarkeit und Tools, nicht auf die
IPC-Registrierung), die Capability-Manifeste pro Fenster und die CSP. Die
Modul-Abwahl ist Konfiguration, keine Sicherheitsgrenze — dieselbe Linie
wie bei den Pools (Konfiguration trennen, nicht Zugriff).
## 5. Frontend: Registry statt Verdrahtung von Hand
Neu `src/modules/` mit einem Deskriptor pro Modul:
```ts
export interface PanelModule {
id: string;
tabLabelKey: string; // i18n-Key
order: number; // Tab-Reihenfolge
init(container: HTMLElement, ctx: ModuleCtx): ModuleView;
/// Kopfzeilen-Werkzeuge des Moduls (z. B. Archivieren-Button).
headerTools?(ctx: ModuleCtx): HTMLElement[];
}
export interface ModuleView { set(text: string): void; empty(): boolean; }
export interface ModuleCtx {
project: string;
toast(msg: string): void;
openDoc(path: string): void; // Dokument in den Entwurfs-Tab laden
openWiki(name: string): void;
}
```
`panel-wiring.ts` wird generisch: `enabled_modules` abfragen, pro Modul
Tab + Container erzeugen, `module_read` laden, `<id>-update` abonnieren,
`initPanelMode` über die Modulliste statt über vier feste Felder. Die
`PanelMode`-Union und die `archiveHome`-Ausblendelogik entfallen. Die
HTML-Dateien verlieren die fest verdrahteten Tab-/Container-Elemente;
beide Panel-Markups (angedockt/abgelöst) entstehen aus derselben Registry.
**Kachel-Renderer als gemeinsamer Baustein**: `commands-view.ts` wird in
einen deklarativen Tile-Renderer zerlegt (Titel/Text/Note, Zeitmarke,
Aktionen kopieren/löschen/öffnen, optionales Badge). Commands, ToDo
(Due-Date-Ampel = Badge) und Suchtreffer rendern darüber — die
ToDo-Ansicht „analog commandlist" ist dann im Wesentlichen ein
Puffer-Format plus Badge-Logik. Das Sanitizing (stripInvisibles, kein
innerHTML) liegt damit an einer Stelle.
## 6. Konfiguration
Projekt-Config (`.ai-control/config.json`) bekommt:
```json
{ "modules": { "commands": false, "todo": true } }
```
Nur Abweichungen vom Default werden gespeichert; fehlender Key = alle
Defaults (bestehende Configs bleiben unverändert gültig, kein
Migrationsschritt). `archiveHome` bleibt eigenständiges Feld — es ist
Pfad-Konfiguration, das Archiv-Modul hängt über `requires_archive` daran.
Ein Eintrag `"archive": false` schaltet das Modul trotz gesetztem
archiveHome ab.
Settings-UI: im Projekt-Dialog eine Checkbox-Gruppe „Module" aus MODULES
generiert; Archiv-Zeile kombiniert Checkbox + Pfadwahl (heutige
Archiv-Einstellung wandert dorthin). Änderungen wirken beim nächsten
Panel-Aufbau; eine laufende claude-Session behält ihre Tool-Liste, der
tools/call-Guard fängt das ab.
## 7. Migration in Schritten
1. `domain/modules.rs` + `enabled_modules` + tools/list/call aus MODULES
speisen — reine Umformung, Verhalten identisch.
2. Frontend-Registry: die vier Bestands-Views als Deskriptoren,
panel-wiring generisch, archiveHome-Sonderlogik durch
`requires_archive` ersetzen. Bestehende vitest-Tests laufen gegen die
Deskriptoren weiter.
3. Kachel-Renderer aus commands-view extrahieren, Suche darauf umstellen.
4. Settings-UI mit Modul-Checkboxen + `modules`-Feld in der Config.
5. Erstes neues Modul: **ToDo** — validiert den Schnitt komplett
(Deskriptor, Puffer, zwei MCP-Tools, Tile-Renderer mit Badge), ohne
eine Zeile Sonderverdrahtung.
Schritte 13 sind Refactoring ohne Funktionsänderung und einzeln
committbar; ab Schritt 4 wird das System sichtbar.
## 8. Auswirkung auf die geplanten Features
- **ToDo**: Modul nach Schema F (Schritt 5), Aufwand fast nur Puffer-Format
und Badge.
- **Commit-Dialog**: Modul ohne Tab — Beitrag ist ein Fenster samt
Capability-Datei; die Abwahl blendet den Einstieg (Menü/Button) aus.
Zeigt, dass der Modulbegriff nicht am Panel klebt.
- **Archiv-Ausbau**: Seitennavigation, Metadaten, Ordnerverwaltung wachsen
im Archiv-Modul, dessen Grenze (requires_archive, drei MCP-Tools,
zwei Tabs) dann schon gezogen ist.
- **Authoring-Ansicht**: bekommt mit der Registry eine definierte
Andockstelle statt weiterer Handverdrahtung in zwei HTML-Dateien.
## 9. Ausblick fremde Plugins — drei Stufen, Empfehlung Stufe 2
1. **Kompilierte Module** (dieser Entwurf): Code im Repo, Registry statisch.
2. **Prozess-Plugins**: ein externes Programm liefert einen Deskriptor
(JSON-Manifest: id, Label, Tile-Schema, MCP-Tool-Definitionen) und
schreibt Pufferdateien im Tile-Format; die App rendert deklarativ und
reicht Tool-Calls per stdio durch — dasselbe Muster, mit dem claude
heute schon angebunden ist. Kein Fremdcode im Webview, Isolation =
Prozessgrenze, CSP und ACL bleiben unangetastet.
3. **Geladener UI-Code** (JS/WASM im Webview): verworfen — hebelt CSP
(`style-src 'self'` ohne unsafe-inline) und das App-ACL-Manifest aus
und schafft genau die Angriffsfläche, die die Sicherheitsrunden
geschlossen haben.
Der Entwurf hält Stufe 2 offen, ohne sie zu bauen: Deskriptor,
Tile-Format und Puffer/Event-Konvention sind bereits die Plugin-API —
später kommt nur ein Loader dazu, der Deskriptoren aus Manifesten statt
aus dem Repo bezieht.