Add session delete commands in CLI and TUI (#27476)

## Summary

The app server exposes `thread/delete`, but users cannot invoke it from
the CLI or TUI. Because deletion is irreversible, the user-facing
commands need deliberate confirmation and safer handling of name-based
targets.

- Add `codex delete <SESSION>` with interactive confirmation,
restricting `--force` to UUID targets.
- Resolve exact names across active and archived sessions, including
renamed sessions, and validate prompted UUID targets before
confirmation.
- Add a `/delete` command with a confirmation popup that warns the
current session and its subagent threads will be permanently deleted.

## Manual testing

- Deleted by UUID with `--force` and verified the rollout, session-index
entry, and database row were removed.
- Exercised name-based confirmation for both cancellation and
affirmative deletion; cancellation preserved the session and
confirmation removed it.
- Verified deletion refuses to proceed without `--force`, while
`--force` rejects names, including duplicate names.
- Verified duplicate-name confirmation displays the concrete UUID
selected.
- Deleted an archived session by name.
- Verified an already-missing UUID fails before displaying a
confirmation prompt.
- Exercised `/delete` in the TUI: the popup defaults to No, cancellation
preserves the session, and confirmation deletes the session and exits.
- Verified that `codex delete` works for both archived and non-archived
sessions.
This commit is contained in:
Eric Traut
2026-06-10 18:04:02 -07:00
committed by GitHub
parent 36fc79c6f4
commit 9d87b771ce
11 changed files with 301 additions and 56 deletions
+17
View File
@@ -0,0 +1,17 @@
use predicates::prelude::*;
#[test]
fn missing_session_fails_before_delete_confirmation() -> anyhow::Result<()> {
let codex_home = tempfile::tempdir()?;
let mut cmd = assert_cmd::Command::new(codex_utils_cargo_bin::cargo_bin("codex")?);
cmd.env("CODEX_HOME", codex_home.path())
.args(["delete", "123e4567-e89b-12d3-a456-426614174000"]);
cmd.assert()
.failure()
.stderr(predicate::str::contains(
"No active or archived session found matching",
))
.stderr(predicate::str::contains("cannot confirm").not());
Ok(())
}