Initial public release of Warp.

Repo-Sync-Origin: warpdotdev/warp-internal@12af1d983b
This commit is contained in:
David Stern
2026-04-28 08:43:33 -05:00
commit 0dbd3d567a
4982 changed files with 1431549 additions and 0 deletions
+149
View File
@@ -0,0 +1,149 @@
use std::{
collections::HashSet,
path::{Path, PathBuf},
sync::LazyLock,
};
use ai::skills::{
home_skills_path, read_skills, ParsedSkill, SkillProvider, SKILL_PROVIDER_DEFINITIONS,
};
use anyhow::Error;
use regex::Regex;
use repo_metadata::{local_model::GetContentsArgs, RepoContent, RepoMetadataModel};
use warpui::AppContext;
use crate::warp_managed_paths_watcher::warp_managed_skill_dirs;
/// Finds all skill directories in a repository by querying the RepoMetadataModel tree.
///
/// Returns a list of paths to skill directories (e.g., `/repo/.agents/skills/`, `/repo/sub/.claude/skills/`).
pub fn find_skill_directories_in_tree(
repo_path: &Path,
repo_metadata: &RepoMetadataModel,
ctx: &AppContext,
) -> Vec<PathBuf> {
// Collect provider skills paths (e.g., ".agents/skills", ".claude/skills")
let skill_path_suffixes: Vec<&Path> = SKILL_PROVIDER_DEFINITIONS
.iter()
.map(|p| p.skills_path.as_path())
.collect();
// Filter during traversal: only collect directories that end with a skill provider path.
// The filter rejects files and non-matching directories, avoiding intermediate allocations.
let args = GetContentsArgs::default().with_filter(move |content| {
let RepoContent::Directory(dir) = content else {
return false;
};
skill_path_suffixes
.iter()
.any(|suffix| dir.path.ends_with(&suffix.to_string_lossy()))
});
let Some(id) = repo_metadata::RepositoryIdentifier::try_local(repo_path) else {
return Vec::new();
};
repo_metadata
.get_repo_contents(&id, args, ctx)
.unwrap_or_default()
.into_iter()
// Only directories should reach this iterator due to the GetContentsArgs::filter.
// Keep the File arm for exhaustive matching in case RepoContent grows new variants.
.map(|content| match content {
RepoContent::Directory(dir) => dir.path.to_local_path_lossy(),
RepoContent::File(f) => f.path.to_local_path_lossy(),
})
.collect()
}
/// Reads all skills from the given skill directories.
pub fn read_skills_from_directories(
skill_dirs: impl IntoIterator<Item = PathBuf>,
) -> Vec<ParsedSkill> {
skill_dirs
.into_iter()
.flat_map(|dir| read_skills(&dir))
.collect()
}
pub fn is_skill_file(path: &Path) -> bool {
extract_skill_parent_directory(path).is_ok()
}
static SKILL_PROVIDER_PATHS: LazyLock<HashSet<String>> = LazyLock::new(|| {
// Collect the skill provider paths from the definitions
SKILL_PROVIDER_DEFINITIONS
.iter()
.map(|p| p.skills_path.to_string_lossy().to_string())
.collect()
});
// Pattern: {prefix}/{provider_path}/{skill-name}/SKILL.md
// where provider_path is 2 parts (e.g., ".agents/skills") and skill-name is 1 part
#[cfg(not(target_os = "windows"))]
static SKILL_FILE_PATTERN: LazyLock<Regex> = LazyLock::new(|| {
Regex::new(r"(.+)/([^/]+/[^/]+)/[^/]+/SKILL\.md$")
.expect("Failed to compile skill file pattern")
});
// On windows, the path separator is \
#[cfg(target_os = "windows")]
static SKILL_FILE_PATTERN: LazyLock<Regex> = LazyLock::new(|| {
Regex::new(r"(.+)\\([^\\]+\\[^\\]+)\\[^\\]+\\SKILL\.md$")
.expect("Failed to compile skill file pattern")
});
pub fn extract_skill_parent_directory(path: &Path) -> Result<PathBuf, Error> {
let is_warp_home_skill = path
.file_name()
.and_then(|name| name.to_str())
.is_some_and(|name| name == "SKILL.md")
&& path
.parent()
.and_then(Path::parent)
.is_some_and(|parent| warp_managed_skill_dirs().iter().any(|dir| parent == dir));
if is_warp_home_skill {
return dirs::home_dir()
.ok_or_else(|| anyhow::anyhow!("Home directory not available for {}", path.display()));
}
let path_str = path.to_string_lossy();
if let Some(captures) = SKILL_FILE_PATTERN.captures(&path_str) {
if let Some(provider_path) = captures.get(2) {
if SKILL_PROVIDER_PATHS.contains(provider_path.as_str()) {
if let Some(parent_directory) = captures.get(1) {
return Ok(PathBuf::from(parent_directory.as_str()));
}
}
}
}
Err(anyhow::anyhow!("Not a skill path: {}", path.display()))
}
/// Check if this path is a skill directory under a home directory provider path
/// E.g. ~/.agents/skills/skill-name
pub fn is_home_skill_directory(path: &Path) -> bool {
let parent_directory = path.parent();
if let Some(parent_directory) = parent_directory {
is_home_provider_path(parent_directory)
} else {
false
}
}
/// Check if this path is a home directory provider path
/// E.g. ~/.agents/skills
pub fn is_home_provider_path(path: &Path) -> bool {
SKILL_PROVIDER_DEFINITIONS.iter().any(|provider| {
if provider.provider == SkillProvider::Warp {
return warp_managed_skill_dirs().iter().any(|dir| path == dir);
}
home_skills_path(provider.provider)
.as_ref()
.is_some_and(|home_skills_path| path == home_skills_path)
})
}
#[cfg(test)]
#[path = "utils_tests.rs"]
mod tests;