mirror of
https://github.com/openai/codex.git
synced 2026-09-09 15:58:47 +00:00
Extract shared project root resolution helper
This commit is contained in:
@@ -25,6 +25,7 @@ use std::path::Path;
|
||||
#[cfg(windows)]
|
||||
use std::path::PathBuf;
|
||||
use toml::Value as TomlValue;
|
||||
use tracing::warn;
|
||||
|
||||
pub use codex_config::AppRequirementToml;
|
||||
pub use codex_config::AppsRequirementsToml;
|
||||
@@ -760,6 +761,31 @@ pub(crate) async fn find_project_root(
|
||||
Ok(cwd.clone())
|
||||
}
|
||||
|
||||
pub(crate) async fn resolve_project_root(
|
||||
config_layer_stack: &ConfigLayerStack,
|
||||
cwd: &AbsolutePathBuf,
|
||||
) -> io::Result<AbsolutePathBuf> {
|
||||
let mut merged = TomlValue::Table(toml::map::Map::new());
|
||||
for layer in config_layer_stack.get_layers(
|
||||
ConfigLayerStackOrdering::LowestPrecedenceFirst,
|
||||
/*include_disabled*/ false,
|
||||
) {
|
||||
if matches!(layer.name, ConfigLayerSource::Project { .. }) {
|
||||
continue;
|
||||
}
|
||||
merge_toml_values(&mut merged, &layer.config);
|
||||
}
|
||||
let project_root_markers = match project_root_markers_from_config(&merged) {
|
||||
Ok(Some(markers)) => markers,
|
||||
Ok(None) => default_project_root_markers(),
|
||||
Err(err) => {
|
||||
warn!("invalid project_root_markers: {err}");
|
||||
default_project_root_markers()
|
||||
}
|
||||
};
|
||||
find_project_root(cwd, &project_root_markers).await
|
||||
}
|
||||
|
||||
/// Return the appropriate list of layers (each with
|
||||
/// [ConfigLayerSource::Project] as the source) between `cwd` and
|
||||
/// `project_root`, inclusive. The list is ordered in _increasing_ precdence,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use std::future::Future;
|
||||
use std::sync::Arc;
|
||||
|
||||
use codex_app_server_protocol::ConfigLayerSource;
|
||||
use codex_hooks::PermissionRequestDecision;
|
||||
use codex_hooks::PermissionRequestOutcome;
|
||||
use codex_hooks::PermissionRequestRequest;
|
||||
@@ -30,17 +29,12 @@ use codex_protocol::protocol::HookStartedEvent;
|
||||
use codex_protocol::protocol::WarningEvent;
|
||||
use codex_protocol::user_input::UserInput;
|
||||
use serde_json::Value;
|
||||
use toml::Value as TomlValue;
|
||||
use tracing::warn;
|
||||
|
||||
use crate::codex::Session;
|
||||
use crate::codex::TurnContext;
|
||||
use crate::config::Config;
|
||||
use crate::config_loader::ConfigLayerStackOrdering;
|
||||
use crate::config_loader::default_project_root_markers;
|
||||
use crate::config_loader::find_project_root;
|
||||
use crate::config_loader::merge_toml_values;
|
||||
use crate::config_loader::project_root_markers_from_config;
|
||||
use crate::config_loader::resolve_project_root;
|
||||
use crate::event_mapping::parse_turn_item;
|
||||
use crate::tools::sandboxing::PermissionRequestPayload;
|
||||
|
||||
@@ -289,28 +283,12 @@ async fn apply_execpolicy_amendment_destination(
|
||||
}
|
||||
|
||||
async fn project_codex_home(config: &Config) -> std::io::Result<std::path::PathBuf> {
|
||||
let mut merged = TomlValue::Table(toml::map::Map::new());
|
||||
for layer in config.config_layer_stack.get_layers(
|
||||
ConfigLayerStackOrdering::LowestPrecedenceFirst,
|
||||
/*include_disabled*/ false,
|
||||
) {
|
||||
if matches!(layer.name, ConfigLayerSource::Project { .. }) {
|
||||
continue;
|
||||
}
|
||||
merge_toml_values(&mut merged, &layer.config);
|
||||
}
|
||||
let project_root_markers = match project_root_markers_from_config(&merged) {
|
||||
Ok(Some(markers)) => markers,
|
||||
Ok(None) => default_project_root_markers(),
|
||||
Err(err) => {
|
||||
warn!("invalid project_root_markers: {err}");
|
||||
default_project_root_markers()
|
||||
}
|
||||
};
|
||||
Ok(find_project_root(&config.cwd, &project_root_markers)
|
||||
.await?
|
||||
.join(".codex")
|
||||
.to_path_buf())
|
||||
Ok(
|
||||
resolve_project_root(&config.config_layer_stack, &config.cwd)
|
||||
.await?
|
||||
.join(".codex")
|
||||
.to_path_buf(),
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) async fn run_post_tool_use_hooks(
|
||||
|
||||
@@ -16,18 +16,13 @@
|
||||
//! 3. We do **not** walk past the project root.
|
||||
|
||||
use crate::config::Config;
|
||||
use crate::config_loader::ConfigLayerStackOrdering;
|
||||
use crate::config_loader::default_project_root_markers;
|
||||
use crate::config_loader::merge_toml_values;
|
||||
use crate::config_loader::project_root_markers_from_config;
|
||||
use codex_app_server_protocol::ConfigLayerSource;
|
||||
use crate::config_loader::resolve_project_root;
|
||||
use codex_exec_server::Environment;
|
||||
use codex_exec_server::ExecutorFileSystem;
|
||||
use codex_features::Feature;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use dunce::canonicalize as normalize_path;
|
||||
use std::io;
|
||||
use toml::Value as TomlValue;
|
||||
use tracing::error;
|
||||
|
||||
pub(crate) const HIERARCHICAL_AGENTS_MESSAGE: &str =
|
||||
@@ -226,51 +221,14 @@ pub async fn discover_project_doc_paths(
|
||||
dir = AbsolutePathBuf::try_from(canon)?;
|
||||
}
|
||||
|
||||
let mut merged = TomlValue::Table(toml::map::Map::new());
|
||||
for layer in config.config_layer_stack.get_layers(
|
||||
ConfigLayerStackOrdering::LowestPrecedenceFirst,
|
||||
/*include_disabled*/ false,
|
||||
) {
|
||||
if matches!(layer.name, ConfigLayerSource::Project { .. }) {
|
||||
continue;
|
||||
}
|
||||
merge_toml_values(&mut merged, &layer.config);
|
||||
}
|
||||
let project_root_markers = match project_root_markers_from_config(&merged) {
|
||||
Ok(Some(markers)) => markers,
|
||||
Ok(None) => default_project_root_markers(),
|
||||
Err(err) => {
|
||||
tracing::warn!("invalid project_root_markers: {err}");
|
||||
default_project_root_markers()
|
||||
}
|
||||
};
|
||||
let mut project_root = None;
|
||||
if !project_root_markers.is_empty() {
|
||||
for ancestor in dir.ancestors() {
|
||||
for marker in &project_root_markers {
|
||||
let marker_path = AbsolutePathBuf::try_from(ancestor.join(marker))?;
|
||||
let marker_exists = match fs.get_metadata(&marker_path).await {
|
||||
Ok(_) => true,
|
||||
Err(err) if err.kind() == io::ErrorKind::NotFound => false,
|
||||
Err(err) => return Err(err),
|
||||
};
|
||||
if marker_exists {
|
||||
project_root = Some(AbsolutePathBuf::try_from(ancestor.to_path_buf())?);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if project_root.is_some() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
let project_root = resolve_project_root(&config.config_layer_stack, &dir).await?;
|
||||
|
||||
let search_dirs: Vec<AbsolutePathBuf> = if let Some(root) = project_root {
|
||||
let search_dirs: Vec<AbsolutePathBuf> = if project_root != dir {
|
||||
let mut dirs = Vec::new();
|
||||
let mut cursor = dir.clone();
|
||||
loop {
|
||||
dirs.push(cursor.clone());
|
||||
if cursor == root {
|
||||
if cursor == project_root {
|
||||
break;
|
||||
}
|
||||
let Some(parent) = cursor.parent() else {
|
||||
|
||||
Reference in New Issue
Block a user