dynamo_bench/coding/codex/
discovery.rs1use crate::coding::common::{dedupe_paths, expand_user_path, home_dir};
5use anyhow::{Result, bail};
6use std::fs;
7use std::path::{Path, PathBuf};
8
9pub fn codex_home() -> Option<PathBuf> {
11 match std::env::var_os("CODEX_HOME") {
12 Some(home) if !home.is_empty() => Some(PathBuf::from(home)),
13 _ => home_dir().map(|home| home.join(".codex")),
14 }
15}
16
17pub fn discover_rollout_files(explicit_inputs: &[String]) -> Result<Vec<PathBuf>> {
22 if explicit_inputs.is_empty() {
23 let Some(codex_home) = codex_home() else {
24 bail!("could not resolve CODEX_HOME or HOME for Codex rollout discovery");
25 };
26 let mut discovered = scan_rollout_dir(&codex_home.join("sessions"))?;
27 discovered.extend(scan_rollout_dir(&codex_home.join("archived_sessions"))?);
28 return Ok(discovered);
29 }
30
31 let mut discovered = Vec::new();
32 for raw_path in explicit_inputs {
33 let input_path = expand_user_path(raw_path);
34 if input_path.is_file() {
35 if !is_rollout_path(&input_path) {
36 bail!("not a Codex rollout file: {}", input_path.display());
37 }
38 discovered.push(input_path);
39 continue;
40 }
41 if !input_path.is_dir() {
42 bail!("input path does not exist: {}", input_path.display());
43 }
44 let hits = scan_rollout_dir(&input_path)?;
45 if hits.is_empty() {
46 bail!(
47 "no Codex rollout files found under {}",
48 input_path.display()
49 );
50 }
51 discovered.extend(hits);
52 }
53 Ok(dedupe_paths(discovered))
54}
55
56fn scan_rollout_dir(root: &Path) -> Result<Vec<PathBuf>> {
57 if !root.exists() {
58 return Ok(Vec::new());
59 }
60 let mut pending = vec![root.to_path_buf()];
61 let mut discovered = Vec::new();
62 while let Some(directory) = pending.pop() {
63 for entry in fs::read_dir(&directory)? {
64 let entry = entry?;
65 let path = entry.path();
66 if entry.file_type()?.is_dir() {
67 pending.push(path);
68 } else if is_rollout_path(&path) {
69 discovered.push(path);
70 }
71 }
72 }
73 discovered.sort();
74 Ok(discovered)
75}
76
77fn is_rollout_path(path: &Path) -> bool {
78 let Some(name) = path.file_name().and_then(|name| name.to_str()) else {
79 return false;
80 };
81 name.starts_with("rollout-") && name.ends_with(".jsonl")
82}
83
84#[cfg(test)]
85mod tests {
86 use super::discover_rollout_files;
87 use std::fs;
88 use tempfile::TempDir;
89
90 #[test]
91 fn discovers_nested_rollouts_and_rejects_other_files() {
92 let temp = TempDir::new().unwrap();
93 let day = temp.path().join("2026").join("09").join("30");
94 fs::create_dir_all(&day).unwrap();
95 fs::write(day.join("rollout-a.jsonl"), "").unwrap();
96 fs::write(day.join("notes.jsonl"), "").unwrap();
97
98 let found = discover_rollout_files(&[temp.path().display().to_string()]).unwrap();
99 assert_eq!(found, [day.join("rollout-a.jsonl").canonicalize().unwrap()]);
100 assert!(discover_rollout_files(&[day.join("notes.jsonl").display().to_string()]).is_err());
101 }
102}