feat(delete): multi-target support with -i and --dry-run#100
Merged
feat(delete): multi-target support with -i and --dry-run#100
Conversation
Allows gw delete to accept multiple positional targets or an interactive multi-select, with best-effort batch execution, single batch confirmation, and non-zero exit on partial failure. Preserves all existing single-target behavior and flags. Explicitly out of scope: sync/merge/change-base multi-target, and clean/delete consolidation.
9 tasks: CLI surface change, delete_one extraction, plan types, summary/ confirm helpers, orchestrator + exit codes, multi-select TUI widget, integration tests, doc polish, final verification. Preserves single-target legacy behavior throughout.
Matches the summary/progress → stdout, errors/prompts → stderr convention already used by gw clean and worktree progress output. Adds the '(dry-run; nothing deleted)' trailer that the spec example calls for.
- exit_code_from uses iter::any for readability - move_cwd_out_of_targets treats canonicalize failures as skip-compare to avoid asymmetric-path mis-classification - busy-arm stderr mirror restores phrasing parity with the legacy flow (includes process count)
…flow Spec prescribes: - Nothing selected (or no worktrees) → exit 0 - Esc / q / Ctrl-C → exit 1 Replace the boolean Ok(Vec::new()) convention with an InteractiveOutcome enum (Selected / Nothing / Cancelled) and map each to the correct exit code in delete_worktrees.
3 tasks
DaveDev42
added a commit
that referenced
this pull request
Apr 23, 2026
- Drop volatile "0.0.38+" version label; link PR #100 instead. - Clarify exit `0` covers the no-eligible-worktrees case in `-i`. - Generalize the script-author guidance from "target not found" to any failure (Skipped also covers busy / remove errors).
DaveDev42
added a commit
that referenced
this pull request
Apr 23, 2026
Single-target failures now exit with code 2 instead of 1, aligning with the multi-target batch contract introduced in PR #100. Surface this in README so users pinning exit codes in scripts can find it.
DaveDev42
added a commit
that referenced
this pull request
Apr 23, 2026
- Drop volatile "0.0.38+" version label; link PR #100 instead. - Clarify exit `0` covers the no-eligible-worktrees case in `-i`. - Generalize the script-author guidance from "target not found" to any failure (Skipped also covers busy / remove errors).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Extends
gw deleteto operate on multiple worktrees in a single invocation.gw delete feat/a feat/b feat/c-i/--interactivemulti-select TUI (arrow keys + Space + Enter; Esc/q cancels)--dry-runpreview modegw delete(no args) path — still deletes the current worktree with the existing busy prompt-k,-r,-f,--no-force,-w,-b) apply to every targetSingle batch confirmation fires when the plan has >= 2 entries (TTY only); non-TTY invocations assume consent.
-iand positional targets are mutually exclusive at parse time.Exit codes
0— full success,--dry-run, or-iwith nothing selected / no feature worktrees1— user cancelled (batch promptN, or-iEsc/q/Ctrl-C)2— any target failed or was skipped (not found, busy without--force, remove error, pre-hook failure)Note: single-target failures (e.g.
gw delete <unknown>) previously exited 1 via the generic error handler. They now exit 2 under the new contract. Scripts pinning exit code 1 for "target not found" should be updated.Implementation
src/cli.rs—Commands::Delete { targets: Vec<String>, interactive, dry_run, ... }with clapconflicts_with.src/operations/worktree.rs— splitdelete_worktreeinto per-targetdelete_one+ legacy public shim. Existingclean.rscaller unchanged.src/operations/delete_batch.rs(new) — plan types (Resolved,PlanEntry,ItemResult), orchestratordelete_worktrees, summary / confirm / execute / exit-code helpers.src/tui/multi_select.rs(new) — arrow/checkbox TUI built on existing raw-mode plumbing fromarrow_select.rs(nowpub(crate)).src/error.rs— newCwError::ExitCode(i32)variant for silent propagation of the orchestrator's exit code.Test plan
cargo fmt --checkcargo clippy --all-targets -- -D warnings(zero warnings)cargo test— 605 passedtests/test_delete_multi.rs(6 scenarios: all-success, mix valid+missing → exit 2, dry-run, keep-branch on multiple,-i+ positional conflict, legacy no-args from inside worktree).github/workflows/test.yml(subagent to verify)Docs
docs/superpowers/specs/2026-04-23-delete-multiple-worktrees-design.md— design specdocs/superpowers/plans/2026-04-23-delete-multiple-worktrees.md— implementation planREADME.md— command table row updatedsrc/cli.rs—Deletevariant long_about documents behavior + exit codes