mirror of
https://github.com/openai/codex.git
synced 2026-09-09 15:58:47 +00:00
Record added marketplaces in local registry
This commit is contained in:
@@ -5,6 +5,7 @@ use clap::Parser;
|
||||
use codex_core::config::find_codex_home;
|
||||
use codex_core::plugins::OPENAI_CURATED_MARKETPLACE_NAME;
|
||||
use codex_core::plugins::marketplace_install_root;
|
||||
use codex_core::plugins::record_installed_marketplace_root;
|
||||
use codex_core::plugins::validate_marketplace_root;
|
||||
use codex_utils_cli::CliConfigOverrides;
|
||||
use std::fs;
|
||||
@@ -162,6 +163,8 @@ async fn run_add(args: AddMarketplaceArgs) -> Result<()> {
|
||||
ensure_marketplace_destination_is_inside_install_root(&install_root, &destination)?;
|
||||
replace_marketplace_root(&staged_root, &destination)
|
||||
.with_context(|| format!("failed to install marketplace at {}", destination.display()))?;
|
||||
record_installed_marketplace_root(&codex_home, &marketplace_name, &destination)
|
||||
.with_context(|| format!("failed to record marketplace `{marketplace_name}`"))?;
|
||||
|
||||
println!(
|
||||
"Added marketplace `{marketplace_name}` from {}.",
|
||||
|
||||
@@ -53,6 +53,9 @@ async fn marketplace_add_local_directory_installs_valid_marketplace_root() -> Re
|
||||
|
||||
let installed_root = marketplace_install_root(codex_home.path()).join("debug");
|
||||
assert_eq!(validate_marketplace_root(&installed_root)?, "debug");
|
||||
let registry = std::fs::read_to_string(codex_home.path().join(".tmp/known_marketplaces.json"))?;
|
||||
assert!(registry.contains(r#""name": "debug""#));
|
||||
assert!(registry.contains(r#""installLocation""#));
|
||||
assert!(
|
||||
installed_root
|
||||
.join("plugins/sample/.codex-plugin/plugin.json")
|
||||
|
||||
@@ -58,6 +58,7 @@ use codex_protocol::protocol::Product;
|
||||
use codex_protocol::protocol::SkillScope;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use serde_json::Map as JsonMap;
|
||||
use serde_json::Value as JsonValue;
|
||||
use serde_json::json;
|
||||
@@ -79,7 +80,8 @@ use tracing::warn;
|
||||
const DEFAULT_SKILLS_DIR_NAME: &str = "skills";
|
||||
const DEFAULT_MCP_CONFIG_FILE: &str = ".mcp.json";
|
||||
const DEFAULT_APP_CONFIG_FILE: &str = ".app.json";
|
||||
pub const INSTALLED_MARKETPLACES_DIR: &str = ".tmp/plugins/marketplaces";
|
||||
pub const INSTALLED_MARKETPLACES_DIR: &str = ".tmp/marketplaces";
|
||||
const KNOWN_MARKETPLACES_FILE: &str = "known_marketplaces.json";
|
||||
pub const OPENAI_CURATED_MARKETPLACE_NAME: &str = "openai-curated";
|
||||
pub const OPENAI_CURATED_MARKETPLACE_DISPLAY_NAME: &str = "OpenAI Curated";
|
||||
static CURATED_REPO_SYNC_STARTED: AtomicBool = AtomicBool::new(false);
|
||||
@@ -1240,7 +1242,37 @@ pub fn marketplace_install_root(codex_home: &Path) -> PathBuf {
|
||||
codex_home.join(INSTALLED_MARKETPLACES_DIR)
|
||||
}
|
||||
|
||||
pub fn record_installed_marketplace_root(
|
||||
codex_home: &Path,
|
||||
marketplace_name: &str,
|
||||
install_location: &Path,
|
||||
) -> std::io::Result<()> {
|
||||
let registry_path = marketplace_registry_path(codex_home);
|
||||
let mut registry = if registry_path.is_file() {
|
||||
read_marketplace_registry(®istry_path)?
|
||||
} else {
|
||||
KnownMarketplacesRegistry::default()
|
||||
};
|
||||
|
||||
registry
|
||||
.marketplaces
|
||||
.retain(|marketplace| marketplace.name != marketplace_name);
|
||||
registry.marketplaces.push(KnownMarketplaceRegistryEntry {
|
||||
name: marketplace_name.to_string(),
|
||||
install_location: install_location.to_path_buf(),
|
||||
});
|
||||
registry
|
||||
.marketplaces
|
||||
.sort_unstable_by(|left, right| left.name.cmp(&right.name));
|
||||
write_marketplace_registry(®istry_path, ®istry)
|
||||
}
|
||||
|
||||
fn installed_marketplace_roots(codex_home: &Path) -> Vec<AbsolutePathBuf> {
|
||||
let registry_path = marketplace_registry_path(codex_home);
|
||||
if registry_path.is_file() {
|
||||
return installed_marketplace_roots_from_registry(®istry_path);
|
||||
}
|
||||
|
||||
let install_root = marketplace_install_root(codex_home);
|
||||
let Ok(entries) = fs::read_dir(&install_root) else {
|
||||
return Vec::new();
|
||||
@@ -1260,6 +1292,86 @@ fn installed_marketplace_roots(codex_home: &Path) -> Vec<AbsolutePathBuf> {
|
||||
roots
|
||||
}
|
||||
|
||||
fn marketplace_registry_path(codex_home: &Path) -> PathBuf {
|
||||
codex_home.join(".tmp").join(KNOWN_MARKETPLACES_FILE)
|
||||
}
|
||||
|
||||
fn installed_marketplace_roots_from_registry(registry_path: &Path) -> Vec<AbsolutePathBuf> {
|
||||
let registry = match read_marketplace_registry(registry_path) {
|
||||
Ok(registry) => registry,
|
||||
Err(err) => {
|
||||
warn!(
|
||||
path = %registry_path.display(),
|
||||
error = %err,
|
||||
"failed to read installed marketplace registry"
|
||||
);
|
||||
return Vec::new();
|
||||
}
|
||||
};
|
||||
|
||||
let mut roots = registry
|
||||
.marketplaces
|
||||
.into_iter()
|
||||
.filter_map(|marketplace| {
|
||||
let path = marketplace.install_location;
|
||||
if path.join(".agents/plugins/marketplace.json").is_file() {
|
||||
AbsolutePathBuf::try_from(path).ok()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
roots.sort_unstable_by(|left, right| left.as_path().cmp(right.as_path()));
|
||||
roots
|
||||
}
|
||||
|
||||
fn read_marketplace_registry(path: &Path) -> std::io::Result<KnownMarketplacesRegistry> {
|
||||
let contents = fs::read_to_string(path)?;
|
||||
serde_json::from_str(&contents).map_err(|err| {
|
||||
std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidData,
|
||||
format!(
|
||||
"failed to parse marketplace registry {}: {err}",
|
||||
path.display()
|
||||
),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
fn write_marketplace_registry(
|
||||
path: &Path,
|
||||
registry: &KnownMarketplacesRegistry,
|
||||
) -> std::io::Result<()> {
|
||||
if let Some(parent) = path.parent() {
|
||||
fs::create_dir_all(parent)?;
|
||||
}
|
||||
let contents = serde_json::to_vec_pretty(registry).map_err(std::io::Error::other)?;
|
||||
fs::write(path, contents)
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct KnownMarketplacesRegistry {
|
||||
version: u32,
|
||||
marketplaces: Vec<KnownMarketplaceRegistryEntry>,
|
||||
}
|
||||
|
||||
impl Default for KnownMarketplacesRegistry {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
version: 1,
|
||||
marketplaces: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct KnownMarketplaceRegistryEntry {
|
||||
name: String,
|
||||
install_location: PathBuf,
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum PluginInstallError {
|
||||
#[error("{0}")]
|
||||
|
||||
@@ -1539,6 +1539,8 @@ plugins = true
|
||||
r#"{"name":"sample"}"#,
|
||||
)
|
||||
.unwrap();
|
||||
record_installed_marketplace_root(tmp.path(), "debug", &marketplace_root)
|
||||
.expect("record installed marketplace");
|
||||
|
||||
let config = load_config(tmp.path(), tmp.path()).await;
|
||||
let marketplaces = PluginsManager::new(tmp.path().to_path_buf())
|
||||
|
||||
@@ -46,6 +46,7 @@ pub use manager::load_plugin_apps;
|
||||
pub use manager::load_plugin_mcp_servers;
|
||||
pub use manager::marketplace_install_root;
|
||||
pub use manager::plugin_telemetry_metadata_from_root;
|
||||
pub use manager::record_installed_marketplace_root;
|
||||
pub use manifest::PluginManifestInterface;
|
||||
pub(crate) use manifest::PluginManifestPaths;
|
||||
pub(crate) use manifest::load_plugin_manifest;
|
||||
|
||||
Reference in New Issue
Block a user