@@ -540,24 +540,102 @@ __launchpad_chpwd() {
540
540
printf "⏱️ [0s] Shell integration started for PWD=%s\n" "$PWD" >&2
541
541
fi
542
542
543
+ # Simple dependency change detection: check if deps file is newer than our cache
544
+ if [[ -n "$LAUNCHPAD_CURRENT_PROJECT" && "$PWD" == "$LAUNCHPAD_CURRENT_PROJECT"* ]]; then
545
+ local deps_file="$(__launchpad_find_dependency_file_path "$LAUNCHPAD_CURRENT_PROJECT" 2>/dev/null)"
546
+ if [[ -n "$deps_file" && -f "$deps_file" ]]; then
547
+ local cache_marker="$HOME/.cache/launchpad/shell_cache/project_\${LAUNCHPAD_CURRENT_PROJECT//\//_}"
548
+
549
+ # If deps file is newer than our cache marker, dependencies may have changed
550
+ if [[ ! -f "$cache_marker" || "$deps_file" -nt "$cache_marker" ]]; then
551
+ if [[ "$LAUNCHPAD_VERBOSE" == "true" ]]; then
552
+ printf "⏱️ [0s] Dependency file changed, clearing cache\n" >&2
553
+ fi
554
+ # Clear the current project to force a fresh setup
555
+ unset LAUNCHPAD_CURRENT_PROJECT
556
+ # Update cache marker
557
+ mkdir -p "$(dirname "$cache_marker")" 2>/dev/null
558
+ touch "$cache_marker" 2>/dev/null
559
+ fi
560
+ fi
561
+ fi
562
+
543
563
local project_dir
544
564
545
565
# Super-fast path: if we're already in the same project, skip file search entirely
546
566
if [[ -n "$LAUNCHPAD_CURRENT_PROJECT" && "$PWD" == "$LAUNCHPAD_CURRENT_PROJECT"* ]]; then
547
567
project_dir="$LAUNCHPAD_CURRENT_PROJECT"
568
+
548
569
if [[ "$LAUNCHPAD_VERBOSE" == "true" ]]; then
549
570
__lp_current_time=$(__lp_get_time_s)
550
571
printf "⏱️ [%ss] Using cached project dir (same project): %s\n" "$(__lp_elapsed_s "$__lp_start_time" "$__lp_current_time")" "$project_dir" >&2
551
572
fi
552
573
else
553
574
project_dir=$(__launchpad_find_deps_file "$PWD")
575
+
554
576
if [[ "$LAUNCHPAD_VERBOSE" == "true" ]]; then
555
577
__lp_current_time=$(__lp_get_time_s)
556
578
printf "⏱️ [%ss] Dependency file search completed: %s\n" $(__lp_elapsed_s "$__lp_start_time" "$__lp_current_time") "\${project_dir:-none}" >&2
557
579
fi
558
580
fi
559
581
560
582
if [[ -n "$project_dir" ]]; then
583
+ # Always compute dependency hash (even for same project, dependencies can change)
584
+ local real_project_dir
585
+ real_project_dir=$(cd "$project_dir" 2>/dev/null && pwd -P || echo "$project_dir")
586
+
587
+ local dep_file_path dep_short
588
+ dep_file_path="$(__launchpad_find_dependency_file_path "$real_project_dir" 2>/dev/null)"
589
+
590
+
591
+ if [[ "$LAUNCHPAD_VERBOSE" == "true" ]]; then
592
+ __lp_current_time=$(__lp_get_time_s)
593
+ printf "⏱️ [%ss] Dependency file path found: %s\n" $(__lp_elapsed_s "$__lp_start_time" "$__lp_current_time") "\${dep_file_path:-none}" >&2
594
+ fi
595
+
596
+ if [[ -n "$dep_file_path" && -f "$dep_file_path" ]]; then
597
+ # Use launchpad's built-in MD5 computation for reliability
598
+ dep_short=$(${ launchpadBinary } dev:md5 "$dep_file_path" 2>/dev/null || echo "")
599
+ fi
600
+
601
+ # Compute environment directory with dependency hash
602
+ local project_basename
603
+ project_basename=$(basename "$real_project_dir")
604
+ local md5hash
605
+ # Use launchpad's built-in MD5 computation for project path
606
+ md5hash=$(printf "%s" "$real_project_dir" | ${ launchpadBinary } dev:md5 /dev/stdin 2>/dev/null || echo "00000000")
607
+ local project_hash="${ project_basename } _$(echo "$md5hash" | cut -c1-8)"
608
+ local env_dir="$HOME/.local/share/launchpad/envs/$project_hash"
609
+
610
+ # Add dependency hash suffix if we have dependencies
611
+ if [[ -n "$dep_short" ]]; then
612
+ env_dir="${ env_dir } -d${ dep_short } "
613
+ fi
614
+
615
+ if [[ "$LAUNCHPAD_VERBOSE" == "true" ]]; then
616
+ __lp_current_time=$(__lp_get_time_s)
617
+ printf "⏱️ [%ss] Project hash computed: %s\n" $(__lp_elapsed_s "$__lp_start_time" "$__lp_current_time") "$project_hash" >&2
618
+ printf "🔍 Env target: env_dir=%s dep_file=%s dep_hash=%s\n" "$env_dir" "\${dep_file_path:-none}" "\${dep_short:-none}" >&2
619
+ fi
620
+
621
+ # Check if dependencies changed in the same project (force new setup)
622
+ if [[ "$LAUNCHPAD_CURRENT_PROJECT" == "$project_dir" && -n "$LAUNCHPAD_ENV_BIN_PATH" ]]; then
623
+ # Extract current environment directory from LAUNCHPAD_ENV_BIN_PATH
624
+ local current_env_dir="\${LAUNCHPAD_ENV_BIN_PATH%/bin}"
625
+
626
+ # If current environment doesn't match expected environment, dependencies changed
627
+ if [[ "$current_env_dir" != "$env_dir" ]]; then
628
+ if [[ "$LAUNCHPAD_VERBOSE" == "true" ]]; then
629
+ __lp_current_time=$(__lp_get_time_s)
630
+ printf "⏱️ [%ss] Dependencies changed, forcing new setup\n" $(__lp_elapsed_s "$__lp_start_time" "$__lp_current_time") >&2
631
+ printf "🔍 Current: %s\n" "$current_env_dir" >&2
632
+ printf "🔍 Expected: %s\n" "$env_dir" >&2
633
+ fi
634
+ # Force new project setup by unsetting the current project
635
+ unset LAUNCHPAD_CURRENT_PROJECT
636
+ fi
637
+ fi
638
+
561
639
# Check if we're entering a new project or if this is the first time
562
640
if [[ "$LAUNCHPAD_CURRENT_PROJECT" != "$project_dir" ]]; then
563
641
export LAUNCHPAD_CURRENT_PROJECT="$project_dir"
@@ -569,7 +647,7 @@ __launchpad_chpwd() {
569
647
570
648
# Check if setup is already in progress to avoid duplicate work
571
649
if [[ "$__launchpad_setup_in_progress" == "$project_dir" ]]; then
572
- if [[ "$LAUNCHPAD_VERBOSE" == "true" ]]; then
650
+ if [[ "$LAUNCHPAD_VERBOSE" == "true" ]]; then
573
651
__lp_current_time=$(__lp_get_time_s)
574
652
printf "⏱️ [%ss] Setup already in progress, skipping\n" $(__lp_elapsed_s "$__lp_start_time" "$__lp_current_time") >&2
575
653
fi
@@ -581,70 +659,17 @@ __launchpad_chpwd() {
581
659
setopt localoptions nonomatch
582
660
fi
583
661
584
- # Ultra-fast activation: compute environment path and check if ready
585
- # Resolve to physical path and compute MD5 (matches generateProjectHash in dump.ts)
586
- local real_project_dir
587
- real_project_dir=$(cd "$project_dir" 2>/dev/null && pwd -P || echo "$project_dir")
588
- # Enable verbose logs for this shell when project config sets verbose: true
662
+ # Ultra-fast activation: enable verbose logs for this shell when project config sets verbose: true
589
663
if [[ -f "$real_project_dir/launchpad.config.ts" ]] && /usr/bin/grep -Eq "verbose:\\s*true" "$real_project_dir/launchpad.config.ts" 2>/dev/null; then
590
664
export LAUNCHPAD_VERBOSE=true
591
665
fi
592
- local project_basename
593
- project_basename=$(basename "$real_project_dir")
594
- local md5hash
595
- if command -v md5 >/dev/null 2>&1; then
596
- md5hash=$(md5 -q -s "$real_project_dir" 2>/dev/null || md5 -q "$real_project_dir" 2>/dev/null)
597
- fi
598
- if [[ -z "$md5hash" ]] && command -v md5sum >/dev/null 2>&1; then
599
- md5hash=$(printf "%s" "$real_project_dir" | md5sum 2>/dev/null | awk '{print $1}')
600
- fi
601
- if [[ -z "$md5hash" ]] && command -v openssl >/dev/null 2>&1; then
602
- md5hash=$(printf "%s" "$real_project_dir" | openssl md5 2>/dev/null | awk '{print $2}')
603
- fi
604
- if [[ -z "$md5hash" ]]; then
605
- md5hash="00000000"
606
- fi
607
- local project_hash="\${project_basename}_$(echo "$md5hash" | cut -c1-8)"
608
- local env_dir="$HOME/.local/share/launchpad/envs/$project_hash"
609
-
610
- if [[ "$LAUNCHPAD_VERBOSE" == "true" ]]; then
611
- __lp_current_time=$(__lp_get_time_s)
612
- printf "⏱️ [%ss] Project hash computed: %s\n" $(__lp_elapsed_s "$__lp_start_time" "$__lp_current_time") "$project_hash" >&2
613
- fi
614
-
615
- # Optionally suffix environment with dependency hash so version changes map to distinct envs
616
- local dep_file_path dep_md5 dep_short
617
- dep_file_path="$(__launchpad_find_dependency_file_path "$real_project_dir" 2>/dev/null)"
618
-
619
- if [[ "$LAUNCHPAD_VERBOSE" == "true" ]]; then
620
- __lp_current_time=$(__lp_get_time_s)
621
- printf "⏱️ [%ss] Dependency file path found: %s\n" $(__lp_elapsed_s "$__lp_start_time" "$__lp_current_time") "\${dep_file_path:-none}" >&2
622
- fi
623
-
624
- if [[ -n "$dep_file_path" && -f "$dep_file_path" ]]; then
625
- if command -v md5 >/dev/null 2>&1; then
626
- dep_md5=$(md5 -q "$dep_file_path" 2>/dev/null || echo "")
627
- elif command -v md5sum >/dev/null 2>&1; then
628
- dep_md5=$(md5sum "$dep_file_path" 2>/dev/null | awk '{print $1}')
629
- else
630
- dep_md5=""
631
- fi
632
- if [[ -n "$dep_md5" ]]; then
633
- dep_short=$(printf "%s" "$dep_md5" | cut -c1-8)
634
- env_dir="\${env_dir}-d\${dep_short}"
635
- fi
636
- fi
637
-
638
- if [[ "$LAUNCHPAD_VERBOSE" == "true" ]]; then
639
- printf "🔍 Env target: env_dir=%s dep_file=%s dep_hash=%s\n" "$env_dir" "\${dep_file_path:-none}" "\${dep_short:-none}" >&2
640
- fi
641
666
642
667
# Skip expensive fallback in shell integration - if env doesn't exist, let full setup handle it
643
668
if [[ ! -d "$env_dir/bin" && -z "$LAUNCHPAD_SHELL_INTEGRATION" ]]; then
644
- if [[ "$LAUNCHPAD_VERBOSE" == "true" ]]; then
669
+ if [[ "$LAUNCHPAD_VERBOSE" == "true" ]]; then
645
670
__lp_current_time=$(__lp_get_time_s)
646
671
printf "⏱️ [%ss] Starting expensive environment fallback search\n" $(__lp_elapsed_s "$__lp_start_time" "$__lp_current_time") >&2
647
- fi
672
+ fi
648
673
local envs_root="$HOME/.local/share/launchpad/envs"
649
674
if [[ -d "$envs_root" ]]; then
650
675
local best_env=""
@@ -722,21 +747,17 @@ __launchpad_chpwd() {
722
747
local mtime size
723
748
mtime=$(stat -c %Y "$dep_file" 2>/dev/null || stat -f %m "$dep_file" 2>/dev/null || echo 0)
724
749
size=$(stat -c %s "$dep_file" 2>/dev/null || stat -f %z "$dep_file" 2>/dev/null || echo 0)
725
- if command -v md5 >/dev/null 2>&1; then
726
- local sum
727
- sum=$(md5 -q "$dep_file" 2>/dev/null || md5 -q -s "$dep_file" 2>/dev/null)
728
- echo "file=$dep_file m=$mtime s=$size md5=$sum"
729
- elif command -v md5sum >/dev/null 2>&1; then
730
750
local sum
731
- sum=$(md5sum "$dep_file" 2>/dev/null | awk '{print $1}')
751
+ sum=$(${ launchpadBinary } dev:md5 "$dep_file" 2>/dev/null || echo "")
752
+ if [[ -n "$sum" ]]; then
732
753
echo "file=$dep_file m=$mtime s=$size md5=$sum"
733
754
else
734
755
echo "file=$dep_file m=$mtime s=$size"
735
756
fi
736
757
}
737
758
738
759
# Persistent cache: check before slow operations (but invalidate when deps changed)
739
- local cache_file="$__launchpad_persistent_cache_dir/env_cache_$(printf "%s" "$env_dir" | md5sum 2>/dev/null | awk '{print $1}' | cut -c1-16)"
760
+ local cache_file="$__launchpad_persistent_cache_dir/env_cache_$(printf "%s" "$env_dir" | ${ launchpadBinary } dev:md5 /dev/stdin 2>/dev/null | cut -c1-16)"
740
761
local current_time=$(date +%s)
741
762
local cache_duration=1800 # 30 minutes for shell integration
742
763
# Use longer cache durations for test/development environments
@@ -826,14 +847,10 @@ __launchpad_chpwd() {
826
847
if [[ -n "$dep_file" && -f "$dep_file" ]]; then
827
848
# Check if the current environment directory matches the expected one for current deps
828
849
local expected_dep_md5 expected_dep_short expected_env_dir
829
- if command -v md5 >/dev/null 2>&1; then
830
- expected_dep_md5=$(md5 -q "$dep_file" 2>/dev/null || echo "")
831
- elif command -v md5sum >/dev/null 2>&1; then
832
- expected_dep_md5=$(md5sum "$dep_file" 2>/dev/null | awk '{print $1}')
833
- fi
850
+ expected_dep_md5=$(${ launchpadBinary } dev:md5 "$dep_file" 2>/dev/null || echo "")
834
851
835
852
if [[ -n "$expected_dep_md5" ]]; then
836
- expected_dep_short=$(printf "%s" " $expected_dep_md5" | cut -c1-8)
853
+ expected_dep_short=" $expected_dep_md5" # Already truncated to 8 chars
837
854
expected_env_dir="$HOME/.local/share/launchpad/envs/\\${ project_basename } _$(echo "$md5hash" | cut -c1-8)-d\\${ expected_dep_short } "
838
855
839
856
# If current environment doesn't match expected environment, dependencies changed
@@ -933,19 +950,19 @@ __launchpad_chpwd() {
933
950
934
951
# All file operations in background
935
952
(
936
- mkdir -p "$(dirname "$cache_file")" 2>/dev/null || true
937
- touch "$cache_file" 2>/dev/null || true
938
- if [[ -z "$dep_file" ]]; then
939
- dep_file="$(__launchpad_find_dependency_file_path "$real_project_dir" 2>/dev/null)"
940
- fi
941
- if [[ -n "$dep_file" && -f "$dep_file" ]]; then
942
- touch -mr "$dep_file" "$cache_file" 2>/dev/null || true
943
- fi
944
- local fp_current
945
- fp_current="$(__launchpad_compute_deps_fingerprint "$real_project_dir")"
946
- if [[ -n "$fp_current" ]]; then
947
- echo "$fp_current" > "$env_dir/.deps_fingerprint" 2>/dev/null || true
948
- fi
953
+ mkdir -p "$(dirname "$cache_file")" 2>/dev/null || true
954
+ touch "$cache_file" 2>/dev/null || true
955
+ if [[ -z "$dep_file" ]]; then
956
+ dep_file="$(__launchpad_find_dependency_file_path "$real_project_dir" 2>/dev/null)"
957
+ fi
958
+ if [[ -n "$dep_file" && -f "$dep_file" ]]; then
959
+ touch -mr "$dep_file" "$cache_file" 2>/dev/null || true
960
+ fi
961
+ local fp_current
962
+ fp_current="$(__launchpad_compute_deps_fingerprint "$real_project_dir")"
963
+ if [[ -n "$fp_current" ]]; then
964
+ echo "$fp_current" > "$env_dir/.deps_fingerprint" 2>/dev/null || true
965
+ fi
949
966
) >/dev/null 2>&1 &
950
967
disown 2>/dev/null || true
951
968
@@ -1004,7 +1021,7 @@ export LAUNCHPAD_PROJECT_DIR=\"$project_dir\"
1004
1021
1005
1022
# All maintenance in background
1006
1023
{
1007
- __launchpad_setup_global_deps
1024
+ __launchpad_setup_global_deps
1008
1025
touch "$HOME/.cache/launchpad/shell_cache/global_refresh_needed" 2>/dev/null || true
1009
1026
mkdir -p "$env_dir" 2>/dev/null || true
1010
1027
touch "$env_dir/.launchpad_ready" 2>/dev/null || true
@@ -1075,10 +1092,10 @@ export LAUNCHPAD_PROJECT_DIR=\"$project_dir\"
1075
1092
1076
1093
# Mark environment ready for instant future activation (both cache and marker) - async
1077
1094
(
1078
- mkdir -p "$env_dir" 2>/dev/null || true
1079
- touch "$env_dir/.launchpad_ready" 2>/dev/null || true
1080
- mkdir -p "$(dirname "$cache_file")" 2>/dev/null || true
1081
- touch "$cache_file" 2>/dev/null || true
1095
+ mkdir -p "$env_dir" 2>/dev/null || true
1096
+ touch "$env_dir/.launchpad_ready" 2>/dev/null || true
1097
+ mkdir -p "$(dirname "$cache_file")" 2>/dev/null || true
1098
+ touch "$cache_file" 2>/dev/null || true
1082
1099
) >/dev/null 2>&1 &
1083
1100
disown 2>/dev/null || true
1084
1101
@@ -1103,6 +1120,12 @@ export LAUNCHPAD_PROJECT_DIR=\"$project_dir\"
1103
1120
fi
1104
1121
fi
1105
1122
fi
1123
+
1124
+ # Always run environment setup logic (ultra-fast path will handle optimization)
1125
+ # Enable verbose logs for this shell when project config sets verbose: true
1126
+ if [[ -f "$real_project_dir/launchpad.config.ts" ]] && /usr/bin/grep -Eq "verbose:\\s*true" "$real_project_dir/launchpad.config.ts" 2>/dev/null; then
1127
+ export LAUNCHPAD_VERBOSE=true
1128
+ fi
1106
1129
else
1107
1130
# No deps file found, deactivate if we were in a project
1108
1131
if [[ -n "$LAUNCHPAD_CURRENT_PROJECT" ]]; then
0 commit comments