From 53056a4f8dc27cecd6441502e98b08d16dc853c0 Mon Sep 17 00:00:00 2001 From: pash Date: Fri, 30 Jan 2026 14:01:46 -0800 Subject: [PATCH] context in headers --- codex-rs/core/src/git_info.rs | 34 ++++++++++++++++++++-- codex-rs/core/src/turn_metadata.rs | 46 +++++++++++++----------------- 2 files changed, 51 insertions(+), 29 deletions(-) diff --git a/codex-rs/core/src/git_info.rs b/codex-rs/core/src/git_info.rs index 1676a6ed85..f398e09084 100644 --- a/codex-rs/core/src/git_info.rs +++ b/codex-rs/core/src/git_info.rs @@ -125,7 +125,16 @@ pub async fn get_git_remote_urls(cwd: &Path) -> Option> /// Collect fetch remotes without checking whether `cwd` is in a git repo. pub async fn get_git_remote_urls_assume_git_repo(cwd: &Path) -> Option> { - let output = run_git_command_with_timeout(&["remote", "-v"], cwd).await?; + get_git_remote_urls_assume_git_repo_with_timeout(cwd, GIT_COMMAND_TIMEOUT).await +} + +/// Collect fetch remotes without checking whether `cwd` is in a git repo, +/// using the provided timeout. +pub async fn get_git_remote_urls_assume_git_repo_with_timeout( + cwd: &Path, + timeout_dur: TokioDuration, +) -> Option> { + let output = run_git_command_with_timeout_override(&["remote", "-v"], cwd, timeout_dur).await?; if !output.status.success() { return None; } @@ -136,7 +145,17 @@ pub async fn get_git_remote_urls_assume_git_repo(cwd: &Path) -> Option Option { - let output = run_git_command_with_timeout(&["rev-parse", "HEAD"], cwd).await?; + get_head_commit_hash_with_timeout(cwd, GIT_COMMAND_TIMEOUT).await +} + +/// Return the current HEAD commit hash without checking whether `cwd` is in a +/// git repo, using the provided timeout. +pub async fn get_head_commit_hash_with_timeout( + cwd: &Path, + timeout_dur: TokioDuration, +) -> Option { + let output = + run_git_command_with_timeout_override(&["rev-parse", "HEAD"], cwd, timeout_dur).await?; if !output.status.success() { return None; } @@ -253,10 +272,19 @@ pub async fn git_diff_to_remote(cwd: &Path) -> Option { /// Run a git command with a timeout to prevent blocking on large repositories async fn run_git_command_with_timeout(args: &[&str], cwd: &Path) -> Option { + run_git_command_with_timeout_override(args, cwd, GIT_COMMAND_TIMEOUT).await +} + +/// Run a git command with a caller-provided timeout. +async fn run_git_command_with_timeout_override( + args: &[&str], + cwd: &Path, + timeout_dur: TokioDuration, +) -> Option { let mut command = Command::new("git"); command.args(args).current_dir(cwd); command.kill_on_drop(true); - let result = timeout(GIT_COMMAND_TIMEOUT, command.output()).await; + let result = timeout(timeout_dur, command.output()).await; match result { Ok(Ok(output)) => Some(output), diff --git a/codex-rs/core/src/turn_metadata.rs b/codex-rs/core/src/turn_metadata.rs index 398b893b6d..ddab90a9c4 100644 --- a/codex-rs/core/src/turn_metadata.rs +++ b/codex-rs/core/src/turn_metadata.rs @@ -3,11 +3,10 @@ use std::path::Path; use serde::Serialize; use tokio::time::Duration as TokioDuration; -use tokio::time::timeout; -use crate::git_info::get_git_remote_urls_assume_git_repo; +use crate::git_info::get_git_remote_urls_assume_git_repo_with_timeout; use crate::git_info::get_git_repo_root; -use crate::git_info::get_head_commit_hash; +use crate::git_info::get_head_commit_hash_with_timeout; const TURN_METADATA_TIMEOUT: TokioDuration = TokioDuration::from_millis(150); @@ -31,28 +30,23 @@ struct TurnMetadata { pub(crate) async fn build_turn_metadata_header(cwd: &Path) -> Option { let repo_root = get_git_repo_root(cwd)?; - // Cap the total time we spend gathering optional metadata so turn startup - // stays responsive even when git is slow in certain environments. - timeout(TURN_METADATA_TIMEOUT, async { - let (latest_git_commit_hash, associated_remote_urls) = tokio::join!( - get_head_commit_hash(cwd), - get_git_remote_urls_assume_git_repo(cwd) - ); - if latest_git_commit_hash.is_none() && associated_remote_urls.is_none() { - return None; - } + // Keep git subprocess work bounded per command, without wrapping the + // entire metadata build in a separate timeout. + let (latest_git_commit_hash, associated_remote_urls) = tokio::join!( + get_head_commit_hash_with_timeout(cwd, TURN_METADATA_TIMEOUT), + get_git_remote_urls_assume_git_repo_with_timeout(cwd, TURN_METADATA_TIMEOUT) + ); + if latest_git_commit_hash.is_none() && associated_remote_urls.is_none() { + return None; + } - let mut workspaces = BTreeMap::new(); - workspaces.insert( - repo_root.to_string_lossy().into_owned(), - TurnMetadataWorkspace { - associated_remote_urls, - latest_git_commit_hash, - }, - ); - serde_json::to_string(&TurnMetadata { workspaces }).ok() - }) - .await - .ok() - .flatten() + let mut workspaces = BTreeMap::new(); + workspaces.insert( + repo_root.to_string_lossy().into_owned(), + TurnMetadataWorkspace { + associated_remote_urls, + latest_git_commit_hash, + }, + ); + serde_json::to_string(&TurnMetadata { workspaces }).ok() }