Centralize remote plugin mutations in PluginsManager (#42114)

## What changed

- Move remote plugin install and uninstall orchestration from the app server into shared `PluginsManager` APIs.
- Keep cache and backend mutations coordinated by the installed-plugin sync gate, and retain install outcomes long enough to protect newly materialized bundles during downstream setup.
- Return structured operation errors and outcomes so callers can preserve JSON-RPC error mapping, telemetry, cache refreshes, and OAuth setup.

## Testing

- Add regression coverage that verifies uninstall holds the mutation gate, preserves the local cache when the backend operation fails, and refreshes installed state after a successful uninstall.

GitOrigin-RevId: de39f19a4e61c6e9c76ddc2c65d2ac130a4b7f88
This commit is contained in:
willwang-openai
2026-09-01 18:35:00 +00:00
committed by copyberry
parent 1f4c47343a
commit ef76e6ac30
5 changed files with 515 additions and 234 deletions
+10 -3
View File
@@ -1,5 +1,12 @@
#[path = "bundled_plugin_exclusions.rs"]
mod bundled_plugin_exclusions;
#[path = "remote_mutations.rs"]
mod remote_mutations;
pub use remote_mutations::RemotePluginInstallOutcome;
pub use remote_mutations::RemotePluginInstallRequest;
pub use remote_mutations::RemotePluginOperationError;
pub use remote_mutations::RemotePluginOperationErrorKind;
pub use remote_mutations::RemotePluginUninstallOutcome;
#[path = "marketplace_context.rs"]
mod marketplace_context;
pub use marketplace_context::PluginMarketplaceContext;
@@ -255,7 +262,7 @@ enum RemoteInstalledPluginsCachePublication {
///
/// Callers should keep this guard only while mutating the remote plugin cache and backend
/// installed state, then release it before unrelated analytics, OAuth, or runtime refresh work.
pub struct RemoteInstalledPluginSyncGuard {
struct RemoteInstalledPluginSyncGuard {
_permit: OwnedSemaphorePermit,
}
@@ -1458,7 +1465,7 @@ impl PluginsManager {
});
}
pub fn maybe_start_remote_installed_plugins_cache_refresh_after_mutation(
fn maybe_start_remote_installed_plugins_cache_refresh_after_mutation(
self: &Arc<Self>,
config: &PluginsConfigInput,
auth: Option<CodexAuth>,
@@ -1563,7 +1570,7 @@ impl PluginsManager {
/// Acquires the cache-root gate shared by full installed-bundle sync, reconciliation, and
/// direct remote plugin mutations.
pub async fn acquire_remote_installed_plugin_sync_guard(
async fn acquire_remote_installed_plugin_sync_guard(
&self,
) -> Result<RemoteInstalledPluginSyncGuard, RemoteInstalledPluginBundleSyncError> {
let permit = tokio::time::timeout(