Skip to content

feat(cli): plugins stay on their major unless --latest is given - #293

Closed
pviti wants to merge 2 commits into
mainfrom
feat/plugin-major-pin
Closed

pviti wants to merge 2 commits into
mainfrom
feat/plugin-major-pin

Conversation

@pviti

@pviti pviti commented Oct 15, 2026

Copy link
Copy Markdown
Member

Plugins stay on their major unless --latest is given

Today the CLI installs every plugin from npm's latest, and plugins:update follows it. A new major of a plugin, with its breaking changes, therefore reaches the users of any CLI version without them asking for it. Since the release of the 7.0.0 majors, for example, the 6.x CLI installs tags 3.0.0.

Changes

  • Plugin table (plugins:available). Each plugin has the major it is installed with, as a ^N range: today resources ^7, tags ^3, and so on. plugins:install uses it, oclif records it, and plugins:update stays within it. plugins:available shows the range in a new VERSION column.
  • plugins:install <plugin> --latest. It installs the latest version on npm, a new major included, so moving to the next major is always explicit.
    • It is the same as --tag latest and cannot be used together with --tag.
    • It works on an installed plugin too. Without --latest or --tag, the "already installed" message suggests it.
  • Plugins installed by an older CLI are recorded as latest. Before plugins:update they are pinned to the major they have, not to the major of the table, so they never change major implicitly. The same happens after an install with --latest.
  • Test: each range is ^N, with N not above the major of the plugin in the workspace. The table may lag behind: a plugin's new major reaches the CLI only when the table is updated explicitly, which is a change of the CLI.

Verification

End to end, with the CLI of this branch and the plugins on npm, in a sandbox with isolated config:

Case Result
plugins:install tags tags@^3 → 3.0.0
orders 5.7.0 recorded as latest, then plugins:update pinned to ^5, stays 5.7.0 (table: ^6)
plugins:install orders with orders installed "already installed" plus the --latest hint
plugins:install orders --latest, then plugins:update 6.0.0, then pinned to ^6
--latest --tag ^2 error, the flags are exclusive
plugins:uninstall tags --latest error, the flag is only for install

In the --latest case, oclif prints "installed v5.7.0" when it reinstalls a plugin, but it does install 6.0.0, as plugins shows.

CLI tests: 33 passing. The 2 that fail locally (applications:login, config:show) fail on main too and depend on the environment.

Not included

The 6.x CLI keeps installing latest. Its users can pin a plugin with plugins:install <plugin> --tag ^N.

🤖 Generated with Claude Code

pviti and others added 2 commits October 15, 2026 12:58
The CLI installed every plugin from npm's latest, and plugins:update followed
it, so a new major of a plugin (with its breaking changes) reached the users
of any CLI version silently.

- the plugin table holds the major each plugin is installed with (^N): a
  plugin is installed and updated within it
- plugins:install <plugin> --latest (same as --tag latest, not together with
  it) installs its latest version, a new major included, also over an
  installed plugin: the explicit move to the next major
- before plugins:update, the plugins that follow latest (installed by an
  older CLI, or with --latest) are pinned to the major they have
- plugins:available shows the version range; a test checks the table
  against the majors of the workspace plugins

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@pviti

pviti commented Oct 15, 2026

Copy link
Copy Markdown
Member Author

Merged into #295, a single PR to review with #294.

@pviti pviti closed this Oct 15, 2026
@pviti
pviti deleted the feat/plugin-major-pin branch October 15, 2026 13:55
pviti added a commit that referenced this pull request Oct 15, 2026
# No implicit major updates of the CLI and its plugins

This PR replaces #293 and #294: one review instead of two. A new major
of the CLI or of a plugin is installed only when the user asks for it
with `--latest`. On a Node.js version that is too old, the CLI now
explains what to do.

**Tests of the combined branch:** CLI 37 passing. The 2 that fail
locally (`applications:login`, `config:show`) fail on main too and
depend on the environment. `pnpm lint` and `check-packages` pass.

## 1. Plugins stay on their major unless `--latest` is given

Today the CLI installs every plugin from npm's `latest`, and
`plugins:update` follows it. A new major of a plugin, with its breaking
changes, therefore reaches the users of any CLI version without them
asking for it. Since the release of the 7.0.0 majors, for example, the
6.x CLI installs tags 3.0.0.

#### Changes

- **Plugin table** (`plugins:available`). Each plugin has the major it
is installed with, as a `^N` range: today `resources ^7`, `tags ^3`, and
so on. `plugins:install` uses it, oclif records it, and `plugins:update`
stays within it. `plugins:available` shows the range in a new VERSION
column.
- **`plugins:install <plugin> --latest`.** It installs the latest
version on npm, a new major included, so moving to the next major is
always explicit.
- It is the same as `--tag latest` and cannot be used together with
`--tag`.
- It works on an installed plugin too. Without `--latest` or `--tag`,
the "already installed" message suggests it.
- **Plugins installed by an older CLI** are recorded as `latest`. Before
`plugins:update` they are pinned to the major they have, not to the
major of the table, so they never change major implicitly. The same
happens after an install with `--latest`.
- **Test:** each range is `^N`, with N not above the major of the plugin
in the workspace. The table may lag behind: a plugin's new major reaches
the CLI only when the table is updated explicitly, which is a change of
the CLI.

#### Verification

End to end, with the CLI of this branch and the plugins on npm, in a
sandbox with isolated config:

| Case | Result |
|---|---|
| `plugins:install tags` | `tags@^3` → 3.0.0 |
| orders 5.7.0 recorded as `latest`, then `plugins:update` | pinned to
`^5`, stays 5.7.0 (table: `^6`) |
| `plugins:install orders` with orders installed | "already installed"
plus the `--latest` hint |
| `plugins:install orders --latest`, then `plugins:update` | 6.0.0, then
pinned to `^6` |
| `--latest --tag ^2` | error, the flags are exclusive |
| `plugins:uninstall tags --latest` | error, the flag is only for
install |

In the `--latest` case, oclif prints "installed v5.7.0" when it
reinstalls a plugin, but it does install 6.0.0, as `plugins` shows.

CLI tests: 33 passing. The 2 that fail locally (`applications:login`,
`config:show`) fail on main too and depend on the environment.

#### Not included

The 6.x CLI keeps installing `latest`. Its users can pin a plugin with
`plugins:install <plugin> --tag ^N`.

## 2. Clear Node.js error, `cli:update` stays on the current major

Users on Node.js 20 updated the 6.x CLI with `cli:update` and ran into
two problems.

1. **`cli:update` moved them to 7.0.0.** The 6.x command runs `npm
install -g @commercelayer/cli`, without a version and without checking
Node.js. It then printed the version of the process still running, the
previous one (6.9.3), so the update looked failed.
2. **CLI 7 fails on Node.js 20.** It stops while loading with
`ERR_REQUIRE_ESM` and prints the minified source of cli-core. I
reproduced it with CLI 7.0.0 on Node.js 20.5.1 (the official binary,
checksum verified).

#### Changes

- **`bin/run.js`** checks `engines.node` before loading anything and
says what to do instead:
  ```
  Commerce Layer CLI 7.0.0 requires Node.js >=22.13 (current: 20.5.1).
Update Node.js, or install the previous CLI major, which supports older
Node.js versions:

    npm install -g @commercelayer/cli@6
  ```
The check is in `src/engines.ts`, with no imports, so it loads on any
Node.js.
- **`cli:update`** works like the plugins (part 1).
- By default it installs the latest version of the current major
(`@^7`).
- `--latest` installs a new major. It cannot be used together with
`--version`.
- A release whose `engines.node` doesn't match the Node.js in use is not
installed: the command stops and names the Node.js version needed.
- **After the update** the command shows the version npm installed (`npm
ls -g`), for example `6.9.3 -> 6.9.9` or "up to date". When a new major
is available it says so: run `cli:update --latest`, or the release needs
a newer Node.js.
- **Update notice:** for a new major it suggests `cli:update --latest`.

#### Verification

- **Node.js 20.5.1:** the branch CLI prints the message above and exits
with code 1, instead of crashing.
- **`cli:update`**, with npm writing to an isolated prefix
(`npm_config_prefix`), so no real global install was touched:

  | Case | Output |
  |---|---|
  | From 7.0.0 | "is up to date: 7.0.0" |
| From a simulated 6.9.3 | "updated: 6.9.3 -> 6.9.9", then the 7.0.0
hint with `--latest` |
  | `--latest --version 7.0.0` | error, the flags are exclusive |

- **Tests:** unit tests for the version check, the error message and the
update target. The 2 that fail locally (`applications:login`,
`config:show`) fail on main too and depend on the environment.
- `pnpm lint` passes and `docs/cli.md` is regenerated.

#### Not included

The 6.x CLI keeps its old `cli:update`, which moves to the latest major.
Only a 6.x patch could change that, and those users would only get it
with `cli:update -v 6`.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant