From e144339efe78442335aed33cca0fe135d830b8f2 Mon Sep 17 00:00:00 2001 From: Ariel Caplan Date: Fri, 5 Jun 2026 08:03:40 +0300 Subject: [PATCH 1/3] Remove semver from cli-kit; use compare-versions Co-Authored-By: Claude --- .changeset/remove-cli-kit-semver.md | 5 +++ packages/cli-kit/package.json | 3 +- .../public/node/node-package-manager.test.ts | 21 ++++++++++ .../src/public/node/node-package-manager.ts | 40 +++++++++++++++++-- .../cli-kit/src/public/node/version.test.ts | 25 +++++++++++- packages/cli-kit/src/public/node/version.ts | 12 ++++-- pnpm-lock.yaml | 19 ++++----- 7 files changed, 103 insertions(+), 22 deletions(-) create mode 100644 .changeset/remove-cli-kit-semver.md diff --git a/.changeset/remove-cli-kit-semver.md b/.changeset/remove-cli-kit-semver.md new file mode 100644 index 00000000000..6701aa588bb --- /dev/null +++ b/.changeset/remove-cli-kit-semver.md @@ -0,0 +1,5 @@ +--- +'@shopify/cli-kit': patch +--- + +Replace direct semver usage with compare-versions. diff --git a/packages/cli-kit/package.json b/packages/cli-kit/package.json index 1725431d06d..572895de18f 100644 --- a/packages/cli-kit/package.json +++ b/packages/cli-kit/package.json @@ -121,6 +121,7 @@ "chalk": "5.4.1", "change-case": "4.1.2", "color-json": "3.0.5", + "compare-versions": "6.1.1", "conf": "11.0.2", "deepmerge": "4.3.1", "dotenv": "16.4.7", @@ -151,7 +152,6 @@ "open": "8.4.2", "pathe": "1.1.2", "react": "19.2.4", - "semver": "7.6.3", "stacktracey": "2.1.8", "strip-ansi": "7.1.0", "supports-hyperlinks": "3.1.0", @@ -165,7 +165,6 @@ "@types/gradient-string": "^1.1.2", "@types/lodash": "4.17.19", "@types/react": "^19.0.0", - "@types/semver": "^7.5.2", "@types/which": "3.0.4", "@vitest/coverage-istanbul": "^3.1.4", "msw": "^2.7.1", diff --git a/packages/cli-kit/src/public/node/node-package-manager.test.ts b/packages/cli-kit/src/public/node/node-package-manager.test.ts index 2e5221a75a9..625bbad3623 100644 --- a/packages/cli-kit/src/public/node/node-package-manager.test.ts +++ b/packages/cli-kit/src/public/node/node-package-manager.test.ts @@ -23,6 +23,7 @@ import { PackageManager, npmLockfile, lockfilesByManager, + versionSatisfies, } from './node-package-manager.js' import {captureOutput, exec} from './system.js' import {inTemporaryDirectory, mkdir, touchFile, writeFile} from './fs.js' @@ -584,6 +585,26 @@ describe('checkForCachedNewVersion', () => { }) }) +describe('versionSatisfies', () => { + test.each<[boolean, string, string]>([ + [true, '1.2.3', '>=1.0.0'], + [true, '1.2.3', '<=1.2.3'], + [false, '1.2.3', '<1.2.3'], + [false, '1.2', '>=1.2.0'], + [true, '2.0.0', '<=2.0'], + [true, '2.0.1', '<=2.0'], + [false, '2.1.0', '<=2.0'], + [false, '0.0.0-snapshot', '<1.0.0'], + [false, '1.2.3-alpha.1', '<1.2.3'], + [true, '1.2.3-alpha.1', '>=1.2.3-alpha.0'], + [true, '1.2.3-alpha.1', '<=1.2.3-alpha.1'], + [true, '1.2.3-alpha.1', '<1.2.3-alpha.2'], + [false, '1.2.4-alpha.1', '>1.2.3-alpha.1'], + ])('returns %s for version %s and requirements %s', (expected, version, requirements) => { + expect(versionSatisfies(version, requirements)).toBe(expected) + }) +}) + describe('checkForNewVersion', () => { beforeEach(() => cacheClear()) afterEach(() => { diff --git a/packages/cli-kit/src/public/node/node-package-manager.ts b/packages/cli-kit/src/public/node/node-package-manager.ts index c2335b46d9d..93719bf30ae 100644 --- a/packages/cli-kit/src/public/node/node-package-manager.ts +++ b/packages/cli-kit/src/public/node/node-package-manager.ts @@ -8,7 +8,7 @@ import {inferPackageManagerForGlobalCLI} from './is-global.js' import {outputToken, outputContent, outputDebug} from './output.js' import {PackageVersionKey, cacheRetrieve, cacheRetrieveOrRepopulate} from '../../private/node/conf-store.js' import {parseJSON} from '../common/json.js' -import {SemVer, satisfies as semverSatisfies} from 'semver' +import {compareVersions, satisfies as versionSatisfiesRequirement} from 'compare-versions' import type {Writable} from 'stream' import type {ExecOptions} from './system.js' @@ -334,7 +334,7 @@ export async function checkForNewVersion( return undefined } - if (lastVersion && new SemVer(currentVersion).compare(lastVersion) < 0) { + if (lastVersion && compareVersions(currentVersion, lastVersion) < 0) { return lastVersion } else { return undefined @@ -351,7 +351,7 @@ export function checkForCachedNewVersion(dependency: string, currentVersion: str const cacheKey: PackageVersionKey = `npm-package-${dependency}` const lastVersion = cacheRetrieve(cacheKey)?.value - if (lastVersion && new SemVer(currentVersion).compare(lastVersion) < 0) { + if (lastVersion && compareVersions(currentVersion, lastVersion) < 0) { return lastVersion } else { return undefined @@ -365,7 +365,39 @@ export function checkForCachedNewVersion(dependency: string, currentVersion: str * @returns A boolean indicating whether the version satisfies the requirements */ export function versionSatisfies(version: string, requirements: string): boolean { - return semverSatisfies(version, requirements) + if (!semverVersionRegex.test(version)) return false + + const prereleaseBaseVersion = baseVersionForPrerelease(version) + // semver excludes prerelease candidates from normal ranges unless the range opts into that prerelease tuple. + if (prereleaseBaseVersion && !requirementsTargetPrereleaseBaseVersion(requirements, prereleaseBaseVersion)) { + return false + } + + return versionSatisfiesRequirement(version, normalizeSemverPartialRequirements(requirements)) +} + +const semverVersionRegex = /^v?\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/ +const prereleaseVersionRegex = /^v?(\d+)\.(\d+)\.(\d+)-[^+]+(?:\+.*)?$/ +const prereleaseRequirementRegex = /v?(\d+)\.(\d+)\.(\d+)-[0-9A-Za-z.-]+(?:\+[0-9A-Za-z.-]+)?/g +const partialMinorUpperBoundRegex = /(^|\s)<=\s*v?(\d+)\.(\d+)(?=$|\s)/g + +function baseVersionForPrerelease(version: string): string | undefined { + const prereleaseMatch = version.match(prereleaseVersionRegex) + if (!prereleaseMatch) return undefined + + return `${prereleaseMatch[1]}.${prereleaseMatch[2]}.${prereleaseMatch[3]}` +} + +function requirementsTargetPrereleaseBaseVersion(requirements: string, baseVersion: string): boolean { + return Array.from(requirements.matchAll(prereleaseRequirementRegex)).some((requirementMatch) => { + return `${requirementMatch[1]}.${requirementMatch[2]}.${requirementMatch[3]}` === baseVersion + }) +} + +function normalizeSemverPartialRequirements(requirements: string): string { + return requirements.replace(partialMinorUpperBoundRegex, (_match, prefix: string, major: string, minor: string) => { + return `${prefix}<${major}.${Number(minor) + 1}.0` + }) } /** diff --git a/packages/cli-kit/src/public/node/version.test.ts b/packages/cli-kit/src/public/node/version.test.ts index 98f3ce67a1c..c8892c1ecb0 100644 --- a/packages/cli-kit/src/public/node/version.test.ts +++ b/packages/cli-kit/src/public/node/version.test.ts @@ -1,5 +1,5 @@ import {captureOutput} from './system.js' -import {localCLIVersion, globalCLIVersion, isPreReleaseVersion} from './version.js' +import {localCLIVersion, globalCLIVersion, isPreReleaseVersion, isMajorVersionChange} from './version.js' import {inTemporaryDirectory} from './fs.js' import {describe, expect, test, vi} from 'vitest' @@ -89,3 +89,26 @@ describe('isPreReleaseVersion', () => { expect(isPreReleaseVersion('3.68.0')).toBe(false) }) }) + +describe('isMajorVersionChange', () => { + test('returns true when the major version changes', () => { + expect(isMajorVersionChange('3.68.0', '4.0.0')).toBe(true) + }) + + test('returns false when the major version stays the same', () => { + expect(isMajorVersionChange('3.68.0', '3.69.0')).toBe(false) + }) + + test('handles a leading v and prerelease suffix', () => { + expect(isMajorVersionChange('v3.68.0-alpha.1', '3.69.0')).toBe(false) + }) + + test('throws for partial versions', () => { + expect(() => isMajorVersionChange('3.68', '4.0.0')).toThrow('Invalid version: 3.68') + }) + + test('returns false for prerelease CLI versions', () => { + expect(isMajorVersionChange('0.0.0-snapshot', '4.0.0')).toBe(false) + expect(isMajorVersionChange('3.68.0', '0.0.0-snapshot')).toBe(false) + }) +}) diff --git a/packages/cli-kit/src/public/node/version.ts b/packages/cli-kit/src/public/node/version.ts index a28ba9e44cf..06864234d87 100644 --- a/packages/cli-kit/src/public/node/version.ts +++ b/packages/cli-kit/src/public/node/version.ts @@ -1,6 +1,6 @@ import {captureOutput} from './system.js' import which from 'which' -import {satisfies, SemVer} from 'semver' +import {satisfies, validateStrict} from 'compare-versions' /** * Returns the version of the local dependency of the CLI if it's installed in the provided directory. * @@ -54,6 +54,12 @@ export function isPreReleaseVersion(version: string): boolean { return version.startsWith('0.0.0') } +function majorVersion(version: string): number { + const normalizedVersion = version.replace(/^v/, '') + if (!validateStrict(normalizedVersion)) throw new Error(`Invalid version: ${version}`) + return Number(normalizedVersion.split('.')[0]) +} + /** * Checks if there is a major version change between two versions. * Pre-release versions (0.0.0-*) are treated as not having a major version change. @@ -64,7 +70,5 @@ export function isPreReleaseVersion(version: string): boolean { */ export function isMajorVersionChange(currentVersion: string, newerVersion: string): boolean { if (isPreReleaseVersion(currentVersion) || isPreReleaseVersion(newerVersion)) return false - const currentSemVer = new SemVer(currentVersion) - const newerSemVer = new SemVer(newerVersion) - return currentSemVer.major !== newerSemVer.major + return majorVersion(currentVersion) !== majorVersion(newerVersion) } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6355cc39894..79e89edd47e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -354,6 +354,9 @@ importers: color-json: specifier: 3.0.5 version: 3.0.5 + compare-versions: + specifier: 6.1.1 + version: 6.1.1 conf: specifier: 11.0.2 version: 11.0.2 @@ -444,9 +447,6 @@ importers: react: specifier: 19.2.4 version: 19.2.4 - semver: - specifier: 7.6.3 - version: 7.6.3 stacktracey: specifier: 2.1.8 version: 2.1.8 @@ -481,9 +481,6 @@ importers: '@types/react': specifier: 18.3.12 version: 18.3.12 - '@types/semver': - specifier: ^7.5.2 - version: 7.7.1 '@types/which': specifier: 3.0.4 version: 3.0.4 @@ -4210,9 +4207,6 @@ packages: '@types/retry@0.12.5': resolution: {integrity: sha512-3xSjTp3v03X/lSQLkczaN9UIEwJMoMCA1+Nb5HfbJEQWogdeQIyVtTvxPXDQjZ5zws8rFQfVfRdz03ARihPJgw==} - '@types/semver@7.7.1': - resolution: {integrity: sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==} - '@types/statuses@2.0.6': resolution: {integrity: sha512-xMAgYwceFhRA2zY+XbEA7mxYbA093wdiW8Vu6gZPGWy9cmOyU9XesH1tNcEWsKFd5Vzrqx5T3D38PWx1FIIXkA==} @@ -5078,6 +5072,9 @@ packages: resolution: {integrity: sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==} engines: {node: '>=4.0.0'} + compare-versions@6.1.1: + resolution: {integrity: sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==} + compress-commons@4.1.2: resolution: {integrity: sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg==} engines: {node: '>= 10'} @@ -13674,8 +13671,6 @@ snapshots: '@types/retry@0.12.5': {} - '@types/semver@7.7.1': {} - '@types/statuses@2.0.6': {} '@types/tinycolor2@1.4.6': {} @@ -14654,6 +14649,8 @@ snapshots: common-tags@1.8.2: {} + compare-versions@6.1.1: {} + compress-commons@4.1.2: dependencies: buffer-crc32: 0.2.13 From ea311d752b2a24e79f1017ff1fbb1a0a0a6b79f3 Mon Sep 17 00:00:00 2001 From: Ariel Caplan Date: Sun, 7 Jun 2026 23:03:20 +0300 Subject: [PATCH 2/3] Simplify versionSatisfies; handle prerelease builds at call sites MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The initial semver→compare-versions swap reproduced semver's prerelease and partial-version range quirks inside versionSatisfies (4 regexes + 3 helpers) to preserve behavior exactly. Investigation showed that logic was only exercised by the CLI's own 0.0.0-* snapshot builds, and the live notifications.json feed never uses partial versions — so the complexity wasn't earning its keep. - versionSatisfies is now plain compare-versions semantics plus a `validate` guard, so invalid input returns false instead of throwing (matching semver's forgiving behavior for the inputs that actually occur). - Snapshot/prerelease policy moved to the two call sites with a product opinion: - notifications-system: 0.0.0-* builds don't match version-pinned notifications. - app-management allowedTemplates: prerelease builds get all non-deprecated templates — its existing isPreReleaseVersion path is now authoritative rather than relying on the shared util reproducing semver's prerelease exclusion. Behavior-preserving for all real release versions and for snapshot builds at every call site; verified via the cli-kit and app test suites. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../app-management-client.ts | 11 +++-- .../public/node/node-package-manager.test.ts | 19 ++++---- .../src/public/node/node-package-manager.ts | 45 ++++--------------- .../public/node/notifications-system.test.ts | 11 +++++ .../src/public/node/notifications-system.ts | 3 ++ 5 files changed, 40 insertions(+), 49 deletions(-) diff --git a/packages/app/src/cli/utilities/developer-platform-client/app-management-client.ts b/packages/app/src/cli/utilities/developer-platform-client/app-management-client.ts index 5d8ac4d1c8f..6ac0fd6e6b6 100644 --- a/packages/app/src/cli/utilities/developer-platform-client/app-management-client.ts +++ b/packages/app/src/cli/utilities/developer-platform-client/app-management-client.ts @@ -1352,14 +1352,17 @@ export async function allowedTemplates( // Check exp flags const hasNeededExpFlags = !ext.organizationExpFlags || ext.organizationExpFlags.every((flag) => enabledExpFlags[flag]) + if (!hasNeededBetaFlags || !hasNeededExpFlags) return false + + // Snapshot/dev builds (0.0.0-*) aren't real releases: they get every template that hasn't been + // explicitly deprecated, regardless of the minimum CLI version. + if (isPreReleaseVersion(version)) return ext.deprecatedFromCliVersion === undefined + // Version checks const satisfiesMinCliVersion = !ext.minimumCliVersion || versionSatisfies(version, `>=${ext.minimumCliVersion}`) const satisfiesDeprecatedFromCliVersion = !ext.deprecatedFromCliVersion || versionSatisfies(version, `<${ext.deprecatedFromCliVersion}`) - const satisfiesVersion = satisfiesMinCliVersion && satisfiesDeprecatedFromCliVersion - const satisfiesPreReleaseVersion = isPreReleaseVersion(version) && ext.deprecatedFromCliVersion === undefined - // Must satisfy both flag types AND version requirements - return hasNeededBetaFlags && hasNeededExpFlags && (satisfiesVersion || satisfiesPreReleaseVersion) + return satisfiesMinCliVersion && satisfiesDeprecatedFromCliVersion }) } diff --git a/packages/cli-kit/src/public/node/node-package-manager.test.ts b/packages/cli-kit/src/public/node/node-package-manager.test.ts index 625bbad3623..db8b4386634 100644 --- a/packages/cli-kit/src/public/node/node-package-manager.test.ts +++ b/packages/cli-kit/src/public/node/node-package-manager.test.ts @@ -590,16 +590,17 @@ describe('versionSatisfies', () => { [true, '1.2.3', '>=1.0.0'], [true, '1.2.3', '<=1.2.3'], [false, '1.2.3', '<1.2.3'], - [false, '1.2', '>=1.2.0'], - [true, '2.0.0', '<=2.0'], - [true, '2.0.1', '<=2.0'], - [false, '2.1.0', '<=2.0'], - [false, '0.0.0-snapshot', '<1.0.0'], - [false, '1.2.3-alpha.1', '<1.2.3'], + [true, '2.0.0', '>=2.0.0'], + [true, '3.83.3', '<=3.83.3'], + [false, '3.83.4', '<=3.83.3'], + [true, '3.80.0', '>=3.50.0'], + [true, '3.80.0', '<4.0.0'], + // Prereleases are compared by numeric precedence; there is no semver-style exclusion from normal ranges. + [true, '1.2.3-alpha.1', '<1.2.3'], [true, '1.2.3-alpha.1', '>=1.2.3-alpha.0'], - [true, '1.2.3-alpha.1', '<=1.2.3-alpha.1'], - [true, '1.2.3-alpha.1', '<1.2.3-alpha.2'], - [false, '1.2.4-alpha.1', '>1.2.3-alpha.1'], + // Invalid versions are rejected rather than throwing. + [false, 'not-a-version', '>=1.0.0'], + [false, '', '>=1.0.0'], ])('returns %s for version %s and requirements %s', (expected, version, requirements) => { expect(versionSatisfies(version, requirements)).toBe(expected) }) diff --git a/packages/cli-kit/src/public/node/node-package-manager.ts b/packages/cli-kit/src/public/node/node-package-manager.ts index 93719bf30ae..897262f08db 100644 --- a/packages/cli-kit/src/public/node/node-package-manager.ts +++ b/packages/cli-kit/src/public/node/node-package-manager.ts @@ -8,7 +8,7 @@ import {inferPackageManagerForGlobalCLI} from './is-global.js' import {outputToken, outputContent, outputDebug} from './output.js' import {PackageVersionKey, cacheRetrieve, cacheRetrieveOrRepopulate} from '../../private/node/conf-store.js' import {parseJSON} from '../common/json.js' -import {compareVersions, satisfies as versionSatisfiesRequirement} from 'compare-versions' +import {compareVersions, satisfies as versionSatisfiesRequirement, validate} from 'compare-versions' import type {Writable} from 'stream' import type {ExecOptions} from './system.js' @@ -360,44 +360,17 @@ export function checkForCachedNewVersion(dependency: string, currentVersion: str /** * Utility function used to check whether a package version satisfies some requirements + * + * Prerelease versions are compared by their numeric precedence, the same as any other version + * (i.e. there is no semver-style exclusion of prereleases from non-prerelease ranges). Callers that + * need to special-case the CLI's `0.0.0-*` snapshot builds should do so explicitly before calling this. * @param version - The version to check - * @param requirements - The requirements to check against, e.g. "\>=1.0.0" - see https://www.npmjs.com/package/semver#ranges - * @returns A boolean indicating whether the version satisfies the requirements + * @param requirements - The requirements to check against, e.g. "\>=1.0.0" - see https://www.npmjs.com/package/compare-versions + * @returns A boolean indicating whether the version satisfies the requirements. Returns false for invalid versions. */ export function versionSatisfies(version: string, requirements: string): boolean { - if (!semverVersionRegex.test(version)) return false - - const prereleaseBaseVersion = baseVersionForPrerelease(version) - // semver excludes prerelease candidates from normal ranges unless the range opts into that prerelease tuple. - if (prereleaseBaseVersion && !requirementsTargetPrereleaseBaseVersion(requirements, prereleaseBaseVersion)) { - return false - } - - return versionSatisfiesRequirement(version, normalizeSemverPartialRequirements(requirements)) -} - -const semverVersionRegex = /^v?\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/ -const prereleaseVersionRegex = /^v?(\d+)\.(\d+)\.(\d+)-[^+]+(?:\+.*)?$/ -const prereleaseRequirementRegex = /v?(\d+)\.(\d+)\.(\d+)-[0-9A-Za-z.-]+(?:\+[0-9A-Za-z.-]+)?/g -const partialMinorUpperBoundRegex = /(^|\s)<=\s*v?(\d+)\.(\d+)(?=$|\s)/g - -function baseVersionForPrerelease(version: string): string | undefined { - const prereleaseMatch = version.match(prereleaseVersionRegex) - if (!prereleaseMatch) return undefined - - return `${prereleaseMatch[1]}.${prereleaseMatch[2]}.${prereleaseMatch[3]}` -} - -function requirementsTargetPrereleaseBaseVersion(requirements: string, baseVersion: string): boolean { - return Array.from(requirements.matchAll(prereleaseRequirementRegex)).some((requirementMatch) => { - return `${requirementMatch[1]}.${requirementMatch[2]}.${requirementMatch[3]}` === baseVersion - }) -} - -function normalizeSemverPartialRequirements(requirements: string): string { - return requirements.replace(partialMinorUpperBoundRegex, (_match, prefix: string, major: string, minor: string) => { - return `${prefix}<${major}.${Number(minor) + 1}.0` - }) + if (!validate(version)) return false + return versionSatisfiesRequirement(version, requirements) } /** diff --git a/packages/cli-kit/src/public/node/notifications-system.test.ts b/packages/cli-kit/src/public/node/notifications-system.test.ts index 1eefbe57a37..296255136bb 100644 --- a/packages/cli-kit/src/public/node/notifications-system.test.ts +++ b/packages/cli-kit/src/public/node/notifications-system.test.ts @@ -276,6 +276,17 @@ describe('filterNotifications', () => { expect(result).toEqual(output) }) + test('excludes version-pinned notifications for prerelease (0.0.0-*) CLI builds', () => { + // Given + const input = [betweenVersins1and2, fromVersion1, upToVersion2, showAlways] + + // When + const result = filterNotifications(input, 'app:info', undefined, new Date('2020-01-15'), '0.0.0-nightly') + + // Then + expect(result).toEqual([showAlways]) + }) + test('Filter for frequency with always', async () => { // Given const current = new Date('2020-01-15T00:00:00.000Z') diff --git a/packages/cli-kit/src/public/node/notifications-system.ts b/packages/cli-kit/src/public/node/notifications-system.ts index d9eade1f1cb..035e7156d1b 100644 --- a/packages/cli-kit/src/public/node/notifications-system.ts +++ b/packages/cli-kit/src/public/node/notifications-system.ts @@ -1,4 +1,5 @@ import {versionSatisfies} from './node-package-manager.js' +import {isPreReleaseVersion} from './version.js' import {renderError, renderInfo, renderWarning} from './ui.js' import {getCurrentCommandId} from './global-context.js' import {outputDebug} from './output.js' @@ -228,6 +229,8 @@ export function filterNotifications( * @param currentVersion - The current version of the CLI. */ function filterByVersion(notification: Notification, currentVersion: string) { + // Snapshot/dev builds (0.0.0-*) aren't real releases, so they don't match version-pinned notifications. + if (isPreReleaseVersion(currentVersion)) return !notification.minVersion && !notification.maxVersion const minVersion = !notification.minVersion || versionSatisfies(currentVersion, `>=${notification.minVersion}`) const maxVersion = !notification.maxVersion || versionSatisfies(currentVersion, `<=${notification.maxVersion}`) return minVersion && maxVersion From 0e2b5a7068a18f7ec4bfb5992ad4d2dc54964767 Mon Sep 17 00:00:00 2001 From: Ariel Caplan Date: Mon, 8 Jun 2026 00:28:11 +0300 Subject: [PATCH 3/3] Remove unnecessary changeset --- .changeset/remove-cli-kit-semver.md | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 .changeset/remove-cli-kit-semver.md diff --git a/.changeset/remove-cli-kit-semver.md b/.changeset/remove-cli-kit-semver.md deleted file mode 100644 index 6701aa588bb..00000000000 --- a/.changeset/remove-cli-kit-semver.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@shopify/cli-kit': patch ---- - -Replace direct semver usage with compare-versions.