@@ -26,6 +26,7 @@ const path = require('path');
2626const fs = require ( 'fs' ) ;
2727const https = require ( 'https' ) ;
2828const http = require ( 'http' ) ;
29+ const { execSync } = require ( 'child_process' ) ;
2930
3031// Parse command line arguments
3132const args = process . argv . slice ( 2 ) ;
@@ -310,48 +311,102 @@ async function queryRegistryVersion(packageName, repository, repositoryUrl) {
310311 return null ;
311312}
312313
314+ /**
315+ * Get global npm prefix for module resolution.
316+ * This helps find globally installed npm packages.
317+ * @returns {string|null } Path to global node_modules or null if not found
318+ */
319+ function getGlobalNpmPrefix ( ) {
320+ try {
321+ // Get npm's global prefix (where global packages are installed)
322+ const prefix = execSync ( 'npm config get prefix' , { encoding : 'utf8' } ) . trim ( ) ;
323+ // Global node_modules is typically at <prefix>/lib/node_modules
324+ const globalNodeModules = path . join ( prefix , 'lib' , 'node_modules' ) ;
325+ if ( fs . existsSync ( globalNodeModules ) ) {
326+ return globalNodeModules ;
327+ }
328+ // Alternative location on some systems
329+ const altGlobalNodeModules = path . join ( prefix , 'node_modules' ) ;
330+ if ( fs . existsSync ( altGlobalNodeModules ) ) {
331+ return altGlobalNodeModules ;
332+ }
333+ return null ;
334+ } catch ( e ) {
335+ // If npm config fails, try to find it via NODE_PATH or common locations
336+ return null ;
337+ }
338+ }
339+
313340// Main execution
314341( async ( ) => {
315342 try {
343+ // Get global npm path for module resolution
344+ const globalNpmPath = getGlobalNpmPrefix ( ) ;
345+ const resolvePaths = [ projectRoot ] ;
346+ if ( globalNpmPath ) {
347+ resolvePaths . push ( globalNpmPath ) ;
348+ }
349+
316350 // Try to require semantic-release
317- // First try resolving from project root (for devDependencies), then fall back to global
351+ // First try resolving from project root (for devDependencies), then try global, then fall back to default
318352 let semanticRelease ;
319- try {
320- const semanticReleasePath = require . resolve ( 'semantic-release' , { paths : [ projectRoot ] } ) ;
321- semanticRelease = require ( semanticReleasePath ) ;
322- } catch ( resolveError ) {
323353 try {
324- semanticRelease = require ( 'semantic-release' ) ;
325- } catch ( e ) {
326- console . error ( 'Error: semantic-release is not installed.' ) ;
327- console . error ( 'Please install it with: npm install -g semantic-release' ) ;
328- console . error ( 'Or install it as a devDependency: npm install --save-dev semantic-release' ) ;
329- if ( isSubfolderBuild ) {
330- console . error ( 'For subfolder builds, also install: npm install -g semantic-release-commit-filter' ) ;
331- console . error ( 'Or as devDependency: npm install --save-dev semantic-release-commit-filter' ) ;
354+ const semanticReleasePath = require . resolve ( 'semantic-release' , { paths : resolvePaths } ) ;
355+ semanticRelease = require ( semanticReleasePath ) ;
356+ } catch ( resolveError ) {
357+ try {
358+ // Try with just global path
359+ if ( globalNpmPath ) {
360+ const semanticReleasePath = require . resolve ( 'semantic-release' , { paths : [ globalNpmPath ] } ) ;
361+ semanticRelease = require ( semanticReleasePath ) ;
362+ } else {
363+ throw resolveError ;
364+ }
365+ } catch ( globalError ) {
366+ try {
367+ // Final fallback: default require (should work if in NODE_PATH or default locations)
368+ semanticRelease = require ( 'semantic-release' ) ;
369+ } catch ( e ) {
370+ console . error ( 'Error: semantic-release is not installed.' ) ;
371+ console . error ( 'Please install it with: npm install -g semantic-release' ) ;
372+ console . error ( 'Or install it as a devDependency: npm install --save-dev semantic-release' ) ;
373+ if ( isSubfolderBuild ) {
374+ console . error ( 'For subfolder builds, also install: npm install -g semantic-release-commit-filter' ) ;
375+ console . error ( 'Or as devDependency: npm install --save-dev semantic-release-commit-filter' ) ;
376+ }
377+ process . exit ( 1 ) ;
378+ }
332379 }
333- process . exit ( 1 ) ;
334380 }
335- }
336381
337- // For subfolder builds, require semantic-release-commit-filter
338- // (required only to verify it's installed; the plugin is used via options.plugins)
339- // First try resolving from project root (for devDependencies), then fall back to global
340- if ( isSubfolderBuild ) {
341- try {
342- const commitFilterPath = require . resolve ( 'semantic-release-commit-filter' , { paths : [ projectRoot ] } ) ;
343- require ( commitFilterPath ) ;
344- } catch ( resolveError ) {
382+ // For subfolder builds, require semantic-release-commit-filter
383+ // (required only to verify it's installed; the plugin is used via options.plugins)
384+ if ( isSubfolderBuild ) {
345385 try {
346- require ( 'semantic-release-commit-filter' ) ;
347- } catch ( e ) {
348- console . error ( 'Error: semantic-release-commit-filter is not installed.' ) ;
349- console . error ( 'Please install it with: npm install -g semantic-release-commit-filter' ) ;
350- console . error ( 'Or install it as a devDependency: npm install --save-dev semantic-release-commit-filter' ) ;
351- process . exit ( 1 ) ;
386+ const commitFilterPath = require . resolve ( 'semantic-release-commit-filter' , { paths : resolvePaths } ) ;
387+ require ( commitFilterPath ) ;
388+ } catch ( resolveError ) {
389+ try {
390+ // Try with just global path
391+ if ( globalNpmPath ) {
392+ const commitFilterPath = require . resolve ( 'semantic-release-commit-filter' , { paths : [ globalNpmPath ] } ) ;
393+ require ( commitFilterPath ) ;
394+ } else {
395+ throw resolveError ;
396+ }
397+ } catch ( globalError ) {
398+ try {
399+ // Final fallback: default require
400+ require ( 'semantic-release-commit-filter' ) ;
401+ } catch ( e ) {
402+ console . error ( 'Error: semantic-release-commit-filter is not installed.' ) ;
403+ console . error ( 'Please install it with: npm install -g semantic-release-commit-filter' ) ;
404+ console . error ( 'Or install it as a devDependency: npm install --save-dev semantic-release-commit-filter' ) ;
405+ process . exit ( 1 ) ;
406+ }
407+ }
352408 }
353409 }
354- }
355410
356411 // Query registry for latest version if repository info is provided
357412 let registryVersion = null ;
0 commit comments