mirror of
https://github.com/openai/codex.git
synced 2026-02-01 22:47:52 +00:00
Fix resume --last with --json option (#9475)
Fix resume --last prompt parsing by dropping the clap conflict on the codex resume subcommand so a positional prompt is accepted when --last is set. This aligns interactive resume behavior with exec-mode logic and avoids the “--last cannot be used with SESSION_ID” error. This addresses #6717
This commit is contained in:
@@ -147,7 +147,7 @@ struct ResumeCommand {
|
||||
session_id: Option<String>,
|
||||
|
||||
/// Continue the most recent session without showing the picker.
|
||||
#[arg(long = "last", default_value_t = false, conflicts_with = "session_id")]
|
||||
#[arg(long = "last", default_value_t = false)]
|
||||
last: bool,
|
||||
|
||||
/// Show all sessions (disables cwd filtering and shows CWD column).
|
||||
@@ -932,6 +932,24 @@ mod tests {
|
||||
finalize_fork_interactive(interactive, root_overrides, session_id, last, all, fork_cli)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exec_resume_last_accepts_prompt_positional() {
|
||||
let cli =
|
||||
MultitoolCli::try_parse_from(["codex", "exec", "--json", "resume", "--last", "2+2"])
|
||||
.expect("parse should succeed");
|
||||
|
||||
let Some(Subcommand::Exec(exec)) = cli.subcommand else {
|
||||
panic!("expected exec subcommand");
|
||||
};
|
||||
let Some(codex_exec::Command::Resume(args)) = exec.command else {
|
||||
panic!("expected exec resume");
|
||||
};
|
||||
|
||||
assert!(args.last);
|
||||
assert_eq!(args.session_id, None);
|
||||
assert_eq!(args.prompt.as_deref(), Some("2+2"));
|
||||
}
|
||||
|
||||
fn app_server_from_args(args: &[&str]) -> AppServerCommand {
|
||||
let cli = MultitoolCli::try_parse_from(args).expect("parse");
|
||||
let Subcommand::AppServer(app_server) = cli.subcommand.expect("app-server present") else {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use clap::Args;
|
||||
use clap::FromArgMatches;
|
||||
use clap::Parser;
|
||||
use clap::ValueEnum;
|
||||
use codex_common::CliConfigOverrides;
|
||||
@@ -108,20 +110,22 @@ pub enum Command {
|
||||
Review(ReviewArgs),
|
||||
}
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
pub struct ResumeArgs {
|
||||
#[derive(Args, Debug)]
|
||||
struct ResumeArgsRaw {
|
||||
// Note: This is the direct clap shape. We reinterpret the positional when --last is set
|
||||
// so "codex resume --last <prompt>" treats the positional as a prompt, not a session id.
|
||||
/// Conversation/session id (UUID). When provided, resumes this session.
|
||||
/// If omitted, use --last to pick the most recent recorded session.
|
||||
#[arg(value_name = "SESSION_ID")]
|
||||
pub session_id: Option<String>,
|
||||
session_id: Option<String>,
|
||||
|
||||
/// Resume the most recent recorded session (newest) without specifying an id.
|
||||
#[arg(long = "last", default_value_t = false)]
|
||||
pub last: bool,
|
||||
last: bool,
|
||||
|
||||
/// Show all sessions (disables cwd filtering).
|
||||
#[arg(long = "all", default_value_t = false)]
|
||||
pub all: bool,
|
||||
all: bool,
|
||||
|
||||
/// Optional image(s) to attach to the prompt sent after resuming.
|
||||
#[arg(
|
||||
@@ -131,13 +135,72 @@ pub struct ResumeArgs {
|
||||
value_delimiter = ',',
|
||||
num_args = 1
|
||||
)]
|
||||
pub images: Vec<PathBuf>,
|
||||
images: Vec<PathBuf>,
|
||||
|
||||
/// Prompt to send after resuming the session. If `-` is used, read from stdin.
|
||||
#[arg(value_name = "PROMPT", value_hint = clap::ValueHint::Other)]
|
||||
prompt: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ResumeArgs {
|
||||
/// Conversation/session id (UUID). When provided, resumes this session.
|
||||
/// If omitted, use --last to pick the most recent recorded session.
|
||||
pub session_id: Option<String>,
|
||||
|
||||
/// Resume the most recent recorded session (newest) without specifying an id.
|
||||
pub last: bool,
|
||||
|
||||
/// Show all sessions (disables cwd filtering).
|
||||
pub all: bool,
|
||||
|
||||
/// Optional image(s) to attach to the prompt sent after resuming.
|
||||
pub images: Vec<PathBuf>,
|
||||
|
||||
/// Prompt to send after resuming the session. If `-` is used, read from stdin.
|
||||
pub prompt: Option<String>,
|
||||
}
|
||||
|
||||
impl From<ResumeArgsRaw> for ResumeArgs {
|
||||
fn from(raw: ResumeArgsRaw) -> Self {
|
||||
// When --last is used without an explicit prompt, treat the positional as the prompt
|
||||
// (clap can’t express this conditional positional meaning cleanly).
|
||||
let (session_id, prompt) = if raw.last && raw.prompt.is_none() {
|
||||
(None, raw.session_id)
|
||||
} else {
|
||||
(raw.session_id, raw.prompt)
|
||||
};
|
||||
Self {
|
||||
session_id,
|
||||
last: raw.last,
|
||||
all: raw.all,
|
||||
images: raw.images,
|
||||
prompt,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Args for ResumeArgs {
|
||||
fn augment_args(cmd: clap::Command) -> clap::Command {
|
||||
ResumeArgsRaw::augment_args(cmd)
|
||||
}
|
||||
|
||||
fn augment_args_for_update(cmd: clap::Command) -> clap::Command {
|
||||
ResumeArgsRaw::augment_args_for_update(cmd)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromArgMatches for ResumeArgs {
|
||||
fn from_arg_matches(matches: &clap::ArgMatches) -> Result<Self, clap::Error> {
|
||||
ResumeArgsRaw::from_arg_matches(matches).map(Self::from)
|
||||
}
|
||||
|
||||
fn update_from_arg_matches(&mut self, matches: &clap::ArgMatches) -> Result<(), clap::Error> {
|
||||
*self = ResumeArgsRaw::from_arg_matches(matches).map(Self::from)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
pub struct ReviewArgs {
|
||||
/// Review staged, unstaged, and untracked changes.
|
||||
|
||||
Reference in New Issue
Block a user