diff --git a/codex-rs/core/src/plugins/manager.rs b/codex-rs/core/src/plugins/manager.rs index c2db3a1de1..af02b06afd 100644 --- a/codex-rs/core/src/plugins/manager.rs +++ b/codex-rs/core/src/plugins/manager.rs @@ -73,6 +73,7 @@ const DEFAULT_MCP_CONFIG_FILE: &str = ".mcp.json"; const DEFAULT_APP_CONFIG_FILE: &str = ".app.json"; pub const OPENAI_CURATED_MARKETPLACE_NAME: &str = "openai-curated"; static CURATED_REPO_SYNC_STARTED: AtomicBool = AtomicBool::new(false); +const MAX_CAPABILITY_SUMMARY_DESCRIPTION_LEN: usize = 140; #[derive(Debug, Clone, PartialEq, Eq)] pub struct PluginInstallRequest { @@ -269,6 +270,23 @@ impl From for PluginCapabilitySummary { } } +fn prompt_safe_plugin_description(description: Option<&str>) -> Option { + let description = description? + .split_whitespace() + .collect::>() + .join(" "); + if description.is_empty() { + return None; + } + + Some( + description + .chars() + .take(MAX_CAPABILITY_SUMMARY_DESCRIPTION_LEN) + .collect(), + ) +} + #[derive(Debug, Clone, Default, PartialEq, Eq)] pub struct RemotePluginSyncResult { /// Plugin ids newly installed into the local plugin cache. diff --git a/codex-rs/core/src/plugins/manifest.rs b/codex-rs/core/src/plugins/manifest.rs index f3ca0e17a3..1bf3769b65 100644 --- a/codex-rs/core/src/plugins/manifest.rs +++ b/codex-rs/core/src/plugins/manifest.rs @@ -1,5 +1,3 @@ -pub(crate) use codex_extensions::plugins::PLUGIN_MANIFEST_PATH; -pub(crate) use codex_extensions::plugins::PluginManifest; pub use codex_extensions::plugins::PluginManifestInterfaceSummary; pub(crate) use codex_extensions::plugins::PluginManifestPaths; pub(crate) use codex_extensions::plugins::load_plugin_manifest; diff --git a/codex-rs/core/src/plugins/store.rs b/codex-rs/core/src/plugins/store.rs index 9424734e16..6d87569318 100644 --- a/codex-rs/core/src/plugins/store.rs +++ b/codex-rs/core/src/plugins/store.rs @@ -1,5 +1,4 @@ pub(crate) use codex_extensions::plugins::DEFAULT_PLUGIN_VERSION; -pub(crate) use codex_extensions::plugins::PLUGINS_CACHE_DIR; pub use codex_extensions::plugins::PluginId; pub use codex_extensions::plugins::PluginIdError; pub(crate) use codex_extensions::plugins::PluginInstallResult; diff --git a/codex-rs/extensions/src/plugins/store.rs b/codex-rs/extensions/src/plugins/store.rs index 0c916fd2a6..43fc605d5f 100644 --- a/codex-rs/extensions/src/plugins/store.rs +++ b/codex-rs/extensions/src/plugins/store.rs @@ -262,13 +262,23 @@ fn replace_plugin_root_atomically( fs::create_dir_all(parent) .map_err(|err| PluginStoreError::io("failed to create plugin cache parent", err))?; - let target = target_root.join(plugin_version); - let staging = target_root.join(format!(".{plugin_version}.tmp")); - remove_existing_target(staging.as_path())?; + let target = parent.join(format!( + ".{}-{}.next", + target_root + .file_name() + .and_then(|file_name| file_name.to_str()) + .ok_or_else(|| PluginStoreError::Invalid(format!( + "plugin cache path has no terminal directory name: {}", + target_root.display() + )))?, + plugin_version + )); + let staging = target.join(plugin_version); remove_existing_target(target.as_path())?; copy_dir_recursive(source, staging.as_path())?; - fs::rename(staging.as_path(), target.as_path()) + remove_existing_target(target_root)?; + fs::rename(target.as_path(), target_root) .map_err(|err| PluginStoreError::io("failed to activate plugin cache entry", err)) }