Made codex exec resume --last consistent with codex resume --last (#9352)

PR #9245 made `codex resume --last` honor cwd, but I forgot to make the
same change for `codex exec resume --last`. This PR fixes the
inconsistency.

This addresses #8700
This commit is contained in:
Eric Traut 2026-01-16 08:53:47 -08:00 committed by GitHub
parent 131590066e
commit 9147df0e60
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 97 additions and 4 deletions

View file

@ -119,6 +119,10 @@ pub struct ResumeArgs {
#[arg(long = "last", default_value_t = false)]
pub last: bool,
/// Show all sessions (disables cwd filtering).
#[arg(long = "all", default_value_t = false)]
pub all: bool,
/// Optional image(s) to attach to the prompt sent after resuming.
#[arg(
long = "image",

View file

@ -507,17 +507,21 @@ async fn resolve_resume_path(
) -> anyhow::Result<Option<PathBuf>> {
if args.last {
let default_provider_filter = vec![config.model_provider_id.clone()];
match codex_core::RolloutRecorder::list_threads(
let filter_cwd = if args.all {
None
} else {
Some(config.cwd.as_path())
};
match codex_core::RolloutRecorder::find_latest_thread_path(
&config.codex_home,
1,
None,
&[],
Some(default_provider_filter.as_slice()),
&config.model_provider_id,
filter_cwd,
)
.await
{
Ok(page) => Ok(page.items.first().map(|it| it.path.clone())),
Ok(path) => Ok(path),
Err(e) => {
error!("Error listing threads: {e}");
Ok(None)

View file

@ -5,6 +5,7 @@ use core_test_support::test_codex_exec::test_codex_exec;
use pretty_assertions::assert_eq;
use serde_json::Value;
use std::string::ToString;
use tempfile::TempDir;
use uuid::Uuid;
use walkdir::WalkDir;
@ -219,6 +220,90 @@ fn exec_resume_last_accepts_prompt_after_flag_in_json_mode() -> anyhow::Result<(
Ok(())
}
#[test]
fn exec_resume_last_respects_cwd_filter_and_all_flag() -> anyhow::Result<()> {
let test = test_codex_exec();
let fixture = exec_fixture()?;
let dir_a = TempDir::new()?;
let dir_b = TempDir::new()?;
let marker_a = format!("resume-cwd-a-{}", Uuid::new_v4());
let prompt_a = format!("echo {marker_a}");
test.cmd()
.env("CODEX_RS_SSE_FIXTURE", &fixture)
.env("OPENAI_BASE_URL", "http://unused.local")
.arg("--skip-git-repo-check")
.arg("-C")
.arg(dir_a.path())
.arg(&prompt_a)
.assert()
.success();
let marker_b = format!("resume-cwd-b-{}", Uuid::new_v4());
let prompt_b = format!("echo {marker_b}");
test.cmd()
.env("CODEX_RS_SSE_FIXTURE", &fixture)
.env("OPENAI_BASE_URL", "http://unused.local")
.arg("--skip-git-repo-check")
.arg("-C")
.arg(dir_b.path())
.arg(&prompt_b)
.assert()
.success();
let sessions_dir = test.home_path().join("sessions");
let path_a = find_session_file_containing_marker(&sessions_dir, &marker_a)
.expect("no session file found for marker_a");
let path_b = find_session_file_containing_marker(&sessions_dir, &marker_b)
.expect("no session file found for marker_b");
let marker_b2 = format!("resume-cwd-b-2-{}", Uuid::new_v4());
let prompt_b2 = format!("echo {marker_b2}");
test.cmd()
.env("CODEX_RS_SSE_FIXTURE", &fixture)
.env("OPENAI_BASE_URL", "http://unused.local")
.arg("--skip-git-repo-check")
.arg("-C")
.arg(dir_a.path())
.arg("resume")
.arg("--last")
.arg("--all")
.arg(&prompt_b2)
.assert()
.success();
let resumed_path_all = find_session_file_containing_marker(&sessions_dir, &marker_b2)
.expect("no resumed session file containing marker_b2");
assert_eq!(
resumed_path_all, path_b,
"resume --last --all should pick newest session"
);
let marker_a2 = format!("resume-cwd-a-2-{}", Uuid::new_v4());
let prompt_a2 = format!("echo {marker_a2}");
test.cmd()
.env("CODEX_RS_SSE_FIXTURE", &fixture)
.env("OPENAI_BASE_URL", "http://unused.local")
.arg("--skip-git-repo-check")
.arg("-C")
.arg(dir_a.path())
.arg("resume")
.arg("--last")
.arg(&prompt_a2)
.assert()
.success();
let resumed_path_cwd = find_session_file_containing_marker(&sessions_dir, &marker_a2)
.expect("no resumed session file containing marker_a2");
assert_eq!(
resumed_path_cwd, path_a,
"resume --last should prefer sessions from the same cwd"
);
Ok(())
}
#[test]
fn exec_resume_accepts_global_flags_after_subcommand() -> anyhow::Result<()> {
let test = test_codex_exec();