feat(backend): système de plugins — domaine, application, infrastructure (#43)
Lots B1-B4 : modèle de domaine des plugins (manifeste, capacités menus/layouts/MCP), port et registre applicatif, chargement/validation en infrastructure, exposition DTO et commandes Tauri. Tests cargo verts. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@ -20,6 +20,253 @@ use domain::{AgentBusyState, PageCursor, PageDirection, Project, ProjectId, Turn
|
||||
|
||||
pub use crate::ticket_dto::*;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Plugins (#43)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// Plugin contribution summary DTO.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PluginContributionSummaryDto {
|
||||
/// Top-level menus count.
|
||||
pub top_level_menus: usize,
|
||||
/// Menu items count.
|
||||
pub menu_items: usize,
|
||||
/// Layouts count.
|
||||
pub layouts: usize,
|
||||
/// MCP servers count.
|
||||
pub mcp_servers: usize,
|
||||
}
|
||||
|
||||
impl From<application::PluginContributionSummary> for PluginContributionSummaryDto {
|
||||
fn from(value: application::PluginContributionSummary) -> Self {
|
||||
Self {
|
||||
top_level_menus: value.top_level_menus,
|
||||
menu_items: value.menu_items,
|
||||
layouts: value.layouts,
|
||||
mcp_servers: value.mcp_servers,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Admin plugin DTO.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PluginAdminDto {
|
||||
/// Plugin id.
|
||||
pub id: String,
|
||||
/// Display name.
|
||||
pub display_name: String,
|
||||
/// Publisher.
|
||||
pub publisher: Option<String>,
|
||||
/// Version.
|
||||
pub version: String,
|
||||
/// Description.
|
||||
pub description: Option<String>,
|
||||
/// Icon URL.
|
||||
pub icon_url: Option<String>,
|
||||
/// Source kind.
|
||||
pub source_kind: String,
|
||||
/// Source label.
|
||||
pub source_label: Option<String>,
|
||||
/// Lifecycle state.
|
||||
pub lifecycle_state: domain::PluginLifecycleState,
|
||||
/// Enabled flag.
|
||||
pub enabled: bool,
|
||||
/// Pending enable state.
|
||||
pub pending_enable_state: Option<bool>,
|
||||
/// Pending uninstall flag.
|
||||
pub pending_uninstall: bool,
|
||||
/// Restart required flag.
|
||||
pub restart_required: bool,
|
||||
/// Trust level.
|
||||
pub trust_level: domain::PluginTrustLevel,
|
||||
/// Contribution summary.
|
||||
pub contribution_summary: PluginContributionSummaryDto,
|
||||
/// Optional error.
|
||||
pub error: Option<String>,
|
||||
}
|
||||
|
||||
impl From<application::PluginAdmin> for PluginAdminDto {
|
||||
fn from(value: application::PluginAdmin) -> Self {
|
||||
Self {
|
||||
id: value.id,
|
||||
display_name: value.display_name,
|
||||
publisher: value.publisher,
|
||||
version: value.version,
|
||||
description: value.description,
|
||||
icon_url: value.icon_url,
|
||||
source_kind: value.source_kind,
|
||||
source_label: value.source_label,
|
||||
lifecycle_state: value.lifecycle_state,
|
||||
enabled: value.enabled,
|
||||
pending_enable_state: value.pending_enable_state,
|
||||
pending_uninstall: value.pending_uninstall,
|
||||
restart_required: value.restart_required,
|
||||
trust_level: value.trust_level,
|
||||
contribution_summary: value.contribution_summary.into(),
|
||||
error: value.error,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Review request DTO.
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ReviewPluginPackageDto {
|
||||
/// Source kind: `archive` or `directory`.
|
||||
pub source_kind: String,
|
||||
/// Local source path.
|
||||
pub path: String,
|
||||
}
|
||||
|
||||
/// Plugin review DTO.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PluginReviewDto {
|
||||
/// Manifest id.
|
||||
pub id: String,
|
||||
/// Display name.
|
||||
pub display_name: String,
|
||||
/// Publisher.
|
||||
pub publisher: Option<String>,
|
||||
/// Version.
|
||||
pub version: String,
|
||||
/// Description.
|
||||
pub description: Option<String>,
|
||||
/// Source kind.
|
||||
pub source_kind: String,
|
||||
/// Source label.
|
||||
pub source_label: Option<String>,
|
||||
/// Content hash.
|
||||
pub content_hash: String,
|
||||
/// Trust level.
|
||||
pub trust_level: domain::PluginTrustLevel,
|
||||
/// Summary.
|
||||
pub contribution_summary: PluginContributionSummaryDto,
|
||||
/// Manifest contributions.
|
||||
pub contributes: domain::PluginContributionSet,
|
||||
}
|
||||
|
||||
impl From<application::PluginReview> for PluginReviewDto {
|
||||
fn from(value: application::PluginReview) -> Self {
|
||||
Self {
|
||||
id: value.manifest.id.as_str().to_owned(),
|
||||
display_name: value.manifest.display_name,
|
||||
publisher: value.manifest.publisher,
|
||||
version: value.manifest.version.as_str().to_owned(),
|
||||
description: value.manifest.description,
|
||||
source_kind: value.source.kind().to_owned(),
|
||||
source_label: Some(value.source.label().to_owned()),
|
||||
content_hash: value.content_hash,
|
||||
trust_level: value.trust_level,
|
||||
contribution_summary: value.contribution_summary.into(),
|
||||
contributes: value.manifest.contributes,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Plugin install result DTO.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PluginInstallResultDto {
|
||||
/// Installed plugin.
|
||||
pub plugin: PluginAdminDto,
|
||||
/// Review.
|
||||
pub review: PluginReviewDto,
|
||||
/// Restart required.
|
||||
pub restart_required: bool,
|
||||
}
|
||||
|
||||
impl From<application::PluginInstallResult> for PluginInstallResultDto {
|
||||
fn from(value: application::PluginInstallResult) -> Self {
|
||||
Self {
|
||||
plugin: value.plugin.into(),
|
||||
review: value.review.into(),
|
||||
restart_required: value.restart_required,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Plugin uninstall result DTO.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PluginUninstallResultDto {
|
||||
/// Plugin id.
|
||||
pub plugin_id: String,
|
||||
/// Removal outcome.
|
||||
pub removal_outcome: domain::RemovalOutcome,
|
||||
/// Restart required.
|
||||
pub restart_required: bool,
|
||||
}
|
||||
|
||||
impl From<application::UninstallPluginResult> for PluginUninstallResultDto {
|
||||
fn from(value: application::UninstallPluginResult) -> Self {
|
||||
Self {
|
||||
plugin_id: value.plugin_id,
|
||||
removal_outcome: value.removal_outcome,
|
||||
restart_required: value.restart_required,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Runtime catalog DTO.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PluginRuntimeContributionCatalogDto {
|
||||
/// Runtime plugins.
|
||||
pub plugins: Vec<PluginRuntimePluginDto>,
|
||||
}
|
||||
|
||||
/// Runtime plugin DTO.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PluginRuntimePluginDto {
|
||||
/// Plugin id.
|
||||
pub id: String,
|
||||
/// Display name.
|
||||
pub display_name: String,
|
||||
/// Publisher.
|
||||
pub publisher: Option<String>,
|
||||
/// Version.
|
||||
pub version: String,
|
||||
/// Bundle URL.
|
||||
pub bundle_url: String,
|
||||
/// Icon URL.
|
||||
pub icon_url: Option<String>,
|
||||
/// Content hash.
|
||||
pub content_hash: String,
|
||||
/// Contributions.
|
||||
pub contributes: domain::PluginContributionSet,
|
||||
}
|
||||
|
||||
impl From<application::PluginRuntimeCatalog> for PluginRuntimeContributionCatalogDto {
|
||||
fn from(value: application::PluginRuntimeCatalog) -> Self {
|
||||
Self {
|
||||
plugins: value
|
||||
.plugins
|
||||
.into_iter()
|
||||
.map(PluginRuntimePluginDto::from)
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<application::PluginRuntimePlugin> for PluginRuntimePluginDto {
|
||||
fn from(value: application::PluginRuntimePlugin) -> Self {
|
||||
Self {
|
||||
id: value.id,
|
||||
display_name: value.display_name,
|
||||
publisher: value.publisher,
|
||||
version: value.version,
|
||||
bundle_url: value.bundle_url,
|
||||
icon_url: value.icon_url,
|
||||
content_hash: value.content_hash,
|
||||
contributes: value.contributes,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Request DTO for the `health` command.
|
||||
#[derive(Debug, Clone, Default, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
|
||||
Reference in New Issue
Block a user