2025-09-10 16:28:58 +08:00
#!/usr/bin/env node
2025-07-06 04:58:59 +08:00
/ * *
* @ license
* Copyright 2025 Google LLC
* SPDX - License - Identifier : Apache - 2.0
* /
2025-08-26 04:11:27 +08:00
import { execSync } from 'node:child_process' ;
2025-09-10 16:28:58 +08:00
import { fileURLToPath } from 'node:url' ;
2025-09-27 07:35:26 +08:00
import { readFileSync } from 'node:fs' ;
2025-09-25 12:02:00 +08:00
import semver from 'semver' ;
2025-10-18 02:08:27 +08:00
import yargs from 'yargs' ;
import { hideBin } from 'yargs/helpers' ;
const TAG _LATEST = 'latest' ;
const TAG _NIGHTLY = 'nightly' ;
const TAG _PREVIEW = 'preview' ;
2025-09-10 16:28:58 +08:00
2025-09-27 07:35:26 +08:00
function readJson ( filePath ) {
return JSON . parse ( readFileSync ( filePath , 'utf-8' ) ) ;
}
2025-09-10 16:28:58 +08:00
function getArgs ( ) {
2025-10-18 02:08:27 +08:00
return yargs ( hideBin ( process . argv ) )
. option ( 'type' , {
description : 'The type of release to generate a version for.' ,
choices : [ TAG _NIGHTLY , 'promote-nightly' , 'stable' , TAG _PREVIEW , 'patch' ] ,
default : TAG _NIGHTLY ,
} )
. option ( 'patch-from' , {
description : 'When type is "patch", specifies the source branch.' ,
choices : [ 'stable' , TAG _PREVIEW ] ,
string : true ,
} )
. option ( 'stable_version_override' , {
description : 'Override the calculated stable version.' ,
string : true ,
} )
. option ( 'cli-package-name' , {
description :
'fully qualified package name with scope (e.g @google/gemini-cli)' ,
string : true ,
default : '@google/gemini-cli' ,
} )
. option ( 'preview_version_override' , {
description : 'Override the calculated preview version.' ,
string : true ,
} )
2025-11-08 05:06:55 +08:00
. option ( 'stable-base-version' , {
description : 'Base version to use for calculating next preview/nightly.' ,
string : true ,
} )
2025-10-18 02:08:27 +08:00
. help ( false )
. version ( false )
. parse ( ) ;
2025-07-06 04:58:59 +08:00
}
2025-09-10 16:28:58 +08:00
function getLatestTag ( pattern ) {
2025-09-25 12:02:00 +08:00
const command = ` git tag -l ' ${ pattern } ' ` ;
2025-09-10 16:28:58 +08:00
try {
2025-09-25 12:02:00 +08:00
const tags = execSync ( command )
. toString ( )
. trim ( )
. split ( '\n' )
. filter ( Boolean ) ;
if ( tags . length === 0 ) return '' ;
// Convert tags to versions (remove 'v' prefix) and sort by semver
const versions = tags
. map ( ( tag ) => tag . replace ( /^v/ , '' ) )
. filter ( ( version ) => semver . valid ( version ) )
. sort ( ( a , b ) => semver . rcompare ( a , b ) ) ; // rcompare for descending order
if ( versions . length === 0 ) return '' ;
// Return the latest version with 'v' prefix restored
return ` v ${ versions [ 0 ] } ` ;
} catch ( error ) {
console . error (
` Failed to get latest git tag for pattern " ${ pattern } ": ${ error . message } ` ,
) ;
2025-09-10 16:28:58 +08:00
return '' ;
2025-08-20 23:50:00 +08:00
}
}
2025-10-18 02:08:27 +08:00
function getVersionFromNPM ( { args , npmDistTag } = { } ) {
const command = ` npm view ${ args [ 'cli-package-name' ] } version --tag= ${ npmDistTag } ` ;
2025-09-17 14:47:05 +08:00
try {
return execSync ( command ) . toString ( ) . trim ( ) ;
2025-09-25 12:02:00 +08:00
} catch ( error ) {
console . error (
2025-10-18 02:08:27 +08:00
` Failed to get NPM version for dist-tag " ${ npmDistTag } ": ${ error . message } ` ,
2025-09-25 12:02:00 +08:00
) ;
2025-09-17 14:47:05 +08:00
return '' ;
}
}
2025-07-06 04:58:59 +08:00
2025-10-18 02:08:27 +08:00
function getAllVersionsFromNPM ( { args } = { } ) {
const command = ` npm view ${ args [ 'cli-package-name' ] } versions --json ` ;
2025-09-25 12:02:00 +08:00
try {
const versionsJson = execSync ( command ) . toString ( ) . trim ( ) ;
return JSON . parse ( versionsJson ) ;
} catch ( error ) {
console . error ( ` Failed to get all NPM versions: ${ error . message } ` ) ;
return [ ] ;
}
}
2025-10-18 02:08:27 +08:00
function isVersionDeprecated ( { args , version } = { } ) {
const command = ` npm view ${ args [ 'cli-package-name' ] } @ ${ version } deprecated ` ;
2025-09-27 07:35:26 +08:00
try {
const output = execSync ( command ) . toString ( ) . trim ( ) ;
return output . length > 0 ;
} catch ( error ) {
// This command shouldn't fail for existing versions, but as a safeguard:
2025-10-01 07:16:53 +08:00
console . error (
2025-09-27 07:35:26 +08:00
` Failed to check deprecation status for ${ version } : ${ error . message } ` ,
) ;
return false ; // Assume not deprecated on error to avoid breaking the release.
}
}
2025-10-18 02:08:27 +08:00
function detectRollbackAndGetBaseline ( { args , npmDistTag } = { } ) {
2025-09-25 12:02:00 +08:00
// Get the current dist-tag version
2025-10-18 02:08:27 +08:00
const distTagVersion = getVersionFromNPM ( { args , npmDistTag } ) ;
2025-09-25 12:02:00 +08:00
if ( ! distTagVersion ) return { baseline : '' , isRollback : false } ;
// Get all published versions
2025-10-18 02:08:27 +08:00
const allVersions = getAllVersionsFromNPM ( { args } ) ;
2025-09-25 12:02:00 +08:00
if ( allVersions . length === 0 )
return { baseline : distTagVersion , isRollback : false } ;
// Filter versions by type to match the dist-tag
let matchingVersions ;
2025-10-18 02:08:27 +08:00
if ( npmDistTag === TAG _LATEST ) {
2025-09-25 12:02:00 +08:00
// Stable versions: no prerelease identifiers
matchingVersions = allVersions . filter (
( v ) => semver . valid ( v ) && ! semver . prerelease ( v ) ,
) ;
2025-10-18 02:08:27 +08:00
} else if ( npmDistTag === TAG _PREVIEW ) {
2025-09-25 12:02:00 +08:00
// Preview versions: contain -preview
matchingVersions = allVersions . filter (
( v ) => semver . valid ( v ) && v . includes ( '-preview' ) ,
) ;
2025-10-18 02:08:27 +08:00
} else if ( npmDistTag === TAG _NIGHTLY ) {
2025-09-25 12:02:00 +08:00
// Nightly versions: contain -nightly
matchingVersions = allVersions . filter (
( v ) => semver . valid ( v ) && v . includes ( '-nightly' ) ,
) ;
} else {
// For other dist-tags, just use the dist-tag version
return { baseline : distTagVersion , isRollback : false } ;
}
if ( matchingVersions . length === 0 )
return { baseline : distTagVersion , isRollback : false } ;
2025-09-27 07:35:26 +08:00
// Sort by semver to get a list from highest to lowest
2025-09-25 12:02:00 +08:00
matchingVersions . sort ( ( a , b ) => semver . rcompare ( a , b ) ) ;
2025-09-27 07:35:26 +08:00
// Find the highest non-deprecated version
let highestExistingVersion = '' ;
for ( const version of matchingVersions ) {
2025-10-18 02:08:27 +08:00
if ( ! isVersionDeprecated ( { version , args } ) ) {
2025-09-27 07:35:26 +08:00
highestExistingVersion = version ;
break ; // Found the one we want
} else {
2025-10-01 07:16:53 +08:00
console . error ( ` Ignoring deprecated version: ${ version } ` ) ;
2025-09-27 07:35:26 +08:00
}
}
// If all matching versions were deprecated, fall back to the dist-tag version
if ( ! highestExistingVersion ) {
highestExistingVersion = distTagVersion ;
}
2025-09-25 12:02:00 +08:00
// Check if we're in a rollback scenario
const isRollback = semver . gt ( highestExistingVersion , distTagVersion ) ;
return {
baseline : isRollback ? highestExistingVersion : distTagVersion ,
isRollback ,
distTagVersion ,
highestExistingVersion ,
} ;
}
2025-10-18 02:08:27 +08:00
function doesVersionExist ( { args , version } = { } ) {
2025-09-27 07:35:26 +08:00
// Check NPM
2025-09-17 14:47:05 +08:00
try {
2025-10-18 02:08:27 +08:00
const command = ` npm view ${ args [ 'cli-package-name' ] } @ ${ version } version 2>/dev/null ` ;
2025-09-17 14:47:05 +08:00
const output = execSync ( command ) . toString ( ) . trim ( ) ;
2025-09-27 07:35:26 +08:00
if ( output === version ) {
2025-10-01 07:16:53 +08:00
console . error ( ` Version ${ version } already exists on NPM. ` ) ;
2025-09-27 07:35:26 +08:00
return true ;
2025-09-13 01:22:10 +08:00
}
2025-09-27 07:35:26 +08:00
} catch ( _error ) {
// This is expected if the version doesn't exist.
2025-09-25 12:02:00 +08:00
}
// Check Git tags
try {
2025-09-27 07:35:26 +08:00
const command = ` git tag -l 'v ${ version } ' ` ;
2025-09-25 12:02:00 +08:00
const tagOutput = execSync ( command ) . toString ( ) . trim ( ) ;
2025-09-27 07:35:26 +08:00
if ( tagOutput === ` v ${ version } ` ) {
2025-10-01 07:16:53 +08:00
console . error ( ` Git tag v ${ version } already exists. ` ) ;
2025-09-27 07:35:26 +08:00
return true ;
2025-09-25 12:02:00 +08:00
}
} catch ( error ) {
2025-10-01 07:16:53 +08:00
console . error ( ` Failed to check git tags for conflicts: ${ error . message } ` ) ;
2025-09-25 12:02:00 +08:00
}
// Check GitHub releases
try {
2025-09-27 07:35:26 +08:00
const command = ` gh release view "v ${ version } " --json tagName --jq .tagName 2>/dev/null ` ;
2025-09-25 12:02:00 +08:00
const output = execSync ( command ) . toString ( ) . trim ( ) ;
2025-09-27 07:35:26 +08:00
if ( output === ` v ${ version } ` ) {
2025-10-01 07:16:53 +08:00
console . error ( ` GitHub release v ${ version } already exists. ` ) ;
2025-09-27 07:35:26 +08:00
return true ;
2025-09-25 12:02:00 +08:00
}
} catch ( error ) {
const isExpectedNotFound =
error . message . includes ( 'release not found' ) ||
error . message . includes ( 'Not Found' ) ||
error . message . includes ( 'not found' ) ||
2025-09-27 07:35:26 +08:00
error . status === 1 ;
2025-09-25 12:02:00 +08:00
if ( ! isExpectedNotFound ) {
2025-10-01 07:16:53 +08:00
console . error (
2025-09-25 12:02:00 +08:00
` Failed to check GitHub releases for conflicts: ${ error . message } ` ,
) ;
}
}
2025-09-27 07:35:26 +08:00
return false ;
2025-09-25 12:02:00 +08:00
}
2025-10-18 02:08:27 +08:00
function getAndVerifyTags ( { npmDistTag , args } = { } ) {
2025-09-25 12:02:00 +08:00
// Detect rollback scenarios and get the correct baseline
2025-10-18 02:08:27 +08:00
const rollbackInfo = detectRollbackAndGetBaseline ( { args , npmDistTag } ) ;
2025-09-25 12:02:00 +08:00
const baselineVersion = rollbackInfo . baseline ;
if ( ! baselineVersion ) {
throw new Error ( ` Unable to determine baseline version for ${ npmDistTag } ` ) ;
}
2025-09-27 07:35:26 +08:00
if ( rollbackInfo . isRollback ) {
2025-09-25 12:02:00 +08:00
// Rollback scenario: warn about the rollback but don't fail
2025-10-01 07:16:53 +08:00
console . error (
2025-09-25 12:02:00 +08:00
` Rollback detected! NPM ${ npmDistTag } tag is ${ rollbackInfo . distTagVersion } , but using ${ baselineVersion } as baseline for next version calculation (highest existing version). ` ,
2025-09-17 14:47:05 +08:00
) ;
2025-07-06 04:58:59 +08:00
}
2025-09-25 12:02:00 +08:00
2025-09-27 07:35:26 +08:00
// Not verifying against git tags or GitHub releases as per user request.
2025-09-25 12:02:00 +08:00
return {
latestVersion : baselineVersion ,
latestTag : ` v ${ baselineVersion } ` ,
} ;
2025-09-17 14:47:05 +08:00
}
2025-11-08 05:06:55 +08:00
function getStableBaseVersion ( args ) {
let latestStableVersion = args [ 'stable-base-version' ] ;
if ( ! latestStableVersion ) {
const { latestVersion } = getAndVerifyTags ( {
npmDistTag : TAG _LATEST ,
args ,
} ) ;
latestStableVersion = latestVersion ;
}
return latestStableVersion ;
}
2025-10-18 02:08:27 +08:00
function promoteNightlyVersion ( { args } = { } ) {
2025-11-08 05:06:55 +08:00
const latestStableVersion = getStableBaseVersion ( args ) ;
const { latestTag : previousNightlyTag } = getAndVerifyTags ( {
2025-10-18 02:08:27 +08:00
npmDistTag : TAG _NIGHTLY ,
args ,
} ) ;
2025-11-08 05:06:55 +08:00
const major = semver . major ( latestStableVersion ) ;
const minor = semver . minor ( latestStableVersion ) ;
const nextMinor = minor + 2 ;
2025-09-17 14:47:05 +08:00
const date = new Date ( ) . toISOString ( ) . slice ( 0 , 10 ) . replace ( /-/g , '' ) ;
const gitShortHash = execSync ( 'git rev-parse --short HEAD' ) . toString ( ) . trim ( ) ;
return {
releaseVersion : ` ${ major } . ${ nextMinor } .0-nightly. ${ date } . ${ gitShortHash } ` ,
2025-10-18 02:08:27 +08:00
npmTag : TAG _NIGHTLY ,
2025-11-08 05:06:55 +08:00
previousReleaseTag : previousNightlyTag ,
2025-09-27 07:35:26 +08:00
} ;
}
function getNightlyVersion ( ) {
const packageJson = readJson ( 'package.json' ) ;
const baseVersion = packageJson . version . split ( '-' ) [ 0 ] ;
const date = new Date ( ) . toISOString ( ) . slice ( 0 , 10 ) . replace ( /-/g , '' ) ;
const gitShortHash = execSync ( 'git rev-parse --short HEAD' ) . toString ( ) . trim ( ) ;
const releaseVersion = ` ${ baseVersion } -nightly. ${ date } . ${ gitShortHash } ` ;
const previousReleaseTag = getLatestTag ( 'v*-nightly*' ) ;
return {
releaseVersion ,
2025-10-18 02:08:27 +08:00
npmTag : TAG _NIGHTLY ,
2025-09-27 07:35:26 +08:00
previousReleaseTag ,
2025-09-17 14:47:05 +08:00
} ;
}
2025-09-18 02:02:54 +08:00
function validateVersion ( version , format , name ) {
const versionRegex = {
'X.Y.Z' : /^\d+\.\d+\.\d+$/ ,
'X.Y.Z-preview.N' : /^\d+\.\d+\.\d+-preview\.\d+$/ ,
} ;
if ( ! versionRegex [ format ] || ! versionRegex [ format ] . test ( version ) ) {
throw new Error (
` Invalid ${ name } : ${ version } . Must be in ${ format } format. ` ,
) ;
}
}
function getStableVersion ( args ) {
2025-10-18 02:08:27 +08:00
const { latestVersion : latestPreviewVersion } = getAndVerifyTags ( {
npmDistTag : TAG _PREVIEW ,
args ,
} ) ;
2025-09-18 02:02:54 +08:00
let releaseVersion ;
2025-10-18 02:08:27 +08:00
if ( args [ 'stable_version_override' ] ) {
const overrideVersion = args [ 'stable_version_override' ] . replace ( /^v/ , '' ) ;
2025-09-18 02:02:54 +08:00
validateVersion ( overrideVersion , 'X.Y.Z' , 'stable_version_override' ) ;
releaseVersion = overrideVersion ;
} else {
releaseVersion = latestPreviewVersion . replace ( /-preview.*/ , '' ) ;
}
2025-10-18 02:08:27 +08:00
const { latestTag : previousStableTag } = getAndVerifyTags ( {
npmDistTag : TAG _LATEST ,
args ,
} ) ;
2025-09-18 02:02:54 +08:00
2025-09-17 14:47:05 +08:00
return {
2025-09-18 02:02:54 +08:00
releaseVersion ,
2025-10-18 02:08:27 +08:00
npmTag : TAG _LATEST ,
2025-09-18 02:02:54 +08:00
previousReleaseTag : previousStableTag ,
2025-09-17 14:47:05 +08:00
} ;
}
2025-07-06 04:58:59 +08:00
2025-09-18 02:02:54 +08:00
function getPreviewVersion ( args ) {
2025-11-08 05:06:55 +08:00
const latestStableVersion = getStableBaseVersion ( args ) ;
2025-09-18 02:02:54 +08:00
let releaseVersion ;
2025-10-18 02:08:27 +08:00
if ( args [ 'preview_version_override' ] ) {
const overrideVersion = args [ 'preview_version_override' ] . replace ( /^v/ , '' ) ;
2025-09-18 02:02:54 +08:00
validateVersion (
overrideVersion ,
'X.Y.Z-preview.N' ,
'preview_version_override' ,
) ;
releaseVersion = overrideVersion ;
} else {
2025-11-08 05:06:55 +08:00
const major = semver . major ( latestStableVersion ) ;
const minor = semver . minor ( latestStableVersion ) ;
const nextMinor = minor + 1 ;
releaseVersion = ` ${ major } . ${ nextMinor } .0-preview.0 ` ;
2025-09-18 02:02:54 +08:00
}
2025-10-18 02:08:27 +08:00
const { latestTag : previousPreviewTag } = getAndVerifyTags ( {
npmDistTag : TAG _PREVIEW ,
args ,
} ) ;
2025-09-18 02:02:54 +08:00
2025-09-17 14:47:05 +08:00
return {
2025-09-18 02:02:54 +08:00
releaseVersion ,
2025-10-18 02:08:27 +08:00
npmTag : TAG _PREVIEW ,
2025-09-18 02:02:54 +08:00
previousReleaseTag : previousPreviewTag ,
2025-09-17 14:47:05 +08:00
} ;
}
2025-08-20 23:50:00 +08:00
2025-10-18 02:08:27 +08:00
function getPatchVersion ( args ) {
const patchFrom = args [ 'patch-from' ] ;
if ( ! patchFrom || ( patchFrom !== 'stable' && patchFrom !== TAG _PREVIEW ) ) {
2025-09-17 14:47:05 +08:00
throw new Error (
'Patch type must be specified with --patch-from=stable or --patch-from=preview' ,
) ;
}
2025-10-18 02:08:27 +08:00
const distTag = patchFrom === 'stable' ? TAG _LATEST : TAG _PREVIEW ;
const { latestVersion , latestTag } = getAndVerifyTags ( {
npmDistTag : distTag ,
args ,
} ) ;
2025-09-19 08:33:08 +08:00
if ( patchFrom === 'stable' ) {
// For stable versions, increment the patch number: 0.5.4 -> 0.5.5
const versionParts = latestVersion . split ( '.' ) ;
const major = versionParts [ 0 ] ;
const minor = versionParts [ 1 ] ;
const patch = versionParts [ 2 ] ? parseInt ( versionParts [ 2 ] ) : 0 ;
const releaseVersion = ` ${ major } . ${ minor } . ${ patch + 1 } ` ;
return {
releaseVersion ,
npmTag : distTag ,
previousReleaseTag : latestTag ,
} ;
} else {
// For preview versions, increment the preview number: 0.6.0-preview.2 -> 0.6.0-preview.3
const [ version , prereleasePart ] = latestVersion . split ( '-' ) ;
if ( ! prereleasePart || ! prereleasePart . startsWith ( 'preview.' ) ) {
throw new Error (
` Invalid preview version format: ${ latestVersion } . Expected format like "0.6.0-preview.2" ` ,
) ;
}
const previewNumber = parseInt ( prereleasePart . split ( '.' ) [ 1 ] ) ;
if ( isNaN ( previewNumber ) ) {
throw new Error ( ` Could not parse preview number from: ${ prereleasePart } ` ) ;
}
const releaseVersion = ` ${ version } -preview. ${ previewNumber + 1 } ` ;
return {
releaseVersion ,
npmTag : distTag ,
previousReleaseTag : latestTag ,
} ;
}
2025-09-17 14:47:05 +08:00
}
export function getVersion ( options = { } ) {
const args = { ... getArgs ( ) , ... options } ;
2025-10-18 02:08:27 +08:00
const type = args [ 'type' ] || TAG _NIGHTLY ; // Nightly is the default.
2025-09-17 14:47:05 +08:00
let versionData ;
switch ( type ) {
2025-10-18 02:08:27 +08:00
case TAG _NIGHTLY :
2025-09-17 14:47:05 +08:00
versionData = getNightlyVersion ( ) ;
2025-09-27 07:35:26 +08:00
// Nightly versions include a git hash, so conflicts are highly unlikely
// and indicate a problem. We'll still validate but not auto-increment.
2025-10-18 02:08:27 +08:00
if ( doesVersionExist ( { args , version : versionData . releaseVersion } ) ) {
2025-09-27 07:35:26 +08:00
throw new Error (
` Version conflict! Nightly version ${ versionData . releaseVersion } already exists. ` ,
) ;
}
break ;
case 'promote-nightly' :
2025-10-23 00:45:42 +08:00
versionData = promoteNightlyVersion ( { args } ) ;
// A promoted nightly version is still a nightly, so we should check for conflicts.
if ( doesVersionExist ( { args , version : versionData . releaseVersion } ) ) {
throw new Error (
` Version conflict! Promoted nightly version ${ versionData . releaseVersion } already exists. ` ,
) ;
}
2025-09-17 14:47:05 +08:00
break ;
case 'stable' :
2025-09-18 02:02:54 +08:00
versionData = getStableVersion ( args ) ;
2025-09-17 14:47:05 +08:00
break ;
2025-10-18 02:08:27 +08:00
case TAG _PREVIEW :
2025-09-18 02:02:54 +08:00
versionData = getPreviewVersion ( args ) ;
2025-09-17 14:47:05 +08:00
break ;
case 'patch' :
2025-10-18 02:08:27 +08:00
versionData = getPatchVersion ( args ) ;
2025-09-17 14:47:05 +08:00
break ;
default :
throw new Error ( ` Unknown release type: ${ type } ` ) ;
}
2025-09-27 07:35:26 +08:00
// For patchable versions, check for existence and increment if needed.
2025-10-18 02:08:27 +08:00
if ( type === 'stable' || type === TAG _PREVIEW || type === 'patch' ) {
2025-09-27 07:35:26 +08:00
let releaseVersion = versionData . releaseVersion ;
2025-10-18 02:08:27 +08:00
while ( doesVersionExist ( { args , version : releaseVersion } ) ) {
2025-10-01 07:16:53 +08:00
console . error ( ` Version ${ releaseVersion } exists, incrementing. ` ) ;
2025-09-27 07:35:26 +08:00
if ( releaseVersion . includes ( '-preview.' ) ) {
// Increment preview number: 0.6.0-preview.2 -> 0.6.0-preview.3
const [ version , prereleasePart ] = releaseVersion . split ( '-' ) ;
const previewNumber = parseInt ( prereleasePart . split ( '.' ) [ 1 ] ) ;
releaseVersion = ` ${ version } -preview. ${ previewNumber + 1 } ` ;
} else {
// Increment patch number: 0.5.4 -> 0.5.5
const versionParts = releaseVersion . split ( '.' ) ;
const major = versionParts [ 0 ] ;
const minor = versionParts [ 1 ] ;
const patch = parseInt ( versionParts [ 2 ] ) ;
releaseVersion = ` ${ major } . ${ minor } . ${ patch + 1 } ` ;
}
}
versionData . releaseVersion = releaseVersion ;
}
2025-09-25 12:02:00 +08:00
2025-09-27 07:35:26 +08:00
// All checks are done, construct the final result.
2025-09-25 12:02:00 +08:00
const result = {
2025-09-17 14:47:05 +08:00
releaseTag : ` v ${ versionData . releaseVersion } ` ,
... versionData ,
2025-09-10 16:28:58 +08:00
} ;
2025-09-25 12:02:00 +08:00
return result ;
2025-07-06 04:58:59 +08:00
}
2025-09-10 16:28:58 +08:00
if ( process . argv [ 1 ] === fileURLToPath ( import . meta . url ) ) {
2025-09-17 14:47:05 +08:00
console . log ( JSON . stringify ( getVersion ( getArgs ( ) ) , null , 2 ) ) ;
2025-07-06 04:58:59 +08:00
}