diff --git a/skills/release-workflow/SKILL.md b/skills/release-workflow/SKILL.md index 0f40e5a..73d3014 100644 --- a/skills/release-workflow/SKILL.md +++ b/skills/release-workflow/SKILL.md @@ -43,7 +43,7 @@ After CI completes: - Commit with `--no-gpg-sign` (avoids GPG passphrase hang in non-interactive terminals) - **Sign once.** Wait for CI to go green on the unsigned commit, **then** amend with `--gpg-sign` + force-push. Do not amend between CI runs — each amend creates a new SHA, which triggers a new CI run and leaves stale Pages deployments that block the next run. -- **Passphrase typo protection.** Run `git commit --amend --gpg-sign --no-edit` **alone first**. If the passphrase is wrong, only that command fails — the force-push, tag, and push don't run on a broken state. Verify with `git verify-commit HEAD` before proceeding with the remaining commands. +- **Split signing into two steps.** Step 1: sign the commit (`git commit --amend --gpg-sign --no-edit`). Verify success with `git verify-commit HEAD`. Step 2: only then run the remaining commands (force-push, tag, push tag). Never chain the amend with the push and tag in one paste — a passphrase typo on the amend would leave the unsigned commit on the remote after the force-push. - Normal push for fast-forward commits - `--force-with-lease` for amended commits or tag refreshes - **Start from a clean tag.** Before re-tagging, always delete the old tag locally AND remotely (`git tag -d v0.x.y && git push --delete origin v0.x.y`). If the old tag still exists, `git tag -s` will fail with "tag already exists" and you'll end up with a tag pointing to the wrong commit. diff --git a/src/main.rs b/src/main.rs index 9dbdbdf..c65219c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -373,8 +373,13 @@ fn run_disclaimer(terminal: &mut Terminal, app: &mut App) -> Resu /// Open the input dialog for the user to type a save-folder path. /// Validates the path exists and contains .sav files before accepting it. fn action_set_save_folder(terminal: &mut Terminal, app: &mut App) -> Result<()> { + let default = app.save_folder.as_ref().map(|p| p.to_string_lossy().to_string()); let mut input_state = tui::InputDialogState::new("Enter the path to your Subnautica 2 SaveGames folder:"); + if let Some(d) = default { + input_state.input = d; + input_state.cursor = input_state.input.len(); + } let mut ok_selected = true; loop { diff --git a/src/tui.rs b/src/tui.rs index fde0401..5e4e81a 100644 --- a/src/tui.rs +++ b/src/tui.rs @@ -819,10 +819,17 @@ fn draw_select_list_with_info( // If pinned_header is set, items[0] (header) and items[1] (blank spacer) // render as fixed rows above the scrollable list. items[2..] form the list. let (list_start_y, list_items_slice): (u16, &[&str]) = if pinned_header && !items.is_empty() { - let header_style = Style::default().fg(Color::Cyan).add_modifier(Modifier::BOLD); + let header_style = Style::default() + .fg(Color::Cyan) + .add_modifier(Modifier::BOLD); f.render_widget( Paragraph::new(Span::styled(items[0], header_style)), - Rect { x: area.x, y: area.y, width: area.width, height: 1 }, + Rect { + x: area.x, + y: area.y, + width: area.width, + height: 1, + }, ); // Leave items[1] (blank spacer) as visual gap — rendered as empty row (area.y + 2, &items[2..]) @@ -839,7 +846,11 @@ fn draw_select_list_with_info( // Offset: when pinned_header is true, the list widget only sees // items[2..], but state.selected() is absolute to the full items array. // Adjust the state so the list widget highlights the correct entry. - let header_offset = if pinned_header && !items.is_empty() { 2u16 } else { 0u16 }; + let header_offset = if pinned_header && !items.is_empty() { + 2u16 + } else { + 0u16 + }; let orig_selected = state.selected(); if header_offset > 0 { if let Some(s) = orig_selected {