feat: support remote_sync for plugin install/uninstall. (#14878)

- Added forceRemoteSync to plugin/install and plugin/uninstall.
- With forceRemoteSync=true, we update the remote plugin status first,
then apply the local change only if the backend call succeeds.
- Kept plugin/list(forceRemoteSync=true) as the main recon path, and for
now it treats remote enabled=false as uninstall. We
will eventually migrate to plugin/installed for more precise state
handling.
This commit is contained in:
xl-openai
2026-03-16 21:37:27 -07:00
committed by GitHub
Unverified
parent 49c2b66ece
commit 1d85fe79ed
17 changed files with 743 additions and 101 deletions
@@ -5679,6 +5679,7 @@ impl CodexMessageProcessor {
let PluginInstallParams {
marketplace_path,
plugin_name,
force_remote_sync,
} = params;
let config_cwd = marketplace_path.as_path().parent().map(Path::to_path_buf);
@@ -5688,7 +5689,23 @@ impl CodexMessageProcessor {
marketplace_path,
};
match plugins_manager.install_plugin(request).await {
let install_result = if force_remote_sync {
let config = match self.load_latest_config(config_cwd.clone()).await {
Ok(config) => config,
Err(err) => {
self.outgoing.send_error(request_id, err).await;
return;
}
};
let auth = self.auth_manager.auth().await;
plugins_manager
.install_plugin_with_remote_sync(&config, auth.as_ref(), request)
.await
} else {
plugins_manager.install_plugin(request).await
};
match install_result {
Ok(result) => {
let config = match self.load_latest_config(config_cwd).await {
Ok(config) => config,
@@ -5789,6 +5806,13 @@ impl CodexMessageProcessor {
)
.await;
}
CorePluginInstallError::Remote(err) => {
self.send_internal_error(
request_id,
format!("failed to enable remote plugin: {err}"),
)
.await;
}
CorePluginInstallError::Join(err) => {
self.send_internal_error(
request_id,
@@ -5813,9 +5837,29 @@ impl CodexMessageProcessor {
request_id: ConnectionRequestId,
params: PluginUninstallParams,
) {
let PluginUninstallParams {
plugin_id,
force_remote_sync,
} = params;
let plugins_manager = self.thread_manager.plugins_manager();
match plugins_manager.uninstall_plugin(params.plugin_id).await {
let uninstall_result = if force_remote_sync {
let config = match self.load_latest_config(/*fallback_cwd*/ None).await {
Ok(config) => config,
Err(err) => {
self.outgoing.send_error(request_id, err).await;
return;
}
};
let auth = self.auth_manager.auth().await;
plugins_manager
.uninstall_plugin_with_remote_sync(&config, auth.as_ref(), plugin_id)
.await
} else {
plugins_manager.uninstall_plugin(plugin_id).await
};
match uninstall_result {
Ok(()) => {
self.clear_plugin_related_caches();
self.outgoing
@@ -5837,6 +5881,13 @@ impl CodexMessageProcessor {
)
.await;
}
CorePluginUninstallError::Remote(err) => {
self.send_internal_error(
request_id,
format!("failed to uninstall remote plugin: {err}"),
)
.await;
}
CorePluginUninstallError::Join(err) => {
self.send_internal_error(
request_id,