Prompt to unarchive sessions before resuming or forking (#39640)

## Why

Starting an archived session with `codex resume` or `codex fork` stopped with
guidance to run a separate `codex unarchive` command first.

## What changed

- Detect archived-session startup failures and offer to unarchive and retry the
  requested operation.
- Allow the user to cancel without modifying the archived session.
- Render the confirmation in the alternate screen when available and preserve
  inline terminal context when `--no-alt-screen` is set.
- Preserve `--no-alt-screen` whether it appears before or after the `resume` or
  `fork` subcommand.

## Testing

- Cover confirmation, cancellation, retry behavior, and unrelated startup
  failures for both resume and fork.
- Add prompt interaction and terminal rendering coverage, including narrow and
  inline viewports.

GitOrigin-RevId: 382cdbd15b5d12c091e554d6d3a2f9b3589654f4
This commit is contained in:
Jeremy Rose
2026-08-20 00:04:26 +00:00
committed by copyberry
parent fdc23b93b8
commit d944ce83a2
11 changed files with 736 additions and 57 deletions

View File

@@ -2795,6 +2795,7 @@ fn merge_interactive_cli_flags(interactive: &mut TuiCli, subcommand_cli: TuiCli)
strict_config,
approval_policy,
web_search,
no_alt_screen,
prompt,
mut config_overrides,
..
@@ -2814,6 +2815,7 @@ fn merge_interactive_cli_flags(interactive: &mut TuiCli, subcommand_cli: TuiCli)
if web_search {
interactive.web_search = true;
}
interactive.no_alt_screen |= no_alt_screen;
if strict_config {
interactive.strict_config = true;
}
@@ -3772,6 +3774,18 @@ mod tests {
assert_eq!(interactive.resume_session_id, None);
}
#[test]
fn resume_and_fork_preserve_no_alt_screen() {
for (command, finalize) in [
("resume", finalize_resume_from_args as fn(&[&str]) -> TuiCli),
("fork", finalize_fork_from_args as fn(&[&str]) -> TuiCli),
] {
assert!(finalize(&["codex", command, "--no-alt-screen"]).no_alt_screen);
assert!(finalize(&["codex", "--no-alt-screen", command]).no_alt_screen);
assert!(!finalize(&["codex", command]).no_alt_screen);
}
}
#[test]
fn resume_picker_logic_none_and_not_last() {
let interactive = finalize_resume_from_args(["codex", "resume"].as_ref());