feat(application,backend,infrastructure,app-tauri,frontend): contributions UI/runtime des plugins limitées aux projets liés — #321 (QA verte)

Les contributions runtime des plugins (menus, slash commands, layouts,
surfaces) ne sont exposées que dans les projets liés au plugin.

- Définition du lien: ProjectPluginSettingsStore par racine projet
  (domaine) — une contribution runtime-active n'entre dans le catalogue
  que si elle est explicitement activée pour le projet courant; hors
  projet focalisé, catalogue vide
- Application: ListPluginRuntimeContributions.execute prend un
  project_id optionnel, charge projet + settings et filtre le registre
  par activation projet; tests fake store/settings (catalogue vide sans
  projet, activation, layout, slash commands)
- Backend/app-tauri: plugin_list_runtime_contributions et slash
  commands list/execute acceptent projectId optionnel (DTO camelCase,
  défaut serde), BackendCore recâblé avec store_port et
  project_plugin_settings_store; test DTO de scope optionnel
- Frontend: PluginGateway.listRuntimeContributions(projectId) (ports,
  tauri, http/unsupported, mock alignés); PluginRuntimeProvider
  re-scope le catalogue au changement de focus projet (vidage du
  registre précédent, disposition des bundles, requêtes obsolètes
  ignorées par projectId/révision); PluginLayoutCellView ignore les
  références de layout devenues hors périmètre via onChooseAnotherLayout
  et ne rend rien pendant le rechargement (aucune fuite inter-projets)
- Tests: plugin_install_load (infrastructure), dto slash commands,
  plugin.test, PluginRuntimeProvider.test, PluginLayoutCellView.test

QA verte sur feature/321-plugin-contributions-linked-projects. Aucun push.
This commit is contained in:
2026-09-11 17:46:03 +02:00
parent 6bdbe755fa
commit bf33e58508
16 changed files with 523 additions and 110 deletions

View File

@ -125,9 +125,14 @@ pub async fn list_slash_commands(
state: State<'_, AppState>,
) -> Result<SlashCommandListDto, ErrorDto> {
let request = request.unwrap_or_default();
let project_id = request
.project_id
.as_deref()
.map(parse_project_id)
.transpose()?;
let catalog = state
.list_plugin_runtime_contributions
.execute()
.execute(project_id)
.await
.map_err(ErrorDto::from)?;
let plugin_commands =
@ -153,6 +158,11 @@ pub async fn execute_slash_command(
request: ExecuteSlashCommandRequestDto,
state: State<'_, AppState>,
) -> Result<ExecuteSlashCommandResponseDto, ErrorDto> {
let project_id = request
.project_id
.as_deref()
.map(parse_project_id)
.transpose()?;
let session_id = request
.session_id
.as_deref()
@ -160,7 +170,7 @@ pub async fn execute_slash_command(
.transpose()?;
let catalog = state
.list_plugin_runtime_contributions
.execute()
.execute(project_id)
.await
.map_err(ErrorDto::from)?;
let plugin_commands =