Describe the bug
Confirming deletion at the post-upgrade cleanup's all-or-nothing prompt ("What would you like to do? y / / N") does not actually delete anything on its own — a second, separate per-version confirmation is silently required afterward, and if it's missed, every candidate is skipped with no visible error and fnm uninstall/m.Uninstall() never runs.
Root cause
internal/cli/cleanup.go:
promptAllOrNothing (called at runCleanupPrompt Step 3, line ~133) correctly parses a y answer as decision.deleteAll = true, setting toOffer = candidates (line 156).
- Step 4 (line 164-187) then unconditionally loops over
toOffer and, because cfg.PerVersion defaults to true (from cleanup.prompt: true's config default), calls promptPerVersion(v, streams) again for every single version — regardless of the "delete all" answer already given in Step 3.
- Nothing sets
cfg.PerVersion = false after decision.deleteAll is chosen. So the user is asked to confirm twice: once for "delete all," then once more per individual version.
- If that second round of prompts doesn't receive an explicit
y for each version (e.g., the user only meant to answer once, or the terminal session's input ends there), promptPerVersion defaults to "no" (cleanup.go:326-331, the default: case), each version lands in result.Skipped, and m.Uninstall(v) is never called.
Reproduction
nodeup upgrade
# at the "Old Node.js versions still on disk (N): ... What would you like to do?" prompt, answer: y
Expected: all listed old versions get deleted (the user just explicitly said "delete all").
Actual: a second, separate Delete v<x>? [y/N] prompt appears per version; if not answered y again for each one, the versions are silently kept, with no clear indication that the first "y" wasn't sufficient.
User-reported symptom
Confirmed live: user answered y/a version number at the cleanup prompt during a real nodeup upgrade, but fnm list afterward still showed the old versions — no deletion occurred.
Suggested fix (not applied — filing only per request)
When decision.deleteAll (or a specific decision.deleteOne) is chosen at the all-or-nothing prompt, that should be treated as sufficient confirmation — either skip the per-version loop's confirmation entirely for those already-confirmed candidates (set cfg.PerVersion = false for this call once a deleteAll/deleteOne decision is made), or make it unambiguous to the user that a second per-version confirmation is coming.
Severity
High — this is the core promise of the cleanup feature (deleting confirmed old versions) silently not happening despite explicit user confirmation, with no error surfaced.
Describe the bug
Confirming deletion at the post-upgrade cleanup's all-or-nothing prompt ("What would you like to do? y / / N") does not actually delete anything on its own — a second, separate per-version confirmation is silently required afterward, and if it's missed, every candidate is skipped with no visible error and
fnm uninstall/m.Uninstall()never runs.Root cause
internal/cli/cleanup.go:promptAllOrNothing(called atrunCleanupPromptStep 3, line ~133) correctly parses ayanswer asdecision.deleteAll = true, settingtoOffer = candidates(line 156).toOfferand, becausecfg.PerVersiondefaults totrue(fromcleanup.prompt: true's config default), callspromptPerVersion(v, streams)again for every single version — regardless of the "delete all" answer already given in Step 3.cfg.PerVersion = falseafterdecision.deleteAllis chosen. So the user is asked to confirm twice: once for "delete all," then once more per individual version.yfor each version (e.g., the user only meant to answer once, or the terminal session's input ends there),promptPerVersiondefaults to "no" (cleanup.go:326-331, thedefault:case), each version lands inresult.Skipped, andm.Uninstall(v)is never called.Reproduction
nodeup upgrade # at the "Old Node.js versions still on disk (N): ... What would you like to do?" prompt, answer: yExpected: all listed old versions get deleted (the user just explicitly said "delete all").
Actual: a second, separate
Delete v<x>? [y/N]prompt appears per version; if not answeredyagain for each one, the versions are silently kept, with no clear indication that the first "y" wasn't sufficient.User-reported symptom
Confirmed live: user answered
y/a version number at the cleanup prompt during a realnodeup upgrade, butfnm listafterward still showed the old versions — no deletion occurred.Suggested fix (not applied — filing only per request)
When
decision.deleteAll(or a specificdecision.deleteOne) is chosen at the all-or-nothing prompt, that should be treated as sufficient confirmation — either skip the per-version loop's confirmation entirely for those already-confirmed candidates (setcfg.PerVersion = falsefor this call once a deleteAll/deleteOne decision is made), or make it unambiguous to the user that a second per-version confirmation is coming.Severity
High — this is the core promise of the cleanup feature (deleting confirmed old versions) silently not happening despite explicit user confirmation, with no error surfaced.