sync from monorepo @ 5408ddc3

This commit is contained in:
2026-05-09 00:05:40 +02:00
parent b03dc15371
commit 16a42d54f8
5 changed files with 191 additions and 39 deletions
+13 -7
View File
@@ -1,12 +1,14 @@
use std::path::{Path, PathBuf};
/// Markers checked in priority order when walking up from a target path.
const MARKERS: &[&str] = &["botignore.toml", ".botignore", ".git"];
/// Strong markers that definitively identify a project root.
const STRONG_MARKERS: &[&str] = &["botignore.toml", ".botignore.toml", ".git"];
/// Walk upward from `target` (or its parent if `target` is a file) looking
/// for the nearest project root. Roots are identified by the presence of
/// any marker in `MARKERS`. Walks from the **target file's location**, not
/// from cwd, because agents `cd` around.
/// for the nearest project root. Strong markers (`botignore.toml`,
/// `.botignore.toml`, `.git`) stop the walk immediately. A `.botignore`
/// file is remembered as a fallback but does not stop the walk — the search
/// continues upward for a stronger boundary. If none is found, the
/// `.botignore` location is used.
pub fn find_project_root(target: &Path) -> Option<PathBuf> {
let start = if target.is_file() {
target.parent()?
@@ -14,14 +16,18 @@ pub fn find_project_root(target: &Path) -> Option<PathBuf> {
target
};
let mut fallback: Option<PathBuf> = None;
let mut current = Some(start);
while let Some(dir) = current {
for marker in MARKERS {
for marker in STRONG_MARKERS {
if dir.join(marker).exists() {
return Some(dir.to_path_buf());
}
}
if fallback.is_none() && dir.join(".botignore").exists() {
fallback = Some(dir.to_path_buf());
}
current = dir.parent();
}
None
fallback
}