fix(plugins): isole les plugins non servables et durcit la réconciliation MCP

Un bundle_url invalide ou un plugin dont l'asset n'est pas réellement
servable passe désormais en état Invalid isolé au lieu de faire
échouer globalement la réconciliation MCP au démarrage — cause racine
de la perte d'affichage à l'installation de hello-plugin (#116/#120).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-08-01 00:05:53 +02:00
parent ac659c42f2
commit 50b71f4ece
3 changed files with 167 additions and 15 deletions

View File

@ -146,3 +146,77 @@ async fn installs_sdk_hello_plugin_and_loads_runtime_catalog() {
let _ = fs::remove_dir_all(app_data);
}
#[tokio::test]
async fn installed_plugin_with_missing_main_is_isolated_from_runtime_catalog() {
let app_data = temp_dir("missing-main-app-data");
let source = temp_dir("missing-main-source");
fs::write(
source.join("idea-plugin.json"),
r#"{
"ideaPluginManifestVersion": 1,
"id": "dev.idea.fixtures.missing-main",
"displayName": "Missing Main Plugin",
"version": "0.1.0",
"main": "dist/index.js",
"trustLevel": "full",
"capabilities": ["ui"],
"contributes": {}
}"#,
)
.unwrap();
let packages = Arc::new(FsPluginPackageStore::new(&app_data));
let registry = Arc::new(FsPluginRegistryStore::new(&app_data));
let validator = Arc::new(JsonPluginManifestValidator::new("0.3.0"));
let events = Arc::new(TokioBroadcastEventBus::new());
let mcp = Arc::new(ExternalMcpPluginSupervisor::new());
let install = InstallPluginFromDirectory::new(
packages.clone(),
registry.clone(),
validator.clone(),
events,
mcp,
);
let result = install
.execute(source.to_string_lossy().into_owned())
.await
.unwrap();
assert_eq!(result.plugin.id, "dev.idea.fixtures.missing-main");
assert_eq!(
result.plugin.lifecycle_state,
domain::PluginLifecycleState::Invalid
);
assert!(result
.plugin
.error
.as_deref()
.unwrap_or_default()
.contains("not servable"));
let catalog = ListPluginRuntimeContributions::new(packages, registry.clone(), validator)
.execute()
.await
.unwrap();
assert!(catalog.plugins.is_empty());
let admin = ListPlugins::new(
Arc::new(FsPluginPackageStore::new(&app_data)),
registry,
Arc::new(JsonPluginManifestValidator::new("0.3.0")),
)
.execute()
.await
.unwrap();
assert_eq!(
admin[0].lifecycle_state,
domain::PluginLifecycleState::Invalid
);
assert!(admin[0]
.error
.as_deref()
.unwrap_or_default()
.contains("not servable"));
let _ = fs::remove_dir_all(source);
let _ = fs::remove_dir_all(app_data);
}