diff --git a/codex-rs/Cargo.lock b/codex-rs/Cargo.lock index f6f0e5583..f35402efd 100644 --- a/codex-rs/Cargo.lock +++ b/codex-rs/Cargo.lock @@ -2809,6 +2809,7 @@ dependencies = [ "codex-utils-plugins", "dirs", "dunce", + "futures", "pretty_assertions", "serde", "serde_json", diff --git a/codex-rs/core-skills/Cargo.toml b/codex-rs/core-skills/Cargo.toml index 7748540ac..3ac82be9a 100644 --- a/codex-rs/core-skills/Cargo.toml +++ b/codex-rs/core-skills/Cargo.toml @@ -31,6 +31,7 @@ codex-utils-path-uri = { workspace = true } codex-utils-plugins = { workspace = true } dirs = { workspace = true } dunce = { workspace = true } +futures = { workspace = true } serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } serde_yaml = { workspace = true } diff --git a/codex-rs/core-skills/src/loader.rs b/codex-rs/core-skills/src/loader.rs index aa9688f9a..b377e909e 100644 --- a/codex-rs/core-skills/src/loader.rs +++ b/codex-rs/core-skills/src/loader.rs @@ -22,6 +22,7 @@ use codex_utils_path_uri::PathUri; use codex_utils_plugins::PluginSkillRoot; use codex_utils_plugins::plugin_namespace_for_skill_path; use dirs::home_dir; +use futures::future::join_all; use serde::Deserialize; use std::collections::HashSet; use std::collections::VecDeque; @@ -534,15 +535,29 @@ async fn discover_skills_under_root( } }; - for entry in entries { - let file_name = entry.file_name; - if file_name.starts_with('.') { - continue; - } + let paths = entries + .into_iter() + .filter_map(|entry| { + let file_name = entry.file_name; + if file_name.starts_with('.') { + return None; + } + let path = dir.join(&file_name); + let path_uri = PathUri::from_abs_path(&path); + Some((file_name, path, path_uri)) + }) + .collect::>(); + let metadata_results = join_all( + paths + .iter() + .map(|(_, _, path_uri)| fs.get_metadata(path_uri, /*sandbox*/ None)), + ) + .await; - let path = dir.join(&file_name); - let path_uri = PathUri::from_abs_path(&path); - let metadata = match fs.get_metadata(&path_uri, /*sandbox*/ None).await { + for ((file_name, path, path_uri), metadata_result) in + paths.into_iter().zip(metadata_results) + { + let metadata = match metadata_result { Ok(metadata) => metadata, Err(e) => { error!("failed to stat skills path {}: {e:#}", path.display());