@@ -4,7 +4,6 @@ import fs from 'node:fs'
4
4
import { homedir } from 'node:os'
5
5
import path from 'node:path'
6
6
import process from 'node:process'
7
- import { parse } from 'yaml'
8
7
import { config } from '../config'
9
8
import { findDependencyFile } from '../env'
10
9
import { cleanupSpinner , install } from '../install'
@@ -426,21 +425,21 @@ export async function dump(dir: string, options: DumpOptions = {}): Promise<void
426
425
// Fast path for shell output: check if environments exist and have binaries
427
426
// Skip fast path in test mode to ensure proper package discovery
428
427
if ( shellOutput && process . env . NODE_ENV !== 'test' ) {
429
- const fastProjectHash = generateProjectHash ( dir )
430
- const fastEnvDir = path . join ( process . env . HOME || '' , '.local' , 'share' , 'launchpad' , fastProjectHash )
431
- const fastGlobalEnvDir = path . join ( process . env . HOME || '' , '.local' , 'share' , 'launchpad' , 'global' )
432
-
433
- const envBinPath = path . join ( fastEnvDir , 'bin' )
434
- const envSbinPath = path . join ( fastEnvDir , 'sbin' )
435
- const globalBinPath = path . join ( fastGlobalEnvDir , 'bin' )
436
- const globalSbinPath = path . join ( fastGlobalEnvDir , 'sbin' )
437
-
438
- const hasLocalBinaries = fs . existsSync ( envBinPath ) && fs . readdirSync ( envBinPath ) . length > 0
439
- const hasGlobalBinaries = fs . existsSync ( globalBinPath ) && fs . readdirSync ( globalBinPath ) . length > 0
440
-
441
428
// Fast path disabled - always do proper constraint checking to ensure correct versions
442
429
// The fast path was causing issues where global binaries would activate environments
443
430
// even when local packages weren't properly installed
431
+ //
432
+ // const fastProjectHash = generateProjectHash(dir)
433
+ // const fastEnvDir = path.join(process.env.HOME || '', '.local', 'share', 'launchpad', fastProjectHash)
434
+ // const fastGlobalEnvDir = path.join(process.env.HOME || '', '.local', 'share', 'launchpad', 'global')
435
+ // const envBinPath = path.join(fastEnvDir, 'bin')
436
+ // const envSbinPath = path.join(fastEnvDir, 'sbin')
437
+ // const globalBinPath = path.join(fastGlobalEnvDir, 'bin')
438
+ // const globalSbinPath = path.join(fastGlobalEnvDir, 'sbin')
439
+ //
440
+ // const hasLocalBinaries = fs.existsSync(envBinPath) && fs.readdirSync(envBinPath).length > 0
441
+ // const hasGlobalBinaries = fs.existsSync(globalBinPath) && fs.readdirSync(globalBinPath).length > 0
442
+ //
444
443
// if (hasLocalBinaries || hasGlobalBinaries) {
445
444
// outputShellCode(dir, envBinPath, envSbinPath, fastProjectHash, minimalSniffResult, globalBinPath, globalSbinPath)
446
445
// return
@@ -683,7 +682,7 @@ export async function dump(dir: string, options: DumpOptions = {}): Promise<void
683
682
return
684
683
}
685
684
686
- // For shell output mode, handle different scenarios
685
+ // For shell output mode, handle different scenarios
687
686
if ( shellOutput ) {
688
687
const hasLocalPackagesInstalled = localReady || localPackages . length === 0
689
688
const hasGlobalPackagesInstalled = globalReady || globalPackages . length === 0
@@ -698,35 +697,42 @@ export async function dump(dir: string, options: DumpOptions = {}): Promise<void
698
697
const hasOptionalGlobalMissing = globalReadyResult . missingPackages && globalReadyResult . missingPackages . length > 0
699
698
const coreGlobalSatisfied = globalConstraintsSatisfied || ( hasOptionalGlobalMissing && globalPackages . length > 0 )
700
699
700
+ // Check if we're being called from shell integration
701
+ const isShellIntegration = process . env . LAUNCHPAD_SHELL_INTEGRATION === '1'
702
+
701
703
if ( hasLocalPackagesInstalled && hasGlobalPackagesInstalled ) {
702
704
// Ideal case: all packages properly installed
703
705
outputShellCode ( dir , envBinPath , envSbinPath , projectHash , sniffResult , globalBinPath , globalSbinPath )
704
706
return
705
707
}
706
- else if ( coreLocalSatisfied && coreGlobalSatisfied ) {
707
- // Fallback case: core constraints satisfied by system binaries, but warn user
708
- if ( ! hasLocalPackagesInstalled && localPackages . length > 0 ) {
709
- process . stderr . write ( `⚠️ Local packages not installed but constraints satisfied by system binaries\n` )
710
- process . stderr . write ( `💡 Run 'launchpad dev .' to install proper versions: ${ localPackages . join ( ', ' ) } \n` )
711
- }
712
- if ( ! hasGlobalPackagesInstalled && hasOptionalGlobalMissing ) {
713
- const missingGlobalPkgs = globalReadyResult . missingPackages ?. map ( p => p . project ) || [ ]
714
- process . stderr . write ( `⚠️ Some global packages not available: ${ missingGlobalPkgs . join ( ', ' ) } \n` )
715
- process . stderr . write ( `💡 Install missing global packages if needed\n` )
716
- }
717
- outputShellCode ( dir , envBinPath , envSbinPath , projectHash , sniffResult , globalBinPath , globalSbinPath )
718
- return
719
- }
708
+ else if ( coreLocalSatisfied && coreGlobalSatisfied ) {
709
+ // Fallback case: core constraints satisfied by system binaries, but warn user
710
+ if ( ! isShellIntegration ) {
711
+ if ( ! hasLocalPackagesInstalled && localPackages . length > 0 ) {
712
+ process . stderr . write ( `⚠️ Local packages not installed but constraints satisfied by system binaries\n` )
713
+ process . stderr . write ( `💡 Run 'launchpad dev .' to install proper versions: ${ localPackages . join ( ', ' ) } \n` )
714
+ }
715
+ if ( ! hasGlobalPackagesInstalled && hasOptionalGlobalMissing ) {
716
+ const missingGlobalPkgs = globalReadyResult . missingPackages ?. map ( p => p . project ) || [ ]
717
+ process . stderr . write ( `⚠️ Some global packages not available: ${ missingGlobalPkgs . join ( ', ' ) } \n` )
718
+ process . stderr . write ( `💡 Install missing global packages if needed\n` )
719
+ }
720
+ }
721
+ outputShellCode ( dir , envBinPath , envSbinPath , projectHash , sniffResult , globalBinPath , globalSbinPath )
722
+ return
723
+ }
720
724
else {
721
725
// No fallback available - but still generate shell code for development workflows
722
- process . stderr . write ( `❌ Environment not ready: local=${ localReady } , global=${ globalReady } \n` )
723
- if ( ! localReady && localPackages . length > 0 ) {
724
- process . stderr . write ( `💡 Local packages need installation: ${ localPackages . join ( ', ' ) } \n` )
725
- }
726
- if ( ! globalReady && globalPackages . length > 0 ) {
727
- process . stderr . write ( `💡 Global packages need installation: ${ globalPackages . join ( ', ' ) } \n` )
726
+ if ( ! isShellIntegration ) {
727
+ process . stderr . write ( `❌ Environment not ready: local=${ localReady } , global=${ globalReady } \n` )
728
+ if ( ! localReady && localPackages . length > 0 ) {
729
+ process . stderr . write ( `💡 Local packages need installation: ${ localPackages . join ( ', ' ) } \n` )
730
+ }
731
+ if ( ! globalReady && globalPackages . length > 0 ) {
732
+ process . stderr . write ( `💡 Global packages need installation: ${ globalPackages . join ( ', ' ) } \n` )
733
+ }
734
+ process . stderr . write ( `⚠️ Generating minimal shell environment for development\n` )
728
735
}
729
- process . stderr . write ( `⚠️ Generating minimal shell environment for development\n` )
730
736
731
737
// Generate basic shell code even when packages aren't installed
732
738
// This allows development workflows to continue with system binaries
@@ -743,20 +749,21 @@ export async function dump(dir: string, options: DumpOptions = {}): Promise<void
743
749
if ( globalPackages . length > 0 && ! skipGlobal ) {
744
750
const originalVerbose = config . verbose
745
751
const originalShowShellMessages = config . showShellMessages
752
+ const isShellIntegration = process . env . LAUNCHPAD_SHELL_INTEGRATION === '1'
746
753
747
- if ( shellOutput ) {
754
+ if ( shellOutput && ! isShellIntegration ) {
748
755
config . showShellMessages = false
749
756
process . stderr . write ( `🌍 Installing global dependencies...\n` )
750
757
}
751
- else if ( ! quiet ) {
758
+ else if ( ! quiet && ! isShellIntegration ) {
752
759
console . log ( `🌍 Installing ${ globalPackages . length } global packages...` )
753
760
}
754
761
755
762
try {
756
763
// If global environment is already ready, just create/update stubs
757
764
if ( globalReady ) {
758
765
await createGlobalStubs ( globalEnvDir , globalPackages )
759
- if ( shellOutput ) {
766
+ if ( shellOutput && ! isShellIntegration ) {
760
767
process . stderr . write ( `✅ Global dependencies ready\n` )
761
768
}
762
769
}
@@ -768,13 +775,13 @@ export async function dump(dir: string, options: DumpOptions = {}): Promise<void
768
775
// Create or update global stubs in system locations (/usr/local/bin)
769
776
await createGlobalStubs ( globalEnvDir , globalPackages )
770
777
771
- if ( shellOutput ) {
778
+ if ( shellOutput && ! isShellIntegration ) {
772
779
process . stderr . write ( `✅ Global dependencies installed\n` )
773
780
}
774
781
}
775
782
}
776
783
catch ( error ) {
777
- if ( shellOutput ) {
784
+ if ( shellOutput ) {
778
785
process . stderr . write ( `❌ Failed to install global packages: ${ error instanceof Error ? error . message : String ( error ) } \n` )
779
786
780
787
// Don't mislead users about system binary usage
@@ -800,8 +807,9 @@ export async function dump(dir: string, options: DumpOptions = {}): Promise<void
800
807
if ( localPackages . length > 0 && ! localReady ) {
801
808
const originalVerbose = config . verbose
802
809
const originalShowShellMessages = config . showShellMessages
810
+ const isShellIntegration = process . env . LAUNCHPAD_SHELL_INTEGRATION === '1'
803
811
804
- if ( shellOutput ) {
812
+ if ( shellOutput && ! isShellIntegration ) {
805
813
config . showShellMessages = false
806
814
const projectName = path . basename ( dir )
807
815
const startTime = Date . now ( )
@@ -896,22 +904,28 @@ export async function dump(dir: string, options: DumpOptions = {}): Promise<void
896
904
// Determine environment state for better messaging
897
905
const hasInstallationFailures = localInstallationFailed || globalInstallationFailed
898
906
const hasRequiredPackages = localPackages . length > 0 || globalPackages . length > 0
899
- const systemBinariesSatisfyConstraints = ( localReadyResult . missingPackages ?. length === 0 ) &&
900
- ( globalReadyResult . missingPackages ?. length === 0 )
901
-
902
- if ( ! hasInstallationFailures && hasRequiredPackages ) {
907
+ const systemBinariesSatisfyConstraints = ( localReadyResult . missingPackages ?. length === 0 )
908
+ && ( globalReadyResult . missingPackages ?. length === 0 )
909
+
910
+ if ( hasInstallationFailures ) {
911
+ // Handle installation failures first
912
+ if ( systemBinariesSatisfyConstraints ) {
913
+ // Fallback case: installations failed but system binaries work
914
+ process . stderr . write ( `⚠️ Environment activated with system binaries (installations failed)\n` )
915
+ process . stderr . write ( `💡 Some packages may not be the exact requested versions\n` )
916
+ }
917
+ else {
918
+ // Bad case: installations failed and system doesn't satisfy requirements
919
+ process . stderr . write ( `❌ Environment activation failed - required packages unavailable\n` )
920
+ process . stderr . write ( `💡 Fix installation issues and try again\n` )
921
+ // Still generate basic shell code for development workflows with global dependencies
922
+ }
923
+ }
924
+ else if ( hasRequiredPackages ) {
903
925
// Perfect case: all packages installed successfully
904
926
process . stderr . write ( `✅ Environment activated for ${ path . basename ( dir ) } \n` )
905
- } else if ( hasInstallationFailures && systemBinariesSatisfyConstraints ) {
906
- // Fallback case: installations failed but system binaries work
907
- process . stderr . write ( `⚠️ Environment activated with system binaries (installations failed)\n` )
908
- process . stderr . write ( `💡 Some packages may not be the exact requested versions\n` )
909
- } else if ( hasInstallationFailures ) {
910
- // Bad case: installations failed and system doesn't satisfy requirements
911
- process . stderr . write ( `❌ Environment activation failed - required packages unavailable\n` )
912
- process . stderr . write ( `💡 Fix installation issues and try again\n` )
913
- return // Don't generate shell code if critical packages are missing
914
- } else {
927
+ }
928
+ else {
915
929
// No packages needed or already satisfied
916
930
process . stderr . write ( `✅ Environment ready for ${ path . basename ( dir ) } \n` )
917
931
}
0 commit comments