use crate::manifest::parse_plugin_manifest;use codex_exec_server::EnvironmentManager;use codex_exec_server::ExecutorFileSystem;use codex_plugin::PluginProvider;use codex_plugin::ResolvedPlugin;use codex_plugin::ResolvedPluginError;use codex_protocol::capabilities::CapabilityRootLocation;use codex_protocol::capabilities::SelectedCapabilityRoot;use codex_utils_absolute_path::AbsolutePathBuf;use codex_utils_path_uri::PathUri;use codex_utils_plugins::DISCOVERABLE_PLUGIN_MANIFEST_PATHS;use std::io;use std::path::PathBuf;use std::sync::Arc;use thiserror::Error;/// Failure to resolve an environment-owned capability root as a plugin package.#[derive(Debug, Error)]pub enum ExecutorPluginProviderError { #[error("selected capability root `{root_id}` has invalid path `{path}`: {message}")] InvalidRootPath { root_id: String, path: String, message: String, }, #[error( "selected capability root `{root_id}` references unavailable environment `{environment_id}`" )] UnavailableEnvironment { root_id: String, environment_id: String, }, #[error("failed to inspect selected capability root `{root_id}` at {path}: {source}")] InspectRoot { root_id: String, path: AbsolutePathBuf, #[source] source: io::Error, }, #[error("selected capability root `{root_id}` path {path} is not a directory")] RootNotDirectory { root_id: String, path: AbsolutePathBuf, }, #[error("failed to inspect plugin manifest for `{root_id}` at {path}: {source}")] InspectManifest { root_id: String, path: AbsolutePathBuf, #[source] source: io::Error, }, #[error("failed to read plugin manifest for `{root_id}` at {path}: {source}")] ReadManifest { root_id: String, path: AbsolutePathBuf, #[source] source: io::Error, }, #[error("failed to parse plugin manifest for `{root_id}` at {path}: {source}")] ParseManifest { root_id: String, path: AbsolutePathBuf, #[source] source: serde_json::Error, }, #[error("failed to construct plugin descriptor for `{root_id}`: {source}")] ConstructDescriptor { root_id: String, #[source] source: ResolvedPluginError, },}/// Resolves plugin packages through the filesystem owned by an execution environment.#[derive(Clone, Debug)]pub struct ExecutorPluginProvider { environment_manager: Arc<EnvironmentManager>,}/// A resolved plugin paired with the concrete filesystem used to read it.#[derive(Clone)]pub struct ResolvedExecutorPlugin { plugin: ResolvedPlugin, file_system: Arc<dyn ExecutorFileSystem>,}impl ResolvedExecutorPlugin { /// Returns the source-neutral plugin descriptor. pub fn plugin(&self) -> &ResolvedPlugin { &self.plugin } /// Returns the concrete filesystem that resolved the descriptor. pub fn file_system(&self) -> &dyn ExecutorFileSystem { self.file_system.as_ref() }}impl ExecutorPluginProvider { /// Creates a provider backed by the active execution environments. pub fn new(environment_manager: Arc<EnvironmentManager>) -> Self { Self { environment_manager, } } /// Resolves a plugin and retains the exact filesystem used for package access. pub async fn resolve_bound( &self, selected_root: &SelectedCapabilityRoot, ) -> Result<Option<ResolvedExecutorPlugin>, ExecutorPluginProviderError> { let root_id = &selected_root.id; let plugin_root = selected_plugin_root(selected_root)?; let CapabilityRootLocation::Environment { environment_id, .. } = &selected_root.location; let environment = self .environment_manager .get_environment(environment_id) .ok_or_else(|| ExecutorPluginProviderError::UnavailableEnvironment { root_id: root_id.clone(), environment_id: environment_id.clone(), })?; let file_system = environment.get_filesystem(); let plugin = resolve_plugin_root(selected_root, plugin_root, file_system.as_ref()).await?; Ok(plugin.map(|plugin| ResolvedExecutorPlugin { plugin, file_system, })) }}impl PluginProvider for ExecutorPluginProvider { type Error = ExecutorPluginProviderError; async fn resolve( &self, selected_root: &SelectedCapabilityRoot, ) -> Result<Option<ResolvedPlugin>, Self::Error> { self.resolve_bound(selected_root) .await .map(|plugin| plugin.map(|plugin| plugin.plugin)) }}fn selected_plugin_root( selected_root: &SelectedCapabilityRoot,) -> Result<AbsolutePathBuf, ExecutorPluginProviderError> { let root_id = &selected_root.id; let CapabilityRootLocation::Environment { path, .. } = &selected_root.location; let plugin_root = PathBuf::from(path); if !plugin_root.is_absolute() { return Err(ExecutorPluginProviderError::InvalidRootPath { root_id: root_id.clone(), path: path.clone(), message: "executor path must be absolute".to_string(), }); } AbsolutePathBuf::from_absolute_path_checked(plugin_root).map_err(|err| { ExecutorPluginProviderError::InvalidRootPath { root_id: root_id.clone(), path: path.clone(), message: err.to_string(), } })}async fn resolve_plugin_root( selected_root: &SelectedCapabilityRoot, plugin_root: AbsolutePathBuf, file_system: &dyn ExecutorFileSystem,) -> Result<Option<ResolvedPlugin>, ExecutorPluginProviderError> { let root_id = &selected_root.id; let CapabilityRootLocation::Environment { environment_id, .. } = &selected_root.location; let root_uri = PathUri::from_abs_path(&plugin_root); let root_metadata = file_system .get_metadata(&root_uri, /*sandbox*/ None) .await .map_err(|source| ExecutorPluginProviderError::InspectRoot { root_id: root_id.clone(), path: plugin_root.clone(), source, })?; if !root_metadata.is_directory { return Err(ExecutorPluginProviderError::RootNotDirectory { root_id: root_id.clone(), path: plugin_root, }); } let mut manifest_path = None; for relative_path in DISCOVERABLE_PLUGIN_MANIFEST_PATHS { let candidate = plugin_root.join(relative_path); let candidate_uri = PathUri::from_abs_path(&candidate); match file_system .get_metadata(&candidate_uri, /*sandbox*/ None) .await { Ok(metadata) if metadata.is_file => { manifest_path = Some((candidate, candidate_uri)); break; } Ok(_) => {} Err(err) if err.kind() == io::ErrorKind::NotFound => {} Err(source) => { return Err(ExecutorPluginProviderError::InspectManifest { root_id: root_id.clone(), path: candidate, source, }); } } } let Some((manifest_path, manifest_uri)) = manifest_path else { return Ok(None); }; let contents = file_system .read_file_text(&manifest_uri, /*sandbox*/ None) .await .map_err(|source| ExecutorPluginProviderError::ReadManifest { root_id: root_id.clone(), path: manifest_path.clone(), source, })?; let manifest = parse_plugin_manifest(&plugin_root, &manifest_path, &contents).map_err(|source| { ExecutorPluginProviderError::ParseManifest { root_id: root_id.clone(), path: manifest_path.clone(), source, } })?; let plugin = ResolvedPlugin::from_environment( root_id.clone(), environment_id.clone(), plugin_root, manifest_path, manifest, ) .map_err(|source| ExecutorPluginProviderError::ConstructDescriptor { root_id: root_id.clone(), source, })?; Ok(Some(plugin))}#[cfg(test)]#[path = "provider_tests.rs"]mod tests;