From d032036542e3a3f8d87913fb07816884199c4984 Mon Sep 17 00:00:00 2001 From: Miguel Palhas Date: Mon, 31 Aug 2026 08:42:00 +0100 Subject: [PATCH] feat(maestro): move worktree choice behind advanced options The worktree step ("+ new" plus the repository's existing worktrees) now lives inside the collapsed "Advanced options" section in both the web form and the TUI draft pane, so a plain spawn is command, project, name. Co-Authored-By: Claude Opus 5 (1M context) --- crates/maestro-tui/src/draft.rs | 125 ++++++++++++++++++-------------- web/src/spawnForm.ts | 8 +- web/src/worktreeStep.test.ts | 10 +++ 3 files changed, 84 insertions(+), 59 deletions(-) diff --git a/crates/maestro-tui/src/draft.rs b/crates/maestro-tui/src/draft.rs index 2df7d33..94eb770 100644 --- a/crates/maestro-tui/src/draft.rs +++ b/crates/maestro-tui/src/draft.rs @@ -699,12 +699,13 @@ impl DraftPane { order.push(DraftField::DirPicker); if self.cwd_raw_visible { order.push(DraftField::CwdRaw); - } else if self.selected_group_key.is_some() { - order.push(DraftField::WorktreeChoice); } order.push(DraftField::Name); order.push(DraftField::Advanced); if !self.advanced_collapsed { + if !self.cwd_raw_visible && self.selected_group_key.is_some() { + order.push(DraftField::WorktreeChoice); + } order.push(DraftField::WorktreeToggle); if self.worktree_body_visible() { order.push(DraftField::BranchMode); @@ -1082,14 +1083,13 @@ impl DraftPane { let show_custom = self.is_custom(); let show_raw = self.cwd_raw_visible; - // The worktree toggle and its body stay behind the "Advanced options" - // disclosure (#93): collapsed hides both, regardless of what they'd - // otherwise show. The worktree *choice* step is not part of that — - // it belongs to the directory picker (#95 rule 3), so it stays - // visible once a project is picked. + // The worktree choice step, the worktree toggle and its body all stay + // behind the "Advanced options" disclosure (#93): collapsed hides + // them, regardless of what they'd otherwise show. let show_wt_toggle = !self.advanced_collapsed; let show_wt_body = show_wt_toggle && self.worktree_body_visible(); - let show_wt_choice = self.selected_group_key.is_some() && !show_raw; + let show_wt_choice = + !self.advanced_collapsed && self.selected_group_key.is_some() && !show_raw; let wt_choice_rows_data = if show_wt_choice { self.worktree_choice_rows() } else { @@ -1118,11 +1118,12 @@ impl DraftPane { constraints.push(Constraint::Length(list_capacity as u16)); if show_raw { constraints.push(Constraint::Length(1)); - } else if show_wt_choice { - constraints.push(Constraint::Length(wt_choice_capacity)); } constraints.push(Constraint::Length(1)); // name constraints.push(Constraint::Length(1)); // advanced header + if show_wt_choice { + constraints.push(Constraint::Length(wt_choice_capacity)); + } if show_wt_toggle { constraints.push(Constraint::Length(1)); // worktree toggle } @@ -1268,7 +1269,52 @@ impl DraftPane { if self.focused_field == DraftField::CwdRaw { cursor = Some((col, row.y)); } - } else if show_wt_choice { + } + + // -- name + reroll --------------------------------------------------------- + let name_row = next_row(); + draw_gutter(f, name_row, "name:"); + let col = draw_text_field(f, &self.name, name_row, field_style(DraftField::Name)); + if self.focused_field == DraftField::Name { + cursor = Some((col, name_row.y)); + } + // Dim reroll hint, tucked after the typed name without covering it. + let hint_offset = (GUTTER as u16 + self.name.value().chars().count() as u16 + 1) + .min(name_row.width.saturating_sub(10)); + f.render_widget( + Paragraph::new(Line::from(Span::styled( + "^R reroll", + Style::default().add_modifier(Modifier::DIM), + ))), + Rect { + x: name_row.x + hint_offset, + y: name_row.y, + width: name_row.width.saturating_sub(hint_offset), + height: 1, + }, + ); + + // -- advanced disclosure (#93) ------------------------------------------ + let advanced_row = next_row(); + f.render_widget( + Paragraph::new(Line::from(vec![ + Span::raw(format!("{: -
Name
@@ -158,6 +154,10 @@ export function createSpawnForm(opts: SpawnFormOptions): SpawnFormHandle {