Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions codex-rs/app-server-protocol/src/protocol/v2/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -600,6 +600,9 @@ pub struct PluginSummary {
pub id: String,
/// Backend remote plugin identifier when available.
pub remote_plugin_id: Option<String>,
/// Version advertised by the remote marketplace backend when available.
#[serde(default)]
pub version: Option<String>,
/// Version of the locally materialized plugin package when available.
#[serde(default)]
pub local_version: Option<String>,
Expand Down
2 changes: 2 additions & 0 deletions codex-rs/app-server-protocol/src/protocol/v2/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3642,6 +3642,7 @@ fn plugin_share_list_response_serializes_share_items() {
remote_plugin_id: Some(
"plugins~Plugin_00000000000000000000000000000000".to_string(),
),
version: None,
local_version: None,
name: "gmail".to_string(),
share_context: None,
Expand All @@ -3663,6 +3664,7 @@ fn plugin_share_list_response_serializes_share_items() {
"plugin": {
"id": "gmail@openai-curated-remote",
"remotePluginId": "plugins~Plugin_00000000000000000000000000000000",
"version": null,
"localVersion": null,
"name": "gmail",
"shareContext": null,
Expand Down
2 changes: 1 addition & 1 deletion codex-rs/app-server/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ Example with notification opt-out:
- `marketplace/add` — add a remote plugin marketplace from an HTTP(S) Git URL, SSH Git URL, or GitHub `owner/repo` shorthand, then persist it into the user marketplace config. Returns the installed root path plus whether the marketplace was already present.
- `marketplace/remove` — remove a configured marketplace by name from the user marketplace config, and delete its installed marketplace root when one exists.
- `marketplace/upgrade` — upgrade all configured Git plugin marketplaces, or one named marketplace when `marketplaceName` is provided. Returns selected marketplace names, upgraded roots, and per-marketplace errors.
- `plugin/list` — list discovered plugin marketplaces and plugin state, including effective marketplace install/auth policy metadata, plugin `availability` (`AVAILABLE` by default or `DISABLED_BY_ADMIN` for remote plugins blocked upstream), fail-open `marketplaceLoadErrors` entries for marketplace files that could not be parsed or loaded, and best-effort `featuredPluginIds` for the official curated marketplace. Clients can explicitly request the remote `workspace-directory`, `shared-with-me`, or `created-by-me-remote` marketplace kinds. `interface.category` uses the marketplace category when present; otherwise it falls back to the plugin manifest category (**under development; do not call from production clients yet**).
- `plugin/list` — list discovered plugin marketplaces and plugin state, including effective marketplace install/auth policy metadata, the remote marketplace `version` and locally materialized `localVersion` when available, plugin `availability` (`AVAILABLE` by default or `DISABLED_BY_ADMIN` for remote plugins blocked upstream), fail-open `marketplaceLoadErrors` entries for marketplace files that could not be parsed or loaded, and best-effort `featuredPluginIds` for the official curated marketplace. Clients can explicitly request the remote `workspace-directory`, `shared-with-me`, or `created-by-me-remote` marketplace kinds. `interface.category` uses the marketplace category when present; otherwise it falls back to the plugin manifest category (**under development; do not call from production clients yet**).
- `plugin/installed` — list installed plugin rows plus any explicitly requested local install-suggestion plugin names, without fetching the broader remote catalog. Mention surfaces can use this narrower view when they need plugin mention payloads rather than plugin-page discovery data (**under development; do not call from production clients yet**).
- `plugin/read` — read one plugin by `marketplacePath` plus `pluginName`, returning marketplace info, a list-style `summary`, manifest descriptions/interface metadata, and bundled skills/hooks/apps/MCP server names. Remote plugin details expose the canonical `shareUrl` supplied by the remote catalog when available; it is `null` for local plugins or when the catalog omits it. This field is separate from `summary.shareContext`, which continues to describe user and workspace sharing state. Returned plugin skills include their current `enabled` state after local config filtering; bundled hooks are returned as lightweight declaration summaries keyed for correlation with `hooks/list`. Use `plugin/install`'s `appsNeedingAuth` to drive post-install authentication and `app/list`'s `isAccessible` to determine current connector accessibility (**under development; do not call from production clients yet**).
- `plugin/skill/read` — read remote plugin skill markdown on demand by `remoteMarketplaceName`, `remotePluginId`, and `skillName`. This lets clients preview uninstalled remote plugin skills without downloading the plugin bundle.
Expand Down
3 changes: 3 additions & 0 deletions codex-rs/app-server/src/request_processors/plugins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ fn convert_configured_marketplace_plugin_to_plugin_summary(
PluginSummary {
id: plugin.id,
remote_plugin_id: None,
version: None,
local_version: plugin.local_version,
installed: plugin.installed,
enabled: plugin.enabled,
Expand Down Expand Up @@ -1095,6 +1096,7 @@ impl PluginRequestProcessor {
summary: PluginSummary {
id: outcome.plugin.id,
remote_plugin_id: None,
version: None,
local_version: outcome.plugin.local_version,
name: outcome.plugin.name,
share_context,
Expand Down Expand Up @@ -2168,6 +2170,7 @@ fn remote_plugin_summary_to_info(summary: RemoteCatalogPluginSummary) -> PluginS
PluginSummary {
id: summary.id,
remote_plugin_id: Some(summary.remote_plugin_id),
version: summary.version,
local_version: summary.local_version,
name: summary.name,
share_context: summary
Expand Down
21 changes: 20 additions & 1 deletion codex-rs/app-server/tests/suite/v2/plugin_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,7 @@ async fn plugin_list_keeps_valid_marketplaces_when_another_marketplace_fails_to_
plugins: vec![PluginSummary {
id: "valid-plugin@valid-marketplace".to_string(),
remote_plugin_id: None,
version: None,
local_version: None,
name: "valid-plugin".to_string(),
share_context: None,
Expand Down Expand Up @@ -743,6 +744,7 @@ async fn plugin_list_uses_alternate_discoverable_manifest_and_keeps_undiscoverab
PluginSummary {
id: "valid-plugin@alternate-marketplace".to_string(),
remote_plugin_id: None,
version: None,
local_version: None,
name: "valid-plugin".to_string(),
share_context: None,
Expand Down Expand Up @@ -780,6 +782,7 @@ async fn plugin_list_uses_alternate_discoverable_manifest_and_keeps_undiscoverab
PluginSummary {
id: "missing-plugin@alternate-marketplace".to_string(),
remote_plugin_id: None,
version: None,
local_version: None,
name: "missing-plugin".to_string(),
share_context: None,
Expand Down Expand Up @@ -1683,6 +1686,7 @@ async fn plugin_list_includes_remote_marketplaces_when_remote_plugin_enabled() -
"authentication_policy": "ON_USE",
"status": "ENABLED",
"release": {
"version": "1.2.3",
"display_name": "Linear",
"description": "Track work in Linear",
"app_ids": [],
Expand Down Expand Up @@ -1831,6 +1835,10 @@ async fn plugin_list_includes_remote_marketplaces_when_remote_plugin_enabled() -
);
assert_eq!(remote_marketplace.plugins[0].name, "linear");
assert_eq!(remote_marketplace.plugins[0].source, PluginSource::Remote);
assert_eq!(
remote_marketplace.plugins[0].version.as_deref(),
Some("1.2.3")
);
assert_eq!(
remote_marketplace.plugins[0].local_version.as_deref(),
Some("1.2.3")
Expand Down Expand Up @@ -2030,6 +2038,7 @@ async fn plugin_list_includes_openai_curated_remote_collection_when_remote_plugi
"authentication_policy": "ON_USE",
"status": "ENABLED",
"release": {
"version": "1.2.3",
"display_name": "Linear",
"description": "Track work in Linear",
"app_ids": [],
Expand Down Expand Up @@ -2090,6 +2099,7 @@ async fn plugin_list_includes_openai_curated_remote_collection_when_remote_plugi
);
assert_eq!(plugin.name, "linear");
assert_eq!(plugin.source, PluginSource::Remote);
assert_eq!(plugin.version.as_deref(), Some("1.2.3"));
assert_eq!(plugin.installed, false);
assert_eq!(plugin.enabled, false);

Expand Down Expand Up @@ -2492,16 +2502,25 @@ plugin_sharing = true
marketplace
.plugins
.iter()
.map(|plugin| (plugin.id.clone(), plugin.installed, plugin.enabled))
.map(|plugin| {
(
plugin.id.clone(),
plugin.version.clone(),
plugin.installed,
plugin.enabled,
)
})
.collect::<Vec<_>>(),
vec![
(
"shared-linear@workspace-shared-with-me".to_string(),
Some("1.2.3".to_string()),
true,
true
),
(
"unlisted-linear@workspace-shared-with-me".to_string(),
Some("1.2.3".to_string()),
true,
false
)
Expand Down
3 changes: 3 additions & 0 deletions codex-rs/app-server/tests/suite/v2/plugin_share.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ async fn plugin_share_save_uploads_local_plugin() -> Result<()> {
plugin: PluginSummary {
id: "demo-plugin@workspace-shared-with-me".to_string(),
remote_plugin_id: Some("plugins_123".to_string()),
version: Some("0.1.0".to_string()),
local_version: Some("0.1.0".to_string()),
name: "demo-plugin".to_string(),
share_context: Some(expected_share_context("plugins_123")),
Expand Down Expand Up @@ -574,6 +575,7 @@ async fn plugin_share_list_returns_created_workspace_plugins() -> Result<()> {
plugin: PluginSummary {
id: "demo-plugin@workspace-shared-with-me".to_string(),
remote_plugin_id: Some("plugins_123".to_string()),
version: Some("0.1.0".to_string()),
local_version: Some("0.1.0".to_string()),
name: "demo-plugin".to_string(),
share_context: Some(expected_share_context("plugins_123")),
Expand Down Expand Up @@ -1174,6 +1176,7 @@ async fn plugin_share_delete_removes_created_workspace_plugin() -> Result<()> {
plugin: PluginSummary {
id: "demo-plugin@workspace-shared-with-me".to_string(),
remote_plugin_id: Some("plugins_123".to_string()),
version: Some("0.1.0".to_string()),
local_version: Some("0.1.0".to_string()),
name: "demo-plugin".to_string(),
share_context: Some(expected_share_context("plugins_123")),
Expand Down
1 change: 1 addition & 0 deletions codex-rs/core-plugins/src/manager_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -777,6 +777,7 @@ fn remote_installed_plugin_in_marketplace(
RemoteInstalledPlugin {
marketplace_name: marketplace_name.to_string(),
id: format!("plugins~Plugin_{name}"),
version: None,
name: name.to_string(),
enabled: true,
install_policy: codex_app_server_protocol::PluginInstallPolicy::Available,
Expand Down
5 changes: 5 additions & 0 deletions codex-rs/core-plugins/src/remote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ pub enum RemoteMarketplaceSource {
pub struct RemoteInstalledPlugin {
pub marketplace_name: String,
pub id: String,
pub version: Option<String>,
pub name: String,
pub enabled: bool,
pub install_policy: PluginInstallPolicy,
Expand All @@ -161,6 +162,7 @@ pub struct RemoteInstalledPlugin {
pub struct RemotePluginSummary {
pub id: String,
pub remote_plugin_id: String,
pub version: Option<String>,
pub local_version: Option<String>,
pub name: String,
pub share_context: Option<RemotePluginShareContext>,
Expand Down Expand Up @@ -1041,6 +1043,7 @@ pub fn group_remote_installed_plugins_by_marketplaces(
let plugin_summary = RemotePluginSummary {
id: plugin_id.as_key(),
remote_plugin_id: plugin.id.clone(),
version: plugin.version.clone(),
local_version: None,
name: plugin.name.clone(),
share_context: None,
Expand Down Expand Up @@ -1472,6 +1475,7 @@ fn build_remote_plugin_summary(
Ok(RemotePluginSummary {
id: plugin_id.as_key(),
remote_plugin_id: plugin.id.clone(),
version: plugin.release.version.clone(),
local_version: installed_plugin
.and_then(|installed| installed.plugin.release.version.clone()),
name: plugin.name.clone(),
Expand Down Expand Up @@ -1554,6 +1558,7 @@ fn remote_installed_plugin_to_cache_entry(
Ok(RemoteInstalledPlugin {
marketplace_name: remote_plugin_canonical_marketplace_name(plugin)?.to_string(),
id: plugin.id.clone(),
version: plugin.release.version.clone(),
name: plugin.name.clone(),
enabled: installed_plugin.enabled,
install_policy: plugin.installation_policy,
Expand Down
2 changes: 2 additions & 0 deletions codex-rs/core-plugins/src/remote/share/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,7 @@ async fn list_remote_plugin_shares_fetches_created_workspace_plugins() {
summary: RemotePluginSummary {
id: "demo-plugin@workspace-shared-with-me".to_string(),
remote_plugin_id: "plugins_123".to_string(),
version: Some("0.1.0".to_string()),
local_version: None,
name: "demo-plugin".to_string(),
share_context: Some(RemotePluginShareContext {
Expand Down Expand Up @@ -658,6 +659,7 @@ async fn list_remote_plugin_shares_fetches_created_workspace_plugins() {
summary: RemotePluginSummary {
id: "demo-plugin@workspace-shared-with-me".to_string(),
remote_plugin_id: "plugins_456".to_string(),
version: Some("0.1.0".to_string()),
local_version: Some("0.1.0".to_string()),
name: "demo-plugin".to_string(),
share_context: Some(RemotePluginShareContext {
Expand Down
1 change: 1 addition & 0 deletions codex-rs/tui/src/app/plugin_mentions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ mod tests {
PluginSummary {
id: format!("{name}@server-marketplace"),
remote_plugin_id: Some(format!("plugins~{name}")),
version: None,
local_version: None,
name: name.to_string(),
share_context: None,
Expand Down
2 changes: 2 additions & 0 deletions codex-rs/tui/src/chatwidget/tests/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1331,6 +1331,7 @@ pub(super) fn plugins_test_summary(
PluginSummary {
id: id.to_string(),
remote_plugin_id: None,
version: None,
local_version: None,
name: name.to_string(),
share_context: None,
Expand Down Expand Up @@ -1361,6 +1362,7 @@ pub(super) fn plugins_test_remote_summary(
PluginSummary {
id: remote_plugin_id.to_string(),
remote_plugin_id: Some(remote_plugin_id.to_string()),
version: None,
local_version: None,
name: name.to_string(),
share_context: None,
Expand Down
Loading