Skip to content

fix(cli): make post-upgrade cleanup confirmation sticky, no silent override#95

Merged
dipto0321 merged 1 commit into
mainfrom
fix/cli/cleanup-double-prompt
Jul 3, 2026
Merged

fix(cli): make post-upgrade cleanup confirmation sticky, no silent override#95
dipto0321 merged 1 commit into
mainfrom
fix/cli/cleanup-double-prompt

Conversation

@dipto0321

Copy link
Copy Markdown
Owner

Summary

The post-upgrade cleanup step's "delete all" confirmation is no longer silently overridden by an unprompted per-version re-confirmation. Pre-fix, a user who answered y at the all-or-nothing prompt saw nothing deleted if their terminal session's input stream ended before they re-answered for every candidate — the per-version loop fired unconditionally for every version in toOffer (because cfg.PerVersion defaults to true from cfg.Cleanup.Prompt's config default), the default: branch of promptPerVersion returned false for empty / non-y input, and every version landed in result.Skipped with no visible error.

User-reported live: answered y at the cleanup prompt during a real nodeup upgrade, then fnm list afterward still showed the old versions — no deletion occurred, with no surface indication of why.

This PR makes confirmation "sticky" at the level the user chose to operate at:

  1. decision.deleteAlly / yes at the all-or-nothing prompt.
  2. decision.deleteOne — a specific version typed at the all-or-nothing prompt (the user's choice IS the per-version confirmation).
  3. AutoDeleteAll (without ForcePerVersion) — set by --cleanup, --yes, or cfg.Cleanup.Auto. The user's pre-flight opt-in counts; the per-version prompt is redundant.

Fix: in runCleanupPrompt Step 4, set cfg.PerVersion = false for the per-version loop once a higher-level confirmation has been recorded. The ForcePerVersion downgrade from #58 is the only path that keeps cfg.PerVersion = true after Step 1b, because it represents an inability to safely exclude the active version from the candidate set — when Manager.Current() errors, we can't be sure which version is powering the user's shell, so we fall back to per-version y/N to avoid mass-deletion. All three TestCleanupPrompt_ForcePerVersion* tests confirm this preservation.

Linked issues

Closes #76

Type of change

  • fix — bug fix (PATCH bump)
  • feat — new feature (MINOR bump)
  • refactor — no behavior change
  • perf — performance improvement
  • docs — documentation only
  • test — tests only
  • chore — maintenance / dependency bump
  • ci — CI/CD only
  • build — build system only
  • Breaking change (MAJOR bump) — explain below

Checklist

  • Title follows Conventional Commits (feat(scope): subject)
  • I ran make ci locally and it passes (Go-side tidy/fmt/vet/lint/test all green)
  • I added or updated tests for the change (TestCleanupPrompt_DeleteAllSkipsPerVersionPrompt is the explicit regression test for bug(cli): cleanup double-prompts — confirming 'delete all' still requires a second per-version 'y', silently skips if missed #76; TestCleanupPrompt_PerVersionConfirm and TestCleanupPrompt_SpecificVersion updated to assert the new correct behavior; TestCleanupPrompt_AutoDeleteAll and TestCleanupPrompt_PrefilteredOnly continue to pass unchanged because their input streams already provided extra y\ns)
  • I updated relevant docs (CHANGELOG.md, inline comment block in runCleanupPrompt Step 4 explains the "sticky-up" semantics and the ForcePerVersion exception)
  • No new linter warnings (make lint green)
  • If breaking: I documented the migration path in the PR body and updated CHANGELOG.md

Screenshots / output

Pre-fix:

$ nodeup upgrade
# (after upgrade succeeds, cleanup prompt fires)
Old Node.js versions still on disk (2):
  v18.20.4
  v20.18.0

What would you like to do?
  y       Delete all of the above
  <num>   Delete one specific version (e.g. 22.11.0)
  N       Skip cleanup
# user types: y

Delete v18.20.4? [y/N]   <-- second, separate prompt; user's terminal session ended here
Delete v20.18.0? [y/N]   <-- never reached, no input available

Upgrade complete!
# (no Deletion: line, no error — fnm list still shows both old versions)

Post-fix:

$ nodeup upgrade
# (same prompt fires)
Old Node.js versions still on disk (2):
  v18.20.4
  v20.18.0

What would you like to do?
  y       Delete all of the above
  <num>   Delete one specific version (e.g. 22.11.0)
  N       Skip cleanup
# user types: y

  Deleted v18.20.4
  Deleted v20.18.0

Upgrade complete!  Deleted: v18.20.4, v20.18.0

--cleanup (no per-version prompt, even with cleanup.prompt: true in config):

$ nodeup upgrade --cleanup
# (no all-or-nothing prompt — AutoDeleteAll skips it)
  Deleted v18.20.4
  Deleted v20.18.0

--cleanup-version 18.20.0 (no all-or-nothing prompt, no per-version prompt):

$ nodeup upgrade --cleanup-version 18.20.0
  Deleted v18.20.0

Why this isn't breaking

The new behavior is strictly more permissive: any user who set cfg.Cleanup.Prompt: false already had per-version prompts off (no change). Users with cleanup.prompt: true who want to delete all will now succeed with one y instead of needing y once per candidate. Users who want to keep the per-version safety net can keep using --no/n at the all-or-nothing prompt to skip cleanup entirely, or --cleanup-version <v> to pick specific versions. The only path that still asks for per-version confirmation is the ForcePerVersion downgrade from #58, which is set when Manager.Current() errors — a real safety mechanism that protects against accidentally deleting the version that's currently powering the user's shell.

Files touched

  • internal/cli/cleanup.go
    • Step 4 of runCleanupPrompt adds a single block before the per-version loop: if !cfg.ForcePerVersion { cfg.PerVersion = false }. This makes the higher-level confirmation sticky. ForcePerVersion (set by upgrade.go when Manager.Current() errors) explicitly overrides this in Step 1b by setting cfg.PerVersion = true, so the ForcePerVersion safety net from bug(cli): Current() failure leaves the active Node version unprotected from cleanup deletion #58 still works.
    • Drops the dead confirm variable from the previous Step 4 (it was assigned but never read).
    • Inline comment block explains the "sticky-up" semantics and the ForcePerVersion exception.
  • internal/cli/cleanup_test.go
    • TestCleanupPrompt_PerVersionConfirm: rewritten. Was: cfg.PerVersion: true + "y\ny\nn\n" → 1 deleted, 1 skipped (pinned the bug). Now: same config + "y\n" → 2 deleted (the new correct behavior). Comment explains why.
    • TestCleanupPrompt_SpecificVersion: rewritten. Was: cfg.PerVersion: false. Now: cfg.PerVersion: true + "20.18.0\n" → 1 deleted, the explicit pick is its own confirmation. The test now also pins the "specific-version pick is sticky" behavior.
    • TestCleanupPrompt_DeleteAllSkipsPerVersionPrompt: new. The explicit regression test for bug(cli): cleanup double-prompts — confirming 'delete all' still requires a second per-version 'y', silently skips if missed #76 — two candidates, only y\n supplied, both must be deleted and no "Delete v" prompt may appear in the output.
    • TestCleanupPrompt_AutoDeleteAll, TestCleanupPrompt_PrefilteredOnly, TestCleanupPrompt_NoSkips, all TestCleanupPrompt_ForcePerVersion*: unchanged and still green. They prove that the fix doesn't accidentally re-prompt under --cleanup, --cleanup-version, n, or ForcePerVersion.
  • CHANGELOG.md### Fixed entry under [Unreleased] documenting the sticky-confirmation semantics + the three higher-level confirmation classes + the ForcePerVersion exception. References bug(cli): cleanup double-prompts — confirming 'delete all' still requires a second per-version 'y', silently skips if missed #76.

…erride

Closes #76

Pre-fix, a user who answered `y` at the all-or-nothing cleanup
prompt ("What would you like to do?") saw nothing deleted if
their terminal session's input stream ended before they
re-answered for every candidate — the per-version loop fired
unconditionally for every version in `toOffer` because
`cfg.PerVersion` defaults to `true` from `cfg.Cleanup.Prompt`'s
config default, the `default:` branch of `promptPerVersion`
returned `false` for empty / non-`y` input, and every version
landed in `result.Skipped` with no visible error. User reported
live: answered `y` at the cleanup prompt during a real `nodeup
upgrade`, then `fnm list` afterward still showed the old
versions — no deletion occurred, with no surface indication of
why.

Fix: confirmation is now sticky at the level the user chose to
operate at. Three classes of higher-level confirmation set
`cfg.PerVersion = false` for the per-version loop:

1. `decision.deleteAll` — `y`/`yes` at the all-or-nothing prompt.
2. `decision.deleteOne` — a specific version typed at the
   all-or-nothing prompt (the user's choice IS the per-version
   confirmation).
3. `AutoDeleteAll` (without `ForcePerVersion`) — set by
   `--cleanup`, `--yes`, or `cfg.Cleanup.Auto`. The user's
   pre-flight opt-in counts; the per-version prompt is redundant.

The `ForcePerVersion` downgrade from #58 is the only path that
keeps `cfg.PerVersion = true` after Step 1b, because it
represents an inability to safely exclude the active version
from the candidate set — when `Manager.Current()` errors, we
fall back to per-version y/N to avoid mass-deletion. All three
`TestCleanupPrompt_ForcePerVersion*` tests confirm this
preservation.

`TestCleanupPrompt_PerVersionConfirm` and
`TestCleanupPrompt_SpecificVersion` (the tests that pinned the
buggy double-prompt behavior) are rewritten to assert the new
correct behavior. `TestCleanupPrompt_DeleteAllSkipsPerVersionPrompt`
is the explicit regression test for #76 — two candidates, only
`y\n` supplied, both must be deleted and no "Delete v" prompt
may appear in the output.

CHANGELOG: ### Fixed entry under [Unreleased].

Co-Authored-By: puku-ai-2.8 <noreply@puku.sh>
@cocogitto-bot

cocogitto-bot Bot commented Jul 3, 2026

Copy link
Copy Markdown

✔️ 73bfce2 - Conventional commits check succeeded.

@dipto0321 dipto0321 merged commit 0da573f into main Jul 3, 2026
10 checks passed
@dipto0321 dipto0321 deleted the fix/cli/cleanup-double-prompt branch July 3, 2026 05:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(cli): cleanup double-prompts — confirming 'delete all' still requires a second per-version 'y', silently skips if missed

1 participant