use codex_core_skills::model::SkillDependencies;use codex_utils_absolute_path::AbsolutePathBuf;/// Source authority that owns a skill package and must be used to read it.#[derive(Clone, Debug, PartialEq, Eq, Hash)]pub enum SkillSourceKind { /// Codex-hosted skills, including bundled, user, repo, plugin-installed, /// and downloaded/materialized remote skills. Host, /// Skills owned by an execution environment. Executor, /// Skills owned by the orchestrator rather than an execution environment. Orchestrator, /// Extension-private source kind for future providers that do not fit an /// existing transport category. Custom(String),}impl SkillSourceKind { pub fn custom(kind: impl Into<String>) -> Self { Self::Custom(kind.into()) } fn as_str(&self) -> &str { match self { Self::Host => "host", Self::Executor => "executor", Self::Orchestrator => "orchestrator", Self::Custom(kind) => kind, } }}impl std::fmt::Display for SkillSourceKind { fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.as_str().fmt(formatter) }}/// Opaque authority identity for list/read routing.#[derive(Clone, Debug, PartialEq, Eq, Hash)]pub struct SkillAuthority { pub kind: SkillSourceKind, pub id: String,}impl SkillAuthority { pub fn new(kind: SkillSourceKind, id: impl Into<String>) -> Self { Self { kind, id: id.into(), } }}/// Opaque package id. Callers should not parse local paths out of this value.#[derive(Clone, Debug, PartialEq, Eq, Hash)]pub struct SkillPackageId(pub String);/// Opaque resource id inside a skill package, optionally bound to the/// environment path that owns its contents.#[derive(Clone, Debug, PartialEq, Eq, Hash)]pub struct SkillResourceId { id: String, environment_path: Option<EnvironmentSkillResource>,}impl SkillResourceId { pub fn new(id: impl Into<String>) -> Self { Self { id: id.into(), environment_path: None, } } pub fn environment( id: impl Into<String>, environment_id: impl Into<String>, path: AbsolutePathBuf, ) -> Self { Self { id: id.into(), environment_path: Some(EnvironmentSkillResource { environment_id: environment_id.into(), path, }), } } pub fn as_str(&self) -> &str { &self.id } pub(crate) fn environment_path(&self) -> Option<(&str, &AbsolutePathBuf)> { self.environment_path .as_ref() .map(|resource| (resource.environment_id.as_str(), &resource.path)) }}#[derive(Clone, Debug, PartialEq, Eq, Hash)]struct EnvironmentSkillResource { environment_id: String, path: AbsolutePathBuf,}/// Metadata shown in the always-visible skills catalog.#[derive(Clone, Debug, PartialEq, Eq)]pub struct SkillCatalogEntry { pub id: SkillPackageId, pub authority: SkillAuthority, pub name: String, pub description: String, pub short_description: Option<String>, pub main_prompt: SkillResourceId, pub display_path: Option<String>, pub dependencies: Option<SkillDependencies>, pub enabled: bool, pub prompt_visible: bool,}impl SkillCatalogEntry { pub fn new( id: SkillPackageId, authority: SkillAuthority, name: impl Into<String>, description: impl Into<String>, main_prompt: SkillResourceId, ) -> Self { Self { id, authority, name: name.into(), description: description.into(), short_description: None, main_prompt, display_path: None, dependencies: None, enabled: true, prompt_visible: true, } } pub fn with_short_description(mut self, short_description: Option<String>) -> Self { self.short_description = short_description; self } pub fn with_display_path(mut self, display_path: impl Into<String>) -> Self { self.display_path = Some(display_path.into()); self } pub fn with_dependencies(mut self, dependencies: Option<SkillDependencies>) -> Self { self.dependencies = dependencies; self } pub fn disabled(mut self) -> Self { self.enabled = false; self } pub fn hidden_from_prompt(mut self) -> Self { self.prompt_visible = false; self } pub(crate) fn rendered_path(&self) -> &str { self.display_path .as_deref() .unwrap_or_else(|| self.main_prompt.as_str()) }}/// Merged catalog for one turn.#[derive(Clone, Debug, Default, PartialEq, Eq)]pub struct SkillCatalog { pub entries: Vec<SkillCatalogEntry>, pub warnings: Vec<String>,}impl SkillCatalog { pub fn extend(&mut self, other: SkillCatalog) { for entry in other.entries { self.push_entry(entry); } self.warnings.extend(other.warnings); } pub fn push_entry(&mut self, entry: SkillCatalogEntry) { if self .entries .iter() .any(|existing| existing.authority == entry.authority && existing.id == entry.id) { return; } self.entries.push(entry); }}/// Contents returned after resolving a skill resource through its owner.#[derive(Clone, Debug, PartialEq, Eq)]pub struct SkillReadResult { pub resource: SkillResourceId, pub contents: String,}/// Search results for a package whose files are not readable through ordinary/// executor filesystem access.#[derive(Clone, Debug, Default, PartialEq, Eq)]pub struct SkillSearchResult { pub matches: Vec<SkillSearchMatch>,}#[derive(Clone, Debug, PartialEq, Eq)]pub struct SkillSearchMatch { pub resource: SkillResourceId, pub title: String, pub snippet: String,}#[derive(Clone, Debug, PartialEq, Eq)]pub struct SkillProviderError { pub message: String,}impl SkillProviderError { pub fn new(message: impl Into<String>) -> Self { Self { message: message.into(), } }}impl std::fmt::Display for SkillProviderError { fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.message.fmt(formatter) }}impl std::error::Error for SkillProviderError {}pub type SkillProviderResult<T> = Result<T, SkillProviderError>;