Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,37 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]

### Added
- Post-upgrade cleanup prompt (`nodeup upgrade`): after a successful
upgrade, nodeup asks whether to delete the old Node.js versions
left behind. The prompt offers three options — `y` deletes every
candidate, typing a specific version (e.g. `20.18.0`) deletes only
that one, and `N` (or empty enter) skips. Candidates are computed
as `installed \ {new LTS, new Current, currently active}`, where
the active version is detected via `<manager> current` (or per-
manager equivalent). The new `Manager.Current()` interface method
backs the exclusion — nvm-windows returns the
`ErrNVMWindowsNotImplemented` sentinel and the exclusion is
skipped. New flags: `--cleanup` (auto-confirm), `--cleanup-version
<v>` (repeatable, picks specific versions), plus the existing
`--no-cleanup` to skip the prompt entirely. Config equivalents
(`cleanup.auto`, `cleanup.prompt`) ship under the same names; see
`docs/managers.md#post-upgrade-cleanup` for the full precedence
table. Closes #41.
- Native mutation commands for all 7 working managers (fnm, nvm,
Volta, asdf, mise, n, nodenv): `Install`, `Uninstall`, `Use`,
`SetDefault`, and `GlobalNpmPrefix` are now real shell-outs rather
than stubs returning `ErrXxxNotImplemented`. Volta's `SetDefault`
and n's `SetDefault` are intentional no-ops (those managers pin
per-project, not per-machine). `GlobalNpmPrefix` returns the
per-version npm global modules directory for each manager's on-
disk layout, which the migration step needs to enumerate packages.
nvm-windows remains unsupported (no install/uninstall CLI on that
platform); its stubs still return
`ErrNVMWindowsNotImplemented` so callers can detect and skip.
Per-manager cleanup behavior is documented in
`docs/managers.md#post-upgrade-cleanup`. Closes #40.

### Added (continued)
- YAML config file support (`internal/config`): the documented schema
from `docs/configuration.md` is now first-class. Settings live in
`~/.nodeup/config.yaml` (override with `$NODEUP_CONFIG` or redirect
Expand Down
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,15 @@ nodeup upgrade --dry-run
nodeup upgrade --yes
```

After a successful upgrade, `nodeup upgrade` prompts you about removing old
Node.js versions — answering **y** deletes all of them, typing a specific
version (e.g. `20.18.0`) deletes only that one, and **N** (or empty enter)
keeps everything. The candidates exclude the new LTS / Current we just
installed plus the version that's currently active on your shell. Skip
the prompt entirely with `--no-cleanup` or pre-decide with `--cleanup`.
See [docs/managers.md](docs/managers.md#post-upgrade-cleanup) for the
full set of cleanup flags and per-manager behavior.

If you have multiple managers installed, `nodeup` will prompt you to pick one
the first time and remember it in `~/.nodeup/config.yaml`.

Expand Down Expand Up @@ -234,7 +243,7 @@ This is the **v1.0.0 development line**. See `CHANGELOG.md` for what's done.

| Version | Status | Notes |
|---|---|---|
| v1.0.0 | 🛠 in development | Phase 1 ✅ — 8/8 managers detected. Phase 2 ✅ — `nodeup check` with nodejs.org/dist/index.json fetch + TTL cache. Phase 3 ✅ — package snapshot/restore + migration report. Phase 4 ✅ — end-to-end `nodeup upgrade`. Phase 5 ✅ — YAML config file + `config` subcommands (show / get / set / init). Phase 6 ✅ — cross-platform polish: `QuotePath` for paths with spaces, interrupted-upgrade sentinel + replay, system-node classifier with warnings. Phase 7 (GoReleaser config + brew/scoop taps + npm wrapper) is the remaining work — see issues #17 and #18. |
| v1.0.0 | 🛠 in development | Phase 1 ✅ — 8/8 managers detected. Phase 2 ✅ — `nodeup check` with nodejs.org/dist/index.json fetch + TTL cache. Phase 3 ✅ — package snapshot/restore + migration report. Phase 4 ✅ — end-to-end `nodeup upgrade`. Phase 5 ✅ — YAML config file + `config` subcommands (show / get / set / init). Phase 6 ✅ — cross-platform polish: `QuotePath` for paths with spaces, interrupted-upgrade sentinel + replay, system-node classifier with warnings. Phase 7 ✅ — post-upgrade cleanup prompt (`--cleanup` / `--cleanup-version` / `--no-cleanup` / `cleanup.auto` / `cleanup.prompt`) plus native mutation commands for all 7 supported managers. Distribution (GoReleaser + brew/scoop taps + npm wrapper) is also Phase 7 — see issues #17 and #18. |

Phase 1 is the **detection surface** — every manager is recognized and the
version + installed-list reads return real data (PRs #1–#8). Subsequent
Expand Down
85 changes: 84 additions & 1 deletion docs/managers.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,87 @@ bin dir (e.g., `fnm env --use-on-cd | source`, or add
points at a binary inside the manager's data dir, nodeup's next
run will classify it as `manager` and proceed without warning.

> _Status: Phase 1 ✅ done — all 8 managers detected · last updated 2026-06-29_
> _Status: Phase 7 in progress — post-upgrade cleanup + native mutation commands per manager._

## Post-upgrade cleanup

When `nodeup upgrade` finishes installing the new LTS and/or Current
versions, it asks whether you want to delete the old ones. The
prompt is enabled by default (so the upgrade doesn't lose data
silently), but the behavior is configurable.

### Candidates

A version is a **cleanup candidate** if all three are true:

1. The manager has it installed (`<manager> list` / equivalent).
2. It's NOT one of the versions we just installed (new LTS, new
Current).
3. It's NOT the version that's currently active on your shell. We
detect this via `<manager> current` (or `<manager> version`,
`<manager> list --format=plain`, etc. — see per-manager table
below). If the manager doesn't expose a "current version" query,
the exclusion is skipped (better to over-prompt than to leave a
broken shell).

For example, if you had 18.20.4, 20.18.0, and 22.11.0 installed and
upgraded to 22.11.0 (LTS) + 24.15.0 (Current), with 20.18.0 active,
the candidates are: just **18.20.4**. The new versions and the
active version are off-limits.

### Flags

| Flag | Effect |
|--------------------------|-----------------------------------------------------------------|
| (no flag) | Prompt: `y` deletes all / typed version deletes one / `N` skips |
| `--cleanup` | Skip the prompt; auto-confirm deletion of every candidate |
| `--cleanup-version <v>` | Skip the prompt; only delete the specified versions (repeatable; pairs with `--cleanup`) |
| `--no-cleanup` | Skip the prompt AND don't delete anything |
| `--yes` | Implies `--cleanup` for non-interactive runs (e.g., CI) |

Config equivalents (`~/.nodeup/config.yaml`):

```yaml
cleanup:
auto: false # set true to skip the all-or-nothing prompt
prompt: true # set false to skip per-version confirm
```

Precedence (highest first):

1. `--no-cleanup` — never prompt, never delete
2. `--cleanup` (or `cleanup.auto: true` in config) — auto-confirm
3. `--cleanup-version <v>` — restrict to specific versions
4. `cleanup.prompt: false` — skip per-version confirm
5. Default — interactive prompt

### Per-manager behavior

| Manager | Install cmd | Uninstall cmd | Current query | Notes |
|----------------|------------------------------|--------------------------|--------------------------------------|-------|
| **fnm** | `fnm install <v>` | `fnm uninstall <v>` | `fnm current` | Refuses to uninstall the active version. The prompt excludes it. |
| **nvm** | `source nvm.sh && nvm install -s <v>` | `… nvm uninstall <v>` | `… nvm current` (`system` / `none` → "unknown") | Uses `-s` to suppress prompts. |
| **Volta** | `volta install node@<v>` | `volta uninstall node@<v>` | First `node@<v>` row of `volta list --format=plain` | `SetDefault` is a no-op (Volta pins per-project, not per-machine). |
| **asdf** | `asdf install nodejs <v>` | `asdf uninstall nodejs <v>` | `asdf current nodejs` | Plugin name is `nodejs` (not `node`). |
| **mise** | `mise install node@<v>` | `mise uninstall node@<v>` | `mise current node` | `SetDefault` writes to `~/.config/mise/config.toml` via `mise use --global`. |
| **n** | `n install <v>` | `n uninstall <v>` | `n current` (n ≥ 8) | `SetDefault` is a no-op (n auto-uses the latest install). |
| **nodenv** | `nodenv install <v>` | `nodenv uninstall <v>` | `nodenv version` (treats `system` as "unknown") | SetDefault writes to `~/.nodenv/version`. |
| **nvm-windows**| **unsupported** | **unsupported** | returns `ErrNVMWindowsNotImplemented` | `nvm-windows` doesn't expose a CLI for install/uninstall — the upgrade command leaves the install list alone and prints a clear note. |

For nvm-windows, the upgrade proceeds normally but the cleanup
prompt is suppressed with a note: "nvm-windows cleanup is not yet
implemented — leave the old versions in place or remove them
manually via `nvm uninstall <v>` from an elevated shell."

### Failure modes

- **Manager not on PATH** — the cleanup step is skipped entirely;
the upgrade itself still completes (Install/SetDefault will
have already failed loudly if the manager wasn't there).
- **Uninstall fails** (permission denied, currently-active
version, locked file, ...) — we record the failure and continue
with the next candidate. The summary at the end lists both
successes and failures, so you can clean up the leftovers
manually.
- **Ctrl-C mid-prompt** — we exit cleanly; the upgrade is already
done, the prompt is the only thing that gets interrupted.
Loading
Loading