#![cfg_attr(not(test), deny(clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::unimplemented, clippy::todo, clippy::unreachable))]
pub mod agents;
pub mod authoring;
pub mod backend;
pub mod commands;
pub mod connectors;
pub mod discover;
pub mod manifest;
pub mod materialize;
pub mod mcp;
pub mod names;
pub mod native;
pub mod pyenv;
pub mod python;
pub mod skills;
use std::collections::BTreeMap;
use std::fmt;
use std::path::PathBuf;
pub use agents::{AgentDef, load_agents_dir, merge_agents, parse_agent};
pub use backend::{Backend, BackendTool};
pub use commands::{Command, load_commands_dir, split_slash};
pub use connectors::{
Connector, ConnectorContent, ConnectorDraft, ConnectorResult, ConnectorTool, ConnectorToolAdapter, base64_decode, connector_tools, connector_tools_from,
connector_tools_on, parse_connector,
};
pub use discover::{BUNDLED_DIR, Discovery, Embedded, Plugin, PluginSources, discover, discover_embedded, load_embedded, load_plugin};
pub use manifest::{MANIFEST, Manifest, ManifestError, McpServerConfig, OLD_MANIFEST, parse_manifest};
pub use names::ToolNames;
pub use pyenv::{PluginPython, PyEnvs};
pub use python::{PythonTool, default_python, python_tools, python_tools_in, python_tools_with, run_script_sandboxed, run_script_unsandboxed};
pub use skills::{SaveSkillTool, Skill, UseSkillTool, load_skills_dir, skills_prompt};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct LoadError {
pub path: PathBuf,
pub message: String,
}
impl fmt::Display for LoadError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}: {}", self.path.display(), self.message)
}
}
impl std::error::Error for LoadError {}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PluginRef {
pub id: String,
pub name: String,
pub dir: PathBuf,
pub network: bool,
pub env: BTreeMap<String, String>,
}
impl PluginRef {
pub fn new(plugin: &Plugin, settings: &BTreeMap<String, String>) -> Self {
let mut env: BTreeMap<String, String> = plugin.manifest.settings.iter().filter_map(|s| Some((s.key.clone(), s.default.clone()?))).collect();
for s in &plugin.manifest.settings {
if let Some(v) = settings.get(&s.key) {
env.insert(s.key.clone(), v.clone());
}
}
Self { id: plugin.manifest.id.clone(), name: plugin.manifest.name.clone(), dir: plugin.dir.clone(), network: plugin.manifest.permissions.network, env }
}
pub fn missing_settings(plugin: &Plugin, settings: &BTreeMap<String, String>) -> Vec<String> {
plugin
.manifest
.settings
.iter()
.filter(|s| s.required && settings.get(&s.key).or(s.default.as_ref()).is_none_or(|v| v.trim().is_empty()))
.map(|s| s.label.clone())
.collect()
}
}