Skip to content

fix(backend): mark -nightly/-canary/-experimental as prereleases#9523

Merged
jdx merged 3 commits intomainfrom
claude/objective-chandrasekhar-7b12bd
May 1, 2026
Merged

fix(backend): mark -nightly/-canary/-experimental as prereleases#9523
jdx merged 3 commits intomainfrom
claude/objective-chandrasekhar-7b12bd

Conversation

@jdx
Copy link
Copy Markdown
Owner

@jdx jdx commented May 1, 2026

Summary

When minimum_release_age is set, latest version resolution skips the backend's latest_stable_version fast path (e.g. npm dist-tags) and falls back to the shared version-list path, which relies on VERSION_REGEX to flag pre-releases. The regex did not catch -nightly, -canary, -experimental, -insider, or -edge channel tags, so npm packages like @google/gemini-cli resolved latest to a -nightly tarball instead of the stable maintainer-tagged release.

This adds those channel tags to VERSION_REGEX so they are filtered out of latest resolution and ls-remote (without --prerelease) on every backend that opts into pattern-based prerelease detection.

Fixes #9503

Test plan

  • cargo test test_version_regex_filters_prerelease
  • cargo test (full unit suite, 796 passing)
  • Manually verified mise install npm:@google/gemini-cli@latest with MISE_MINIMUM_RELEASE_AGE=0d no longer picks the -nightly tarball

🤖 Generated with Claude Code


Note

Medium Risk
Changes prerelease detection used in version listing/resolution, which may alter which versions are considered installable as “stable” (especially for npm packages) and could inadvertently filter edge-case version strings.

Overview
Improves prerelease filtering during version resolution so npm channel builds like -nightly, -canary, -experimental, -insider, and -edge are no longer treated as stable when VERSION_REGEX-based filtering is used.

The npm backend now explicitly marks versions as prereleases based on strict semver rule 9 (hyphen suffix, ignoring +build metadata), and adds focused unit tests covering both the new regex channels and semver prerelease parsing.

Reviewed by Cursor Bugbot for commit 9246794. Bugbot is set up for automated code reviews on this repo. Configure here.

When `minimum_release_age` is set, latest version resolution skips the
backend's `latest_stable_version` fast path (e.g. npm dist-tags) and
falls back to the shared version-list path, which relies on
`VERSION_REGEX` to flag pre-releases. The regex did not catch `-nightly`,
`-canary`, `-experimental`, `-insider`, or `-edge` channel tags, so npm
packages like `@google/gemini-cli` resolved `latest` to a `-nightly`
tarball instead of the stable maintainer-tagged release.

Add those channel tags to `VERSION_REGEX` so they are filtered out of
`latest` resolution and `ls-remote` (without `--prerelease`) on every
backend that opts into pattern-based prerelease detection.

Fixes #9503

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 1, 2026

Greptile Summary

This PR fixes a bug where npm packages like @google/gemini-cli resolved latest to a -nightly tarball when minimum_release_age was set, because the shared VERSION_REGEX didn't recognize common npm channel suffixes. The fix takes two complementary approaches: adding the five channel names to VERSION_REGEX (for all backends using pattern-based prerelease detection) and setting VersionInfo.prerelease via a new is_semver_prerelease helper in the npm backend that catches any semver prerelease tag, not just the named ones.

Confidence Score: 5/5

Safe to merge — targeted, well-tested regex and helper changes with no risk to stable version resolution.

Both change sites are additive: the regex adds new filter terms that won't match any realistic stable version string, and the npm helper correctly follows semver semantics. All five new channel tags now have test coverage (addressing the prior review comment), and the stable-version negative assertions are preserved.

No files require special attention.

Important Files Changed

Filename Overview
src/plugins/mod.rs Extends VERSION_REGEX with 5 npm channel tags (-nightly, -canary, -experimental, -insider, -edge); all are covered by the updated test block.
src/backend/npm.rs Adds npm-specific is_semver_prerelease helper that flags any version with a hyphen after stripping build metadata, wires it into VersionInfo.prerelease during list_remote_versions, with three new unit-test functions providing good coverage.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[list_remote_versions called] --> B{minimum_release_age set?}
    B -- No --> C[latest_stable_version fast path\ne.g. npm dist-tag latest]
    B -- Yes --> D[full version list path]
    D --> E[VersionInfo populated\nprerelease = is_semver_prerelease version]
    E --> F{version contains '-'\nafter stripping '+' build meta?}
    F -- Yes --> G[prerelease = true\nfiltered from latest]
    F -- No --> H[prerelease = false\nincluded in latest]
    D --> I[VERSION_REGEX also checked\nfor non-npm backends]
    I --> J{matches -nightly/-canary/\n-experimental/-insider/-edge/\nor other known pre-tag?}
    J -- Yes --> K[filtered as prerelease]
    J -- No --> L[kept as stable]
Loading

Reviews (3): Last reviewed commit: "fix(npm): treat any hyphen-suffixed vers..." | Re-trigger Greptile

Comment thread src/plugins/mod.rs Outdated
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request expands the VERSION_REGEX to include additional pre-release tags (nightly, canary, experimental, insider, edge) and adds corresponding unit tests. The reviewer suggests allowing dot separators for the new tags for consistency and robustness, and recommends adding test cases for the insider and edge tags.

Comment thread src/plugins/mod.rs
pub static VERSION_REGEX: Lazy<regex::Regex> = Lazy::new(|| {
Regex::new(
r"(?i)(^Available versions:|-src|[-\\.]dev|-latest|-stm|[-\\.]rc|-milestone|-alpha|-beta|[-\\.]pre|-next|-test|([abc])[0-9]+|snapshot|SNAPSHOT|master)"
r"(?i)(^Available versions:|-src|[-\\.]dev|-latest|-stm|[-\\.]rc|-milestone|-alpha|-beta|[-\\.]pre|-next|-test|-nightly|-canary|-experimental|-insider|-edge|([abc])[0-9]+|snapshot|SNAPSHOT|master)"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The newly added pre-release identifiers (nightly, canary, experimental, insider, edge) are currently only matched when preceded by a hyphen. For consistency with other identifiers in this regex (like dev, rc, and pre) which allow both hyphens and dots as separators (e.g., 1.0.0.dev), consider using [-\\.] for these new tags as well. This improves robustness for backends that might use different versioning conventions.

Suggested change
r"(?i)(^Available versions:|-src|[-\\.]dev|-latest|-stm|[-\\.]rc|-milestone|-alpha|-beta|[-\\.]pre|-next|-test|-nightly|-canary|-experimental|-insider|-edge|([abc])[0-9]+|snapshot|SNAPSHOT|master)"
r"(?i)(^Available versions:|-src|[-\\.]dev|-latest|-stm|[-\\.]rc|-milestone|-alpha|-beta|[-\\.]pre|-next|-test|[-\\.]nightly|[-\\.]canary|[-\\.]experimental|[-\\.]insider|[-\\.]edge|([abc])[0-9]+|snapshot|SNAPSHOT|master)"

Comment thread src/plugins/mod.rs Outdated
Comment on lines +451 to +463
// npm prerelease channels (GitHub discussion #9503)
assert!(
VERSION_REGEX.is_match("0.42.0-nightly.20260429.g6d9911393"),
"npm -nightly tag should be filtered"
);
assert!(
VERSION_REGEX.is_match("13.0.0-canary.1"),
"npm -canary tag should be filtered"
);
assert!(
VERSION_REGEX.is_match("18.0.0-experimental-abc1234"),
"npm -experimental tag should be filtered"
);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The test suite is missing cases for the -insider and -edge tags that were added to the regex. It's recommended to include test cases for all newly added patterns to ensure they are correctly identified and to prevent regressions.

        // npm prerelease channels (GitHub discussion #9503)
        assert!(
            VERSION_REGEX.is_match("0.42.0-nightly.20260429.g6d9911393"),
            "npm -nightly tag should be filtered"
        );
        assert!(
            VERSION_REGEX.is_match("13.0.0-canary.1"),
            "npm -canary tag should be filtered"
        );
        assert!(
            VERSION_REGEX.is_match("18.0.0-experimental-abc1234"),
            "npm -experimental tag should be filtered"
        );
        assert!(
            VERSION_REGEX.is_match("1.2.3-insider"),
            "npm -insider tag should be filtered"
        );
        assert!(
            VERSION_REGEX.is_match("1.2.3-edge"),
            "npm -edge tag should be filtered"
        );

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit fe83614. Configure here.

Comment thread src/plugins/mod.rs
The original `18.0.0-experimental-abc1234` fixture was already matched by
the pre-existing `([abc])[0-9]+` alternative (`c1234`), so the assertion
would pass even if `-experimental` was dropped from the regex. Switch to
suffixes that exercise only the channel-tag alternative under test, and
add the missing `-insider` / `-edge` cases for full coverage of #9523.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
@jdx
Copy link
Copy Markdown
Owner Author

jdx commented May 1, 2026

Addressed review feedback in e8e9b00:

  • cursor-bot (correct catch): the 18.0.0-experimental-abc1234 fixture was already matched by the pre-existing ([abc])[0-9]+ alternative via c1234, so the assertion would pass even if -experimental was removed from the regex. Switched to 18.0.0-experimental.1 which exercises only the new alternative. Did the same audit for the other tags (13.0.0-canary → no incidental match; 1.99.0-insider / 1.99.0-edge → no incidental match).
  • greptile / gemini: added -insider and -edge test cases.
  • gemini "use [-\.]nightly etc. for consistency": skipped — these are npm-style channel tags that universally use -. Broadening to . would risk false positives for backends using literals like .canary in stable version strings, and there's no current evidence any tool actually publishes the dot form.

🤖 Generated with Claude Code

The shared `VERSION_REGEX` channel-tag list will always lag behind
whatever new pre-release tag a maintainer invents (`-nightly`, `-canary`,
`-experimental`, ...). For npm specifically we don't have to play
whack-a-mole: npm enforces strict semver, so any hyphen-introduced
identifier on a version is — by rule 9 — a pre-release.

Stamp `prerelease = true` directly in `NPMBackend::_list_remote_versions`
based on a structural semver check, so the prerelease filter catches
maintainer-chosen tags that aren't in the regex (`-foo`, `-internal-...`,
future-named channels) without requiring a code change for each one.

The general regex addition from the previous commits is kept as a
backstop for backends without a strict semver guarantee.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 1, 2026

Hyperfine Performance

mise x -- echo

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.4.28 x -- echo 24.2 ± 1.0 22.9 33.0 1.00 ± 0.04
mise x -- echo 24.1 ± 0.3 23.5 29.0 1.00

mise env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.4.28 env 23.6 ± 2.0 22.3 43.6 1.00
mise env 23.9 ± 1.5 23.0 40.9 1.01 ± 0.11

mise hook-env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.4.28 hook-env 23.9 ± 0.7 23.1 28.4 1.00
mise hook-env 24.6 ± 0.5 23.8 29.5 1.03 ± 0.04

mise ls

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.4.28 ls 20.6 ± 0.2 20.1 22.0 1.00
mise ls 21.5 ± 0.3 20.8 22.8 1.04 ± 0.02

xtasks/test/perf

Command mise-2026.4.28 mise Variance
install (cached) 156ms 162ms -3%
ls (cached) 78ms 81ms -3%
bin-paths (cached) 83ms 85ms -2%
task-ls (cached) 797ms 788ms +1%

@jdx jdx merged commit 2e9e7e9 into main May 1, 2026
36 checks passed
@jdx jdx deleted the claude/objective-chandrasekhar-7b12bd branch May 1, 2026 17:38
mise-en-dev added a commit that referenced this pull request May 3, 2026
### 🚀 Features

- **(conda)** graduate conda backend out of experimental by @jdx in
[#9544](#9544)
- **(deps)** Add dart and flutter providers by @tjarvstrand in
[#9505](#9505)
- **(registry)** add neo4j by @mnm364 in
[#9525](#9525)
- **(registry)** add rustfs by @mnm364 in
[#9530](#9530)
- **(task)** support exclusion patterns in task sources by
@jlarmstrongiv in [#9496](#9496)
- **(vfox)** add stat function to lua file module by @esteve in
[#9497](#9497)

### 🐛 Bug Fixes

- **(backend)** flag regex prerelease versions by @jdx in
[#9500](#9500)
- **(backend)** mark -nightly/-canary/-experimental as prereleases by
@jdx in [#9523](#9523)
- **(backend)** suppress no-versions warning for unresolved-latest
backends by @jdx in [#9548](#9548)
- **(backend)** include dotnet prereleases from package flags by @jdx in
[#9551](#9551)
- **(backend)** scope PEP 440 prerelease detection to Python backends by
@jdx in [#9558](#9558)
- **(cargo)** Apply install_env during cargo install by @c22 in
[#9502](#9502)
- **(copr)** drop epel-9 chroots since rust >= 1.91 is unavailable by
@jdx in [#9484](#9484)
- **(github)** skip attestations on non-default api_url by @jdx in
[#9486](#9486)
- **(github)** retry ip allow list errors without auth by @risu729 in
[#9506](#9506)
- **(http)** update versions host tracking endpoint by @jdx in
[#9527](#9527)
- **(install)** don't warn for configured tools when version is passed
via CLI by @jdx in [#9522](#9522)
- **(install)** refresh latest before installing missing tools by @jdx
in [#9545](#9545)
- **(install)** don't cache nonexistent install paths by @jdx in
[#9553](#9553)
- **(lockfile)** don't propagate ad-hoc CLI overrides into the project
lockfile by @jdx in [#9562](#9562)
- **(plugin)** detect plugin types after cloning by @risu729 in
[#9540](#9540)
- **(release)** pass --no-git-checks to aube publish by @jdx in
[#9483](#9483)
- **(task)** convert PATH to MSYS Unix form when spawning POSIX shells
on Windows by @JamBalaya56562 in
[#9547](#9547)

### 📚 Documentation

- **(contributing)** require popularity check for registry PRs by @jdx
in
[7bbeebe](7bbeebe)
- **(watch)** update pitchfork domain to en.dev by @risu729 in
[#9536](#9536)
- document ghtkn GitHub token setup by @jdx in
[#9546](#9546)
- clarify registry backend acceptance policy by @jdx in
[#9543](#9543)
- Change exec command to use bash for variable echo by @kuboon in
[#9567](#9567)

### 🧪 Testing

- **(e2e)** run test-tool targets in parallel by @jdx in
[#9564](#9564)
- **(e2e)** run tests in parallel by @jdx in
[#9563](#9563)
- **(e2e)** bind-mount /tmp on disk and surface failed tests in CI
summary by @jdx in [#9570](#9570)
- **(tasks)** migrate test_task_help atask to usage field by @jdx in
[#9549](#9549)

### 📦️ Dependency Updates

- update fedora:45 docker digest to 8b838b3 by @renovate[bot] in
[#9507](#9507)
- update ghcr.io/jdx/mise:deb docker digest to f02194c by @renovate[bot]
in [#9509](#9509)
- update taiki-e/install-action digest to 7769b73 by @renovate[bot] in
[#9512](#9512)
- update ghcr.io/jdx/mise:alpine docker digest to 581f8a8 by
@renovate[bot] in [#9508](#9508)
- update rust crate ctor to v0.10.1 by @renovate[bot] in
[#9515](#9515)
- update ghcr.io/jdx/mise:rpm docker digest to a5c9655 by @renovate[bot]
in [#9510](#9510)
- update rust docker digest to a9cfb75 by @renovate[bot] in
[#9511](#9511)
- update rust crate age to v0.11.3 by @renovate[bot] in
[#9514](#9514)
- update rust crate jiff to v0.2.24 by @renovate[bot] in
[#9516](#9516)
- update dependency vitepress-plugin-tabs to ^0.9.0 by @renovate[bot] in
[#9518](#9518)
- update autofix-ci/action action to v1.3.4 by @renovate[bot] in
[#9513](#9513)
- update rust crate usage-lib to v3.2.1 by @renovate[bot] in
[#9517](#9517)
- update apple-actions/import-codesign-certs action to v7 by
@renovate[bot] in [#9519](#9519)
- update taiki-e/install-action digest to 51cd0b8 by @renovate[bot] in
[#9531](#9531)
- exclude taiki-e/install-action from renovate by @jdx in
[#9532](#9532)
- update rust crate blake3 to v1.8.5 by @renovate[bot] in
[#9533](#9533)

### 📦 Registry

- enable shellcheck on windows by @zeitlinger in
[#9487](#9487)
- add google-java-format by @zeitlinger in
[#9488](#9488)
- add expert
([aqua:expert-lsp/expert](https://github.com/expert-lsp/expert)) by
@AlternateRT in [#9498](#9498)
- update entry for checkmake by @eread in
[#9504](#9504)
- add systemctl-tui
([aqua:rgwood/systemctl-tui](https://github.com/rgwood/systemctl-tui))
by @2xdevv in [#9521](#9521)
- add codon by @3w36zj6 in
[#9538](#9538)
- add tool yr (backend:github:VirusTotal/yara-x) by @adam-moss in
[#9542](#9542)
- add tool betterleaks (backend:aqua/betterleaks/betterleaks) by
@adam-moss in [#9541](#9541)
- add `git-filter-repo` by @garysassano in
[#9550](#9550)
- add umoci
([aqua:opencontainers/umoci](https://github.com/opencontainers/umoci))
by @2xdevv in [#9555](#9555)
- add aqua backend for elixir-ls by @AlternateRT in
[#9557](#9557)
- deny inline backend options by @risu729 in
[#9565](#9565)

### Chore

- **(ci)** fail registry tests without summary by @jdx in
[#9559](#9559)
- **(ci)** use !cancelled() instead of always() for test-ci aggregator
by @jdx in [#9569](#9569)
- **(ci)** use namespace runners for ci jobs by @jdx in
[#9561](#9561)
- **(config)** deprecate shorthands_file setting by @risu729 in
[#9534](#9534)
- **(docs)** remove shrill.en.dev analytics script by @jdx in
[#9539](#9539)
- **(release)** replace bc with awk in release-plz star formatting by
@jdx in
[d7f177f](d7f177f)
- bump hk to 1.44.3 by @jdx in
[#9493](#9493)
- invert CLAUDE.md/AGENTS.md so AGENTS.md is canonical by @jdx in
[#9560](#9560)
- set dev profile debug to 1 by @jdx in
[#9572](#9572)

### New Contributors

- @kuboon made their first contribution in
[#9567](#9567)
- @AlternateRT made their first contribution in
[#9557](#9557)
- @2xdevv made their first contribution in
[#9555](#9555)
- @adam-moss made their first contribution in
[#9541](#9541)
- @jlarmstrongiv made their first contribution in
[#9496](#9496)
- @tjarvstrand made their first contribution in
[#9505](#9505)
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.

1 participant