diff --git a/codex-rs/app-server-protocol/schema/json/ClientRequest.json b/codex-rs/app-server-protocol/schema/json/ClientRequest.json index 77f601bad740..1557df56f737 100644 --- a/codex-rs/app-server-protocol/schema/json/ClientRequest.json +++ b/codex-rs/app-server-protocol/schema/json/ClientRequest.json @@ -2199,7 +2199,8 @@ "PluginShareUpdateDiscoverability": { "enum": [ "UNLISTED", - "PRIVATE" + "PRIVATE", + "LISTED" ], "type": "string" }, diff --git a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json index 1f2cd11dff6d..7588992563a7 100644 --- a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json +++ b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json @@ -14531,7 +14531,8 @@ "PluginShareUpdateDiscoverability": { "enum": [ "UNLISTED", - "PRIVATE" + "PRIVATE", + "LISTED" ], "type": "string" }, diff --git a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json index f77838ea6663..7c265ebbff34 100644 --- a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json +++ b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json @@ -10888,7 +10888,8 @@ "PluginShareUpdateDiscoverability": { "enum": [ "UNLISTED", - "PRIVATE" + "PRIVATE", + "LISTED" ], "type": "string" }, diff --git a/codex-rs/app-server-protocol/schema/json/v2/PluginShareUpdateTargetsParams.json b/codex-rs/app-server-protocol/schema/json/v2/PluginShareUpdateTargetsParams.json index 38a7d8d29f29..1a5da52281fd 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/PluginShareUpdateTargetsParams.json +++ b/codex-rs/app-server-protocol/schema/json/v2/PluginShareUpdateTargetsParams.json @@ -38,7 +38,8 @@ "PluginShareUpdateDiscoverability": { "enum": [ "UNLISTED", - "PRIVATE" + "PRIVATE", + "LISTED" ], "type": "string" } diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/PluginShareUpdateDiscoverability.ts b/codex-rs/app-server-protocol/schema/typescript/v2/PluginShareUpdateDiscoverability.ts index fd601987af43..767acae932de 100644 --- a/codex-rs/app-server-protocol/schema/typescript/v2/PluginShareUpdateDiscoverability.ts +++ b/codex-rs/app-server-protocol/schema/typescript/v2/PluginShareUpdateDiscoverability.ts @@ -2,4 +2,4 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -export type PluginShareUpdateDiscoverability = "UNLISTED" | "PRIVATE"; +export type PluginShareUpdateDiscoverability = "UNLISTED" | "PRIVATE" | "LISTED"; diff --git a/codex-rs/app-server-protocol/src/protocol/v2/plugin.rs b/codex-rs/app-server-protocol/src/protocol/v2/plugin.rs index 70ca587222a3..a39db6dd36c2 100644 --- a/codex-rs/app-server-protocol/src/protocol/v2/plugin.rs +++ b/codex-rs/app-server-protocol/src/protocol/v2/plugin.rs @@ -345,6 +345,9 @@ pub enum PluginShareUpdateDiscoverability { #[serde(rename = "PRIVATE")] #[ts(rename = "PRIVATE")] Private, + #[serde(rename = "LISTED")] + #[ts(rename = "LISTED")] + Listed, } #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)] diff --git a/codex-rs/app-server/src/request_processors/plugins.rs b/codex-rs/app-server/src/request_processors/plugins.rs index b6338030ee5a..45663321023c 100644 --- a/codex-rs/app-server/src/request_processors/plugins.rs +++ b/codex-rs/app-server/src/request_processors/plugins.rs @@ -255,6 +255,9 @@ fn remote_plugin_share_update_discoverability( discoverability: PluginShareUpdateDiscoverability, ) -> codex_core_plugins::remote::RemotePluginShareUpdateDiscoverability { match discoverability { + PluginShareUpdateDiscoverability::Listed => { + codex_core_plugins::remote::RemotePluginShareUpdateDiscoverability::Listed + } PluginShareUpdateDiscoverability::Unlisted => { codex_core_plugins::remote::RemotePluginShareUpdateDiscoverability::Unlisted } diff --git a/codex-rs/app-server/tests/suite/v2/plugin_share.rs b/codex-rs/app-server/tests/suite/v2/plugin_share.rs index b8350536eee1..a3445a562a3a 100644 --- a/codex-rs/app-server/tests/suite/v2/plugin_share.rs +++ b/codex-rs/app-server/tests/suite/v2/plugin_share.rs @@ -1078,6 +1078,82 @@ async fn plugin_share_update_targets_updates_share_targets() -> Result<()> { Ok(()) } +#[tokio::test] +async fn plugin_share_update_targets_publishes_workspace_plugin() -> Result<()> { + let codex_home = TempDir::new()?; + let server = MockServer::start().await; + write_remote_plugin_config(codex_home.path(), &format!("{}/backend-api", server.uri()))?; + write_chatgpt_auth( + codex_home.path(), + ChatGptAuthFixture::new("chatgpt-token") + .account_id("account-123") + .chatgpt_user_id("user-123") + .chatgpt_account_id("account-123"), + AuthCredentialsStoreMode::File, + )?; + + Mock::given(method("PUT")) + .and(path("/backend-api/ps/plugins/plugins_123/shares")) + .and(header("authorization", "Bearer chatgpt-token")) + .and(header("chatgpt-account-id", "account-123")) + .and(body_json(json!({ + "discoverability": "LISTED", + "targets": [], + }))) + .respond_with(ResponseTemplate::new(200).set_body_json(json!({ + "principals": [ + { + "principal_type": "user", + "principal_id": "owner-1", + "role": "owner", + "name": "Owner", + }, + ], + "discoverability": "LISTED", + }))) + .expect(1) + .mount(&server) + .await; + + let mut mcp = TestAppServer::builder() + .with_codex_home(codex_home.path()) + .without_auto_env() + .build() + .await?; + timeout(DEFAULT_TIMEOUT, mcp.initialize()).await??; + let request_id = mcp + .send_raw_request( + "plugin/share/updateTargets", + Some(json!({ + "remotePluginId": "plugins_123", + "discoverability": "LISTED", + "shareTargets": [], + })), + ) + .await?; + + let response: JSONRPCResponse = timeout( + DEFAULT_TIMEOUT, + mcp.read_stream_until_response_message(RequestId::Integer(request_id)), + ) + .await??; + let response: PluginShareUpdateTargetsResponse = to_response(response)?; + + assert_eq!( + response, + PluginShareUpdateTargetsResponse { + principals: vec![PluginSharePrincipal { + principal_type: PluginSharePrincipalType::User, + principal_id: "owner-1".to_string(), + role: PluginSharePrincipalRole::Owner, + name: "Owner".to_string(), + }], + discoverability: codex_app_server_protocol::PluginShareDiscoverability::Listed, + } + ); + Ok(()) +} + #[tokio::test] async fn plugin_share_update_targets_rejects_when_plugin_sharing_disabled() -> Result<()> { let codex_home = TempDir::new()?; diff --git a/codex-rs/core-plugins/src/remote/share.rs b/codex-rs/core-plugins/src/remote/share.rs index c400d27c47d4..44644c91375a 100644 --- a/codex-rs/core-plugins/src/remote/share.rs +++ b/codex-rs/core-plugins/src/remote/share.rs @@ -43,6 +43,7 @@ pub enum RemotePluginShareDiscoverability { #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] pub enum RemotePluginShareUpdateDiscoverability { + Listed, Unlisted, Private, } @@ -300,6 +301,7 @@ pub async fn update_remote_plugin_share_targets( ) -> Result { let auth = ensure_chatgpt_auth(auth)?; let target_discoverability = match discoverability { + RemotePluginShareUpdateDiscoverability::Listed => RemotePluginShareDiscoverability::Listed, RemotePluginShareUpdateDiscoverability::Unlisted => { RemotePluginShareDiscoverability::Unlisted }