feat(frontend): système de plugins — runtime, menus, layouts custom (#43)

Lots F1-F4 : runtime de chargement/registre plugin, extension des menus
existants, panneau de gestion des plugins, types de layout custom
(sélecteur, fallback, cellule dédiée) branchés sur le port plugin.
Suite npm typecheck/test verte (947/947).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-22 07:37:11 +02:00
parent bb35641715
commit ac726d075e
41 changed files with 3245 additions and 24 deletions

View File

@ -12,6 +12,11 @@
import type {
EmbeddedServerStatus,
GatewayError,
PluginAdmin,
PluginInstallResult,
PluginReview,
PluginRuntimeContributionCatalog,
PluginUninstallResult,
ServerExposurePreview,
ServerExposureSettings,
Unsubscribe,
@ -20,7 +25,9 @@ import type {
DesktopServerGateway,
FocusedProject,
FocusedProjectGateway,
PluginGateway,
RemoteGateway,
ReviewPluginPackageInput,
ViewWindowClosed,
ViewWindowSnapshot,
WindowGateway,
@ -119,3 +126,37 @@ export class WebDesktopServerGateway implements DesktopServerGateway {
return Promise.resolve(() => {});
}
}
/**
* Web stub: the plugin system (#43) installs/loads full-trust local ESM
* bundles from the desktop filesystem — no server-side equivalent in V1. The
* web client must not manage or load plugins on behalf of the desktop app.
*/
export class WebPluginGateway implements PluginGateway {
async listPlugins(): Promise<PluginAdmin[]> {
return unsupportedOnWeb("Plugin management");
}
async reviewPackage(_input: ReviewPluginPackageInput): Promise<PluginReview> {
return unsupportedOnWeb("Plugin management");
}
async installFromArchive(_path: string): Promise<PluginInstallResult> {
return unsupportedOnWeb("Plugin management");
}
async installFromDirectory(_path: string): Promise<PluginInstallResult> {
return unsupportedOnWeb("Plugin management");
}
async setEnabled(_pluginId: string, _enabled: boolean): Promise<PluginAdmin> {
return unsupportedOnWeb("Plugin management");
}
async uninstall(_pluginId: string): Promise<PluginUninstallResult> {
return unsupportedOnWeb("Plugin management");
}
async listRuntimeContributions(): Promise<PluginRuntimeContributionCatalog> {
// No plugin bundles are ever loaded on the web client — an empty catalog
// lets the bootstrap loader run unconditionally without a transport check.
return { plugins: [] };
}
async openPluginsFolder(_pluginId?: string): Promise<void> {
return unsupportedOnWeb("Plugin management");
}
}