[codex] Add installed-plugin mention API (#22448)

## Summary
- add app-server `plugin/installed` for mention-oriented plugin loading
- return installed plugins plus explicitly requested install-suggestion
rows
- keep remote handling on installed-state data instead of the broad
catalog listing path

## Why
The `@` mention surface only needs plugins that are usable now, plus a
small product-approved set of install suggestions. It does not need the
full catalog-shaped `plugin/list` payload that the Plugins page uses.

## Validation
- `just write-app-server-schema`
- `just fmt`
- `cargo test -p codex-app-server-protocol`
- `cargo test -p codex-core-plugins`
- `cargo test -p codex-app-server --test all plugin_installed_`

## Notes
- The package-wide `cargo test -p codex-app-server` run still hits an
existing unrelated stack overflow in
`in_process::tests::in_process_start_clamps_zero_channel_capacity`.
- Companion webview PR: https://github.com/openai/openai/pull/915672
This commit is contained in:
xli-oai
2026-05-18 03:11:54 -07:00
committed by GitHub
parent 22dd9ad392
commit da14dd2add
22 changed files with 1609 additions and 82 deletions
+35 -1
View File
@@ -37,6 +37,7 @@ use crate::marketplace_upgrade::configured_git_marketplace_names;
use crate::marketplace_upgrade::upgrade_configured_git_marketplaces;
use crate::remote::RemoteInstalledPlugin;
use crate::remote::RemotePluginCatalogError;
use crate::remote::RemotePluginScope;
use crate::remote::RemotePluginServiceConfig;
use crate::remote_legacy::RemotePluginFetchError;
use crate::remote_legacy::RemotePluginMutationError;
@@ -597,6 +598,39 @@ impl PluginsManager {
remote_installed_plugins_to_config(plugins, &self.store)
}
pub fn build_remote_installed_plugin_marketplaces_from_cache(
&self,
visible_scopes: &[RemotePluginScope],
) -> Option<Vec<crate::remote::RemoteMarketplace>> {
let cache = match self.remote_installed_plugins_cache.read() {
Ok(cache) => cache,
Err(err) => err.into_inner(),
};
let plugins = cache.as_ref()?;
Some(crate::remote::group_remote_installed_plugins_by_marketplaces(plugins, visible_scopes))
}
pub async fn build_and_cache_remote_installed_plugin_marketplaces(
&self,
config: &PluginsConfigInput,
auth: Option<&CodexAuth>,
visible_scopes: &[RemotePluginScope],
on_effective_plugins_changed: Option<Arc<dyn Fn() + Send + Sync + 'static>>,
) -> Result<Vec<crate::remote::RemoteMarketplace>, RemotePluginCatalogError> {
let plugins = crate::remote::fetch_remote_installed_plugins(
&remote_plugin_service_config(config),
auth,
)
.await?;
let marketplaces =
crate::remote::group_remote_installed_plugins_by_marketplaces(&plugins, visible_scopes);
let changed = self.write_remote_installed_plugins_cache(plugins);
if changed && let Some(on_effective_plugins_changed) = on_effective_plugins_changed {
on_effective_plugins_changed();
}
Ok(marketplaces)
}
fn write_remote_installed_plugins_cache(&self, plugins: Vec<RemoteInstalledPlugin>) -> bool {
let mut cache = match self.remote_installed_plugins_cache.write() {
Ok(cache) => cache,
@@ -674,7 +708,7 @@ impl PluginsManager {
);
}
fn maybe_start_remote_installed_plugin_bundle_sync(
pub fn maybe_start_remote_installed_plugin_bundle_sync(
self: &Arc<Self>,
config: &PluginsConfigInput,
auth: Option<CodexAuth>,