Skip to content

Commit 9d697c7

Browse files
committed
chore: wip
1 parent e3b3a40 commit 9d697c7

File tree

6 files changed

+298
-46
lines changed

6 files changed

+298
-46
lines changed

packages/launchpad/bin/cli.ts

Lines changed: 45 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -519,44 +519,48 @@ async function setupDevelopmentEnvironment(
519519
}
520520

521521
/**
522-
* Create symlinks for global binaries to ~/.local/bin
522+
* Install specific packages globally
523523
*/
524-
async function createGlobalBinarySymlinks(globalEnvDir: string): Promise<void> {
524+
async function installPackagesGlobally(packages: string[], options: { verbose?: boolean, quiet?: boolean }): Promise<void> {
525525
try {
526-
const globalBinDir = path.join(globalEnvDir, 'bin')
527-
const localBinDir = path.join(homedir(), '.local', 'bin')
526+
const { install } = await import('../src/install-main')
528527

529-
// Ensure ~/.local/bin exists
530-
await fs.promises.mkdir(localBinDir, { recursive: true })
528+
// Install to global directory
529+
const globalEnvDir = path.join(homedir(), '.local', 'share', 'launchpad', 'global')
531530

532-
if (!fs.existsSync(globalBinDir)) {
533-
return // No global binaries to link
531+
if (!options.quiet) {
532+
console.log(`Installing ${packages.length} package${packages.length === 1 ? '' : 's'} globally...`)
534533
}
535534

536-
const binaries = await fs.promises.readdir(globalBinDir)
535+
const results = await install(packages, globalEnvDir)
537536

538-
for (const binary of binaries) {
539-
const sourcePath = path.join(globalBinDir, binary)
540-
const targetPath = path.join(localBinDir, binary)
537+
// Create global binary symlinks
538+
const { createGlobalBinarySymlinks } = await import('../src/install-helpers')
539+
await createGlobalBinarySymlinks(globalEnvDir)
541540

542-
// Skip if source is not a file or symlink
543-
const stats = await fs.promises.lstat(sourcePath)
544-
if (!stats.isFile() && !stats.isSymbolicLink()) {
545-
continue
546-
}
541+
// Ensure shell integration is installed for current user
542+
await ensureShellIntegrationInstalled()
543+
// Ensure post-install hooks are present and signal shell to refresh
544+
ensurePostInstallHooks()
545+
triggerShellGlobalRefresh()
547546

548-
// Remove existing symlink if it exists
549-
if (fs.existsSync(targetPath)) {
550-
await fs.promises.unlink(targetPath)
547+
if (!options.quiet) {
548+
if (results.length > 0) {
549+
console.log(`🎉 Successfully installed ${packages.join(', ')} globally (${results.length} ${results.length === 1 ? 'binary' : 'binaries'})`)
550+
results.forEach((file) => {
551+
console.log(` ${file}`)
552+
})
553+
}
554+
else {
555+
console.log('✅ All specified packages were already installed globally')
551556
}
552-
553-
// Create new symlink
554-
await fs.promises.symlink(sourcePath, targetPath)
555557
}
556558
}
557559
catch (error) {
558-
// Don't fail the whole installation if symlink creation fails
559-
console.warn('⚠️ Warning: Failed to create global binary symlinks:', error)
560+
if (!options.quiet) {
561+
console.error('❌ Failed to install packages globally:', error instanceof Error ? error.message : String(error))
562+
}
563+
process.exit(1)
560564
}
561565
}
562566

@@ -905,7 +909,7 @@ cli
905909
.alias('add')
906910
.option('--verbose', 'Enable verbose output')
907911
.option('--path <path>', 'Custom installation path')
908-
.option('-g, --global-deps', 'Install all global dependencies found across the machine')
912+
.option('-g, --global', 'Install packages globally (or scan for all global dependencies if no packages specified)')
909913
.option('--deps-only', 'Install only the dependencies of packages, not the packages themselves')
910914
.option('--dry-run', 'Show packages that would be installed without installing them')
911915
.option('--quiet', 'Suppress non-error output')
@@ -915,12 +919,13 @@ cli
915919
.example('launchpad install php --deps-only')
916920
.example('launchpad install')
917921
.example('launchpad install ./my-project')
918-
.example('launchpad install --global-deps')
922+
.example('launchpad install -g')
923+
.example('launchpad install starship -g')
919924
.example('launchpad add node python')
920925
.action(async (packages: string[], options: {
921926
verbose?: boolean
922927
path?: string
923-
globalDeps?: boolean
928+
global?: boolean
924929
depsOnly?: boolean
925930
dryRun?: boolean
926931
quiet?: boolean
@@ -934,10 +939,18 @@ cli
934939
const packageList = Array.isArray(packages) ? packages : [packages].filter(Boolean)
935940

936941
try {
937-
// Handle global dependencies installation
938-
if (options.globalDeps) {
939-
await installGlobalDependencies(options)
940-
return
942+
// Handle global installation
943+
if (options.global) {
944+
if (packageList.length === 0) {
945+
// No packages specified - scan for all global dependencies (old behavior)
946+
await installGlobalDependencies(options)
947+
return
948+
}
949+
else {
950+
// Packages specified - install them globally
951+
await installPackagesGlobally(packageList, options)
952+
return
953+
}
941954
}
942955

943956
// Handle dependencies-only installation

packages/launchpad/src/dev/shellcode.ts

Lines changed: 65 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ if [[ "$LAUNCHPAD_DISABLE_SHELL_INTEGRATION" == "1"${testModeCheck} ]]; then
3030
return 0 2>/dev/null || exit 0
3131
fi
3232
33+
# Skip shell integration during initial shell startup to avoid interfering with prompt initialization
34+
# This prevents conflicts with starship and other prompt systems during .zshrc loading
35+
if [[ "$LAUNCHPAD_SKIP_INITIAL_INTEGRATION" == "1" ]]; then
36+
return 0 2>/dev/null || exit 0
37+
fi
38+
3339
# Set up directory change hooks for zsh and bash (do this first, before any processing guards)
3440
if [[ -n "$ZSH_VERSION" ]]; then
3541
# zsh hook
@@ -79,9 +85,22 @@ fi
7985
8086
# Environment switching function (called by hooks)
8187
__launchpad_switch_environment() {
88+
# Start timer for performance tracking
89+
local start_time=$(date +%s%3N 2>/dev/null || echo "0")
90+
91+
# Check if verbose mode is enabled
92+
local verbose_mode="${verboseDefault}"
93+
if [[ -n "$LAUNCHPAD_VERBOSE" ]]; then
94+
verbose_mode="$LAUNCHPAD_VERBOSE"
95+
fi
96+
97+
if [[ "$verbose_mode" == "true" ]]; then
98+
printf "⏱️ [0ms] Shell integration started for PWD=%s\\n" "$PWD" >&2
99+
fi
100+
82101
# Step 1: Find project directory using our fast binary (with timeout)
83102
local project_dir=""
84-
if timeout 0.5s ${launchpadBinary} dev:find-project-root "$PWD" 2>/dev/null; then
103+
if timeout 0.5s ${launchpadBinary} dev:find-project-root "$PWD" >/dev/null 2>&1; then
85104
project_dir=$(LAUNCHPAD_DISABLE_SHELL_INTEGRATION=1 timeout 0.5s ${launchpadBinary} dev:find-project-root "$PWD" 2>/dev/null || echo "")
86105
fi
87106
@@ -91,6 +110,39 @@ __launchpad_switch_environment() {
91110
export PATH="$global_bin:$PATH"
92111
fi
93112
113+
# Step 2.1: Check for global refresh marker and initialize newly available tools
114+
local refresh_marker="$HOME/.cache/launchpad/shell_cache/global_refresh_needed"
115+
if [[ -f "$refresh_marker" ]]; then
116+
# Remove the marker file
117+
rm -f "$refresh_marker" 2>/dev/null || true
118+
119+
# Re-initialize tools that may have just become available
120+
# This mirrors the conditional checks typically found in shell configs
121+
122+
# Skip starship initialization - let user's shell config handle it
123+
# This prevents conflicts with user's own starship configuration
124+
# if command -v starship >/dev/null 2>&1 && [[ -z "$STARSHIP_SHELL" ]]; then
125+
# if [[ -n "$ZSH_VERSION" ]]; then
126+
# eval "$(starship init zsh 2>/dev/null || true)"
127+
# elif [[ -n "$BASH_VERSION" ]]; then
128+
# eval "$(starship init bash 2>/dev/null || true)"
129+
# fi
130+
# fi
131+
132+
# Refresh command hash table to pick up new binaries
133+
hash -r 2>/dev/null || true
134+
135+
# Rehash for zsh to pick up new commands
136+
if [[ -n "$ZSH_VERSION" ]]; then
137+
rehash 2>/dev/null || true
138+
fi
139+
140+
# Show refresh message if verbose
141+
if [[ "$verbose_mode" == "true" ]]; then
142+
printf "🔄 Shell environment refreshed for newly installed tools\\n" >&2
143+
fi
144+
fi
145+
94146
# If no project found, check if we need to deactivate current project
95147
if [[ -z "$project_dir" ]]; then
96148
# If we were in a project but now we're not, deactivate it
@@ -149,7 +201,7 @@ __launchpad_switch_environment() {
149201
# If environment exists, activate it
150202
if [[ -d "$env_dir/bin" ]]; then
151203
export LAUNCHPAD_CURRENT_PROJECT="$project_dir"
152-
export LAUNCHPAD_ENV_BIN_PATH="$env_dir/bin"
204+
export LAUNCHPAD_ENV_BIN_PATH="$env_dir/bin"
153205
export PATH="$env_dir/bin:$PATH"
154206
155207
# Show activation message if enabled
@@ -161,7 +213,7 @@ __launchpad_switch_environment() {
161213
# Use LAUNCHPAD_SHELL_INTEGRATION=1 to enable proper progress display
162214
if LAUNCHPAD_DISABLE_SHELL_INTEGRATION=1 LAUNCHPAD_SHELL_INTEGRATION=1 timeout 30s ${launchpadBinary} install "$project_dir"; then
163215
# If install succeeded, try to activate the environment
164-
if [[ -d "$env_dir/bin" ]]; then
216+
if [[ -d "$env_dir/bin" ]]; then
165217
export LAUNCHPAD_CURRENT_PROJECT="$project_dir"
166218
export LAUNCHPAD_ENV_BIN_PATH="$env_dir/bin"
167219
export PATH="$env_dir/bin:$PATH"
@@ -174,6 +226,15 @@ __launchpad_switch_environment() {
174226
fi
175227
fi
176228
fi
229+
230+
# Show completion time if verbose
231+
if [[ "$verbose_mode" == "true" ]]; then
232+
local end_time=$(date +%s%3N 2>/dev/null || echo "0")
233+
local elapsed=$((end_time - start_time))
234+
if [[ "$elapsed" -gt 0 ]]; then
235+
printf "⏱️ [%sms] Shell integration completed\\n" "$elapsed" >&2
236+
fi
237+
fi
177238
}
178239
179240
# CRITICAL: Prevent infinite loops - if we're already processing, exit immediately
@@ -186,17 +247,7 @@ export __LAUNCHPAD_PROCESSING=1
186247
trap 'unset __LAUNCHPAD_PROCESSING 2>/dev/null || true' EXIT
187248
188249
# Basic shell integration with aggressive safeguards
189-
# Use verbose default if LAUNCHPAD_VERBOSE is not explicitly set
190-
local verbose_mode="${verboseDefault}"
191-
if [[ -n "$LAUNCHPAD_VERBOSE" ]]; then
192-
verbose_mode="$LAUNCHPAD_VERBOSE"
193-
fi
194-
195-
if [[ "$verbose_mode" == "true" ]]; then
196-
printf "⏱️ [0s] Shell integration started for PWD=%s\\n" "$PWD" >&2
197-
fi
198-
199-
# Run the environment switching logic
250+
# Run the environment switching logic (which handles its own timing)
200251
__launchpad_switch_environment
201252
202253
# Clean up processing flag before exit

0 commit comments

Comments
 (0)