[codex] Refactor marketplace add into shared core flow (#17717)

## Summary

Move `codex marketplace add` onto a shared core implementation so the
CLI and app-server path can use one source of truth.

This change:
- adds shared marketplace-add orchestration in `codex-core`
- switches the CLI command to call that shared implementation
- removes duplicated CLI-only marketplace add helpers
- preserves focused parser and add-path coverage while moving the shared
behavior into core tests

## Why

The new `marketplace/add` RPC should reuse the same underlying
marketplace-add flow as the CLI. This refactor lands that consolidation
first so the follow-up app-server PR can be mostly protocol and handler
wiring.

## Validation

- `cargo test -p codex-core marketplace_add`
- `cargo test -p codex-cli marketplace_cmd`
- `just fix -p codex-core`
- `just fix -p codex-cli`
- `just fmt`
This commit is contained in:
xli-oai
2026-04-13 20:37:11 -07:00
committed by GitHub
parent d9a385ac8c
commit ff584c5a4b
24 changed files with 1321 additions and 720 deletions
@@ -76,6 +76,8 @@ use codex_app_server_protocol::LoginAccountParams;
use codex_app_server_protocol::LoginAccountResponse;
use codex_app_server_protocol::LoginApiKeyParams;
use codex_app_server_protocol::LogoutAccountResponse;
use codex_app_server_protocol::MarketplaceAddParams;
use codex_app_server_protocol::MarketplaceAddResponse;
use codex_app_server_protocol::MarketplaceInterface;
use codex_app_server_protocol::McpResourceReadParams;
use codex_app_server_protocol::McpResourceReadResponse;
@@ -228,6 +230,7 @@ use codex_core::find_thread_names_by_ids;
use codex_core::find_thread_path_by_id_str;
use codex_core::parse_cursor;
use codex_core::path_utils;
use codex_core::plugins::MarketplaceAddError;
use codex_core::plugins::MarketplaceError;
use codex_core::plugins::MarketplacePluginSource;
use codex_core::plugins::OPENAI_CURATED_MARKETPLACE_NAME;
@@ -235,6 +238,7 @@ use codex_core::plugins::PluginInstallError as CorePluginInstallError;
use codex_core::plugins::PluginInstallRequest;
use codex_core::plugins::PluginReadRequest;
use codex_core::plugins::PluginUninstallError as CorePluginUninstallError;
use codex_core::plugins::add_marketplace as add_marketplace_to_codex_home;
use codex_core::plugins::load_plugin_apps;
use codex_core::plugins::load_plugin_mcp_servers;
use codex_core::read_head_for_summary;
@@ -927,6 +931,10 @@ impl CodexMessageProcessor {
self.skills_list(to_connection_request_id(request_id), params)
.await;
}
ClientRequest::MarketplaceAdd { request_id, params } => {
self.marketplace_add(to_connection_request_id(request_id), params)
.await;
}
ClientRequest::PluginList { request_id, params } => {
self.plugin_list(to_connection_request_id(request_id), params)
.await;
@@ -6483,6 +6491,39 @@ impl CodexMessageProcessor {
.await;
}
async fn marketplace_add(&self, request_id: ConnectionRequestId, params: MarketplaceAddParams) {
let result = add_marketplace_to_codex_home(
self.config.codex_home.to_path_buf(),
codex_core::plugins::MarketplaceAddRequest {
source: params.source,
ref_name: params.ref_name,
sparse_paths: params.sparse_paths.unwrap_or_default(),
},
)
.await;
match result {
Ok(outcome) => {
self.outgoing
.send_response(
request_id,
MarketplaceAddResponse {
marketplace_name: outcome.marketplace_name,
installed_root: outcome.installed_root,
already_added: outcome.already_added,
},
)
.await;
}
Err(MarketplaceAddError::InvalidRequest(message)) => {
self.send_invalid_request_error(request_id, message).await;
}
Err(MarketplaceAddError::Internal(message)) => {
self.send_internal_error(request_id, message).await;
}
}
}
async fn plugin_read(&self, request_id: ConnectionRequestId, params: PluginReadParams) {
let plugins_manager = self.thread_manager.plugins_manager();
let PluginReadParams {