feat(wave): #119/#122/#131/#132 verts + sprint plugins ESM/persistance #135/#136/#139

État d'intégration confiné à la branche batch. Les tickets #119 (skills →
capacités agent découvrables), #122 (override permissions par défaut), #131
(effort par agent/presets) et #132 (outil MCP d'édition du contexte projet)
sont verts en périmètre. Le sprint plugins multi-fichiers ESM / persistance
plugin-owned (#135/#136/#139) est co-implémenté dans les MÊMES fichiers de
câblage (frontend/src/ports/index.ts, backend/src/lib.rs, domain/ports.rs,
backend/dto.rs), inséparable sans staging interactif (indisponible ici).

Commit unique volontaire : préserve l'état vert QA sans découpe hunk risquée.
NON mergé vers develop tant que #137 (QA e2e plugins) n'est pas vert.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-08-03 11:06:23 +02:00
parent 22c6bd803d
commit 171c6c923c
59 changed files with 3654 additions and 291 deletions

View File

@ -386,6 +386,48 @@ pub enum PluginMcpError {
Process(String),
}
/// Plugin-owned storage errors.
#[derive(Debug, Clone, PartialEq, Eq, Error)]
pub enum PluginStorageError {
/// Invalid key or value.
#[error("plugin storage invalid input: {0}")]
Invalid(String),
/// Filesystem failure.
#[error("plugin storage I/O error: {0}")]
Io(String),
/// Serialization failure.
#[error("plugin storage serialization error: {0}")]
Serialization(String),
}
/// Store for plugin-owned key/value JSON data under app-data `plugins/data/<pluginId>/`.
#[async_trait]
pub trait PluginStorageStore: Send + Sync {
/// Reads one plugin-owned value.
async fn get(
&self,
plugin_id: &PluginId,
key: &str,
) -> Result<Option<Value>, PluginStorageError>;
/// Writes one plugin-owned value.
async fn set(
&self,
plugin_id: &PluginId,
key: &str,
value: Value,
) -> Result<(), PluginStorageError>;
/// Deletes one plugin-owned value.
async fn delete(&self, plugin_id: &PluginId, key: &str) -> Result<bool, PluginStorageError>;
/// Purges every plugin-owned value for one plugin.
async fn purge_plugin(
&self,
plugin_id: &PluginId,
) -> Result<RemovalOutcome, PluginStorageError>;
}
/// Store for installed plugin packages under the global app data directory.
#[async_trait]
pub trait PluginPackageStore: Send + Sync {