agcodex_core/util.rs
1use std::path::Path;
2use std::time::Duration;
3
4use rand::Rng;
5
6const INITIAL_DELAY_MS: u64 = 200;
7const BACKOFF_FACTOR: f64 = 2.0;
8
9pub(crate) fn backoff(attempt: u64) -> Duration {
10 let exp = BACKOFF_FACTOR.powi(attempt.saturating_sub(1) as i32);
11 let base = (INITIAL_DELAY_MS as f64 * exp) as u64;
12 let jitter = rand::rng().random_range(0.9..1.1);
13 Duration::from_millis((base as f64 * jitter) as u64)
14}
15
16/// Return `true` if the project folder specified by the `Config` is inside a
17/// Git repository.
18///
19/// The check walks up the directory hierarchy looking for a `.git` file or
20/// directory (note `.git` can be a file that contains a `gitdir` entry). This
21/// approach does **not** require the `git` binary or the `git2` crate and is
22/// therefore fairly lightweight.
23///
24/// Note that this does **not** detect *work‑trees* created with
25/// `git worktree add` where the checkout lives outside the main repository
26/// directory. If you need Codex to work from such a checkout simply pass the
27/// `--allow-no-git-exec` CLI flag that disables the repo requirement.
28pub fn is_inside_git_repo(base_dir: &Path) -> bool {
29 let mut dir = base_dir.to_path_buf();
30
31 loop {
32 if dir.join(".git").exists() {
33 return true;
34 }
35
36 // Pop one component (go up one directory). `pop` returns false when
37 // we have reached the filesystem root.
38 if !dir.pop() {
39 break;
40 }
41 }
42
43 false
44}