Add app-server marketplace upgrade RPC (#19074)

## Summary
- add a v2 `marketplace/upgrade` app-server RPC that mirrors the
existing configured Git marketplace upgrade path
- expose typed request/response/error payloads and regenerate
JSON/TypeScript schema fixtures
- add app-server integration coverage for all, named, already
up-to-date, and invalid marketplace upgrade requests

## Tests
- `just write-app-server-schema`
- `cargo test -p codex-app-server-protocol`
- `cargo test -p codex-app-server marketplace_upgrade`
- `just fix -p codex-app-server-protocol`
- `just fix -p codex-app-server`
- `just fmt`
This commit is contained in:
xli-oai
2026-04-23 13:00:46 -07:00
committed by GitHub
Unverified
parent 491a3058f6
commit 0d6a90cd6b
18 changed files with 806 additions and 8 deletions
@@ -357,6 +357,10 @@ client_request_definitions! {
params: v2::MarketplaceRemoveParams,
response: v2::MarketplaceRemoveResponse,
},
MarketplaceUpgrade => "marketplace/upgrade" {
params: v2::MarketplaceUpgradeParams,
response: v2::MarketplaceUpgradeResponse,
},
PluginList => "plugin/list" {
params: v2::PluginListParams,
response: v2::PluginListResponse,
@@ -4104,6 +4104,31 @@ pub struct MarketplaceRemoveResponse {
pub installed_root: Option<AbsolutePathBuf>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct MarketplaceUpgradeParams {
#[ts(optional = nullable)]
pub marketplace_name: Option<String>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct MarketplaceUpgradeResponse {
pub selected_marketplaces: Vec<String>,
pub upgraded_roots: Vec<AbsolutePathBuf>,
pub errors: Vec<MarketplaceUpgradeErrorInfo>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct MarketplaceUpgradeErrorInfo {
pub marketplace_name: String,
pub message: String,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
@@ -9790,6 +9815,36 @@ mod tests {
);
}
#[test]
fn marketplace_upgrade_params_serialization_uses_optional_marketplace_name() {
assert_eq!(
serde_json::to_value(MarketplaceUpgradeParams {
marketplace_name: None,
})
.unwrap(),
json!({
"marketplaceName": null,
}),
);
assert_eq!(
serde_json::from_value::<MarketplaceUpgradeParams>(json!({})).unwrap(),
MarketplaceUpgradeParams {
marketplace_name: None,
},
);
assert_eq!(
serde_json::to_value(MarketplaceUpgradeParams {
marketplace_name: Some("debug".to_string()),
})
.unwrap(),
json!({
"marketplaceName": "debug",
}),
);
}
#[test]
fn plugin_marketplace_entry_serializes_remote_only_path_as_null() {
assert_eq!(
@@ -10036,6 +10091,37 @@ mod tests {
);
}
#[test]
fn marketplace_upgrade_response_serializes_camel_case_fields() {
let upgraded_root = if cfg!(windows) {
r"C:\marketplaces\debug"
} else {
"/tmp/marketplaces/debug"
};
let upgraded_root = AbsolutePathBuf::try_from(PathBuf::from(upgraded_root)).unwrap();
let upgraded_root_json = upgraded_root.as_path().display().to_string();
assert_eq!(
serde_json::to_value(MarketplaceUpgradeResponse {
selected_marketplaces: vec!["debug".to_string()],
upgraded_roots: vec![upgraded_root],
errors: vec![MarketplaceUpgradeErrorInfo {
marketplace_name: "broken".to_string(),
message: "failed to clone".to_string(),
}],
})
.unwrap(),
json!({
"selectedMarketplaces": ["debug"],
"upgradedRoots": [upgraded_root_json],
"errors": [{
"marketplaceName": "broken",
"message": "failed to clone",
}],
}),
);
}
#[test]
fn codex_error_info_serializes_http_status_code_in_camel_case() {
let value = CodexErrorInfo::ResponseTooManyFailedAttempts {