use crate::manifest::PluginManifest;
use codex_protocol::capabilities::SelectedCapabilityRoot;
use codex_utils_path_uri::PathUri;
use std::error::Error as StdError;
use std::future::Future;
use thiserror::Error;
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum PluginResourceLocator {
Environment {
environment_id: String,
path: PathUri,
},
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ResolvedPluginLocation {
Environment {
environment_id: String,
root: PathUri,
},
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ResolvedPlugin {
selected_root_id: String,
location: ResolvedPluginLocation,
manifest_path: PluginResourceLocator,
manifest: PluginManifest<PluginResourceLocator>,
}
#[derive(Clone, Debug, Error, PartialEq, Eq)]
pub enum ResolvedPluginError {
#[error("plugin resource path `{path}` is outside package root `{root}`")]
ResourceOutsideRoot { root: PathUri, path: PathUri },
}
impl ResolvedPlugin {
pub fn from_environment(
selected_root_id: String,
environment_id: String,
root: PathUri,
manifest_path: PathUri,
manifest: PluginManifest<PathUri>,
) -> Result<Self, ResolvedPluginError> {
let manifest_path = environment_resource(&environment_id, &root, manifest_path)?;
let manifest = manifest
.try_map_resources(|path| environment_resource(&environment_id, &root, path))?;
Ok(Self {
selected_root_id,
location: ResolvedPluginLocation::Environment {
environment_id,
root,
},
manifest_path,
manifest,
})
}
pub fn selected_root_id(&self) -> &str {
&self.selected_root_id
}
pub fn location(&self) -> &ResolvedPluginLocation {
&self.location
}
pub fn manifest_path(&self) -> &PluginResourceLocator {
&self.manifest_path
}
pub fn manifest(&self) -> &PluginManifest<PluginResourceLocator> {
&self.manifest
}
}
fn environment_resource(
environment_id: &str,
root: &PathUri,
path: PathUri,
) -> Result<PluginResourceLocator, ResolvedPluginError> {
if !path.starts_with(root) {
return Err(ResolvedPluginError::ResourceOutsideRoot {
root: root.clone(),
path,
});
}
Ok(PluginResourceLocator::Environment {
environment_id: environment_id.to_string(),
path,
})
}
pub trait PluginProvider: Send + Sync {
type Error: StdError + Send + Sync + 'static;
fn resolve(
&self,
root: &SelectedCapabilityRoot,
) -> impl Future<Output = Result<Option<ResolvedPlugin>, Self::Error>> + Send;
}
#[cfg(test)]
#[path = "provider_tests.rs"]
mod tests;