diff --git a/bin/analyze.sh b/bin/analyze.sh index a6ca691..00f8695 100755 --- a/bin/analyze.sh +++ b/bin/analyze.sh @@ -720,7 +720,7 @@ display_cleanup_suggestions() { echo "" echo " ${YELLOW}Tip:${NC} Run 'mole clean' to perform cleanup operations" else - echo " ${GREEN}✓${NC} No obvious cleanup opportunities found" + echo " ${BLUE}✓${NC} No obvious cleanup opportunities found" fi echo "" } @@ -1272,11 +1272,11 @@ scan_directory_contents_fast() { xargs -0 -n 1 -P "$num_jobs" sh -c ' dir="$1" size="" - + # Ultra-fast strategy: Try du with 1 second timeout only du -sk "$dir" 2>/dev/null > /tmp/mole_du_$$ & du_pid=$! - + # Wait only 1 second (aggressive!) if ! sleep 1 || kill -0 $du_pid 2>/dev/null; then # Still running after 1s = large dir, kill it @@ -1289,7 +1289,7 @@ scan_directory_contents_fast() { size=$(cat /tmp/mole_du_$$ 2>/dev/null | cut -f1) rm -f /tmp/mole_du_$$ 2>/dev/null fi - + # If timeout or empty, use instant estimation if [[ -z "$size" ]] || [[ "$size" -eq 0 ]]; then # Ultra-fast: count only immediate files (no recursion) @@ -1297,7 +1297,7 @@ scan_directory_contents_fast() { size=$(find "$dir" -type f -maxdepth 1 -print0 2>/dev/null | \ xargs -0 stat -f%z 2>/dev/null | \ awk "BEGIN{sum=0} {sum+=\$1} END{print int(sum/1024)}") - + # If still 0, mark as unknown but ensure it shows up [[ -z "$size" ]] || [[ "$size" -eq 0 ]] && size=1 fi @@ -1318,7 +1318,7 @@ scan_directory_contents_fast() { ((i++)) sleep 0.1 # Faster animation (100ms per frame) ((tick++)) - + # Update elapsed seconds every 10 ticks (1 second) if [[ $((tick % 10)) -eq 0 ]]; then ((elapsed++)) @@ -1343,7 +1343,7 @@ scan_directory_contents_fast() { # Wait for completion (non-blocking if already killed) wait "$file_pid" 2>/dev/null || true wait "$dir_pid" 2>/dev/null || true - + # Small delay only if scan was very fast (let user see the spinner briefly) if [[ "$show_progress" == "true" ]] && [[ ${elapsed:-0} -lt 1 ]]; then sleep 0.2 @@ -1592,8 +1592,6 @@ interactive_drill_down() { # Ensure cursor is always hidden during navigation printf "\033[?25l" >&2 - # Drain any burst input (e.g. trackpad scroll converted to many arrow keys) - type drain_pending_input >/dev/null 2>&1 && drain_pending_input # Only scan if needed (directory changed or refresh requested) if [[ "$need_scan" == "true" ]]; then # Generate cache key (use md5 hash of path) @@ -1632,7 +1630,7 @@ interactive_drill_down() { has_calculating=false need_scan=false wait_for_calc=false - + # Reset scroll when entering new directory scroll_offset=0 @@ -1701,7 +1699,7 @@ interactive_drill_down() { local page_start=$scroll_offset local page_end=$((scroll_offset + max_show)) [[ $page_end -gt $total_items ]] && page_end=$total_items - + local display_idx=0 local idx=0 for item_info in "${items[@]}"; do @@ -1710,7 +1708,7 @@ interactive_drill_down() { ((idx++)) continue fi - + # Stop if we've shown enough items for this page if [[ $idx -ge $page_end ]]; then break @@ -1782,10 +1780,7 @@ interactive_drill_down() { # Output everything at once (single write = no flicker) printf "%b" "$output" >&2 - # Drain any pending input to prevent escape sequence leakage - drain_pending_input 2>/dev/null || true - - # Read key (suppress any escape sequences that might leak) + # Read key directly without draining (to preserve all user input) local key key=$(read_key 2>/dev/null || echo "OTHER") @@ -1832,41 +1827,75 @@ interactive_drill_down() { need_scan=true else # It's a file - open it for viewing - # Exit alternate screen temporarily - printf "\033[?25h" # Show cursor - tput rmcup 2>/dev/null || true - - # Try to open with system default viewer local file_ext="${selected_path##*.}" + local filename=$(basename "$selected_path") local open_success=false - - # For text-like files, use less + + # For text-like files, use less or fallback to open case "$file_ext" in txt|log|md|json|xml|yaml|yml|conf|cfg|ini|sh|bash|zsh|py|js|ts|go|rs|c|cpp|h|java|rb|php|html|css|sql) + # Clear screen and show loading message + printf "\033[H\033[J" + echo "" + echo " ${BLUE}📄 Opening: $filename${NC}" + echo "" + + # Try less first (best for text viewing) if command -v less &>/dev/null; then + # Exit alternate screen only for less + printf "\033[?25h" # Show cursor + tput rmcup 2>/dev/null || true + less -F "$selected_path" 2>/dev/null && open_success=true + + # Return to alternate screen + tput smcup 2>/dev/null || true + printf "\033[?25l" # Hide cursor + else + # Fallback to system open if less is not available + echo " ${GRAY}Launching default application...${NC}" + if command -v open &>/dev/null; then + open "$selected_path" 2>/dev/null && open_success=true + if [[ "$open_success" == "true" ]]; then + echo "" + echo " ${BLUE}✓${NC} File opened in external app" + sleep 0.8 + fi + fi fi ;; *) - # For other files, try system open + # For other files, use system open (keep in alternate screen) + # Show message without flashing + printf "\033[H\033[J" + echo "" + echo " ${BLUE}📦 Opening: $filename${NC}" + echo "" + echo " ${GRAY}Launching default application...${NC}" + if command -v open &>/dev/null; then open "$selected_path" 2>/dev/null && open_success=true - sleep 0.5 # Give time for app to launch + + # Show brief success message + if [[ "$open_success" == "true" ]]; then + echo "" + echo " ${BLUE}✓${NC} File opened in external app" + sleep 0.8 + fi fi ;; esac - - # If nothing worked, show a message + + # If nothing worked, show error message if [[ "$open_success" != "true" ]]; then + printf "\033[H\033[J" echo "" - echo " ${YELLOW}File: $selected_path${NC}" + echo " ${YELLOW}⚠️ Could not open file${NC}" + echo "" + echo " ${GRAY}File: $selected_path${NC}" echo " ${GRAY}Press any key to return...${NC}" read -n 1 -s 2>/dev/null fi - - # Return to alternate screen - tput smcup 2>/dev/null || true - printf "\033[?25l" # Hide cursor fi fi ;; @@ -1973,7 +2002,7 @@ interactive_drill_down() { fi if [[ "$delete_success" == "true" ]]; then - echo " ${GREEN}✓ Deleted successfully${NC}" + echo " ${BLUE}✓ Deleted successfully${NC}" echo " ${GRAY}Freed: $human_size${NC}" sleep 0.8 diff --git a/bin/clean.sh b/bin/clean.sh index 504fb9f..8749f18 100755 --- a/bin/clean.sh +++ b/bin/clean.sh @@ -63,21 +63,21 @@ start_spinner() { local message="$1" if [[ ! -t 1 ]]; then - echo -n " ${BLUE}🔍${NC} $message" + echo -n " ${BLUE}◎${NC} $message" return fi - echo -n " ${BLUE}🔍${NC} $message" + echo -n " ${BLUE}◎${NC} $message" ( local delay=0.5 while true; do - printf "\r ${BLUE}🔍${NC} $message. " + printf "\r ${BLUE}◎${NC} $message. " sleep $delay - printf "\r ${BLUE}🔍${NC} $message.. " + printf "\r ${BLUE}◎${NC} $message.. " sleep $delay - printf "\r ${BLUE}🔍${NC} $message..." + printf "\r ${BLUE}◎${NC} $message..." sleep $delay - printf "\r ${BLUE}🔍${NC} $message " + printf "\r ${BLUE}◎${NC} $message " sleep $delay done ) & @@ -96,9 +96,9 @@ stop_spinner() { kill "$SPINNER_PID" 2>/dev/null wait "$SPINNER_PID" 2>/dev/null SPINNER_PID="" - printf "\r ${GREEN}✓${NC} %s\n" "$result_message" + printf "\r ${BLUE}✓${NC} %s\n" "$result_message" else - echo " ${GREEN}✓${NC} $result_message" + echo " ${BLUE}✓${NC} $result_message" fi } @@ -111,7 +111,7 @@ start_section() { end_section() { if [[ $TRACK_SECTION -eq 1 && $SECTION_ACTIVITY -eq 0 ]]; then - echo -e " ${BLUE}✨${NC} Nothing to tidy" + echo -e " ${BLUE}○${NC} Nothing to tidy" fi TRACK_SECTION=0 } @@ -156,7 +156,7 @@ safe_clean() { # Show progress indicator for potentially slow operations if [[ ${#existing_paths[@]} -gt 3 ]]; then - [[ -t 1 ]] && echo -ne " ${BLUE}●${NC} Checking $description...\r" + [[ -t 1 ]] && echo -ne " ${BLUE}◎${NC} Checking $description...\r" local temp_dir=$(mktemp -d) # Parallel processing (bash 3.2 compatible) @@ -197,7 +197,7 @@ safe_clean() { rm -rf "$temp_dir" else # Show progress for small batches too (simpler jobs) - [[ -t 1 ]] && echo -ne " ${BLUE}●${NC} Checking $description...\r" + [[ -t 1 ]] && echo -ne " ${BLUE}◎${NC} Checking $description...\r" for path in "${existing_paths[@]}"; do local size_bytes=$(du -sk "$path" 2>/dev/null | awk '{print $1}' || echo "0") @@ -235,7 +235,7 @@ safe_clean() { if [[ "$DRY_RUN" == "true" ]]; then echo -e " ${YELLOW}→${NC} $label ${YELLOW}($size_human, dry)${NC}" else - echo -e " ${GREEN}✓${NC} $label ${GREEN}($size_human)${NC}" + echo -e " ${BLUE}✓${NC} $label ${GREEN}($size_human)${NC}" fi ((files_cleaned+=total_count)) ((total_size_cleaned+=total_size_bytes)) @@ -442,10 +442,10 @@ perform_cleanup() { start_section "Developer tools" # Node.js ecosystem if command -v npm >/dev/null 2>&1; then - [[ -t 1 ]] && echo -ne " ${BLUE}●${NC} Cleaning npm cache...\r" + [[ -t 1 ]] && echo -ne " ${BLUE}◎${NC} Cleaning npm cache...\r" npm cache clean --force >/dev/null 2>&1 || true [[ -t 1 ]] && echo -ne "\r\033[K" - echo -e " ${GREEN}✓${NC} npm cache cleaned" + echo -e " ${BLUE}✓${NC} npm cache cleaned" note_activity fi @@ -455,10 +455,10 @@ perform_cleanup() { # Python ecosystem if command -v pip3 >/dev/null 2>&1; then - [[ -t 1 ]] && echo -ne " ${BLUE}●${NC} Cleaning pip cache...\r" + [[ -t 1 ]] && echo -ne " ${BLUE}◎${NC} Cleaning pip cache...\r" pip3 cache purge >/dev/null 2>&1 || true [[ -t 1 ]] && echo -ne "\r\033[K" - echo -e " ${GREEN}✓${NC} pip cache cleaned" + echo -e " ${BLUE}✓${NC} pip cache cleaned" note_activity fi @@ -468,11 +468,11 @@ perform_cleanup() { # Go ecosystem if command -v go >/dev/null 2>&1; then - [[ -t 1 ]] && echo -ne " ${BLUE}●${NC} Cleaning Go cache...\r" + [[ -t 1 ]] && echo -ne " ${BLUE}◎${NC} Cleaning Go cache...\r" go clean -modcache >/dev/null 2>&1 || true go clean -cache >/dev/null 2>&1 || true [[ -t 1 ]] && echo -ne "\r\033[K" - echo -e " ${GREEN}✓${NC} Go cache cleaned" + echo -e " ${BLUE}✓${NC} Go cache cleaned" note_activity fi @@ -484,20 +484,20 @@ perform_cleanup() { # Docker (only clean build cache, preserve images and volumes) if command -v docker >/dev/null 2>&1; then - [[ -t 1 ]] && echo -ne " ${BLUE}●${NC} Cleaning Docker build cache...\r" + [[ -t 1 ]] && echo -ne " ${BLUE}◎${NC} Cleaning Docker build cache...\r" docker builder prune -af >/dev/null 2>&1 || true [[ -t 1 ]] && echo -ne "\r\033[K" - echo -e " ${GREEN}✓${NC} Docker build cache cleaned" + echo -e " ${BLUE}✓${NC} Docker build cache cleaned" note_activity fi # Container tools safe_clean ~/.kube/cache/* "Kubernetes cache" if command -v podman >/dev/null 2>&1; then - [[ -t 1 ]] && echo -ne " ${BLUE}●${NC} Cleaning Podman build cache...\r" + [[ -t 1 ]] && echo -ne " ${BLUE}◎${NC} Cleaning Podman build cache...\r" podman system prune -f >/dev/null 2>&1 || true [[ -t 1 ]] && echo -ne "\r\033[K" - echo -e " ${GREEN}✓${NC} Podman build cache cleaned" + echo -e " ${BLUE}✓${NC} Podman build cache cleaned" note_activity fi safe_clean ~/.local/share/containers/storage/tmp/* "Container storage temp" @@ -512,10 +512,10 @@ perform_cleanup() { safe_clean /opt/homebrew/var/homebrew/locks/* "Homebrew lock files (M series)" safe_clean /usr/local/var/homebrew/locks/* "Homebrew lock files (Intel)" if command -v brew >/dev/null 2>&1; then - [[ -t 1 ]] && echo -ne " ${BLUE}●${NC} Cleaning Homebrew...\r" + [[ -t 1 ]] && echo -ne " ${BLUE}◎${NC} Cleaning Homebrew...\r" brew cleanup >/dev/null 2>&1 || true [[ -t 1 ]] && echo -ne "\r\033[K" - echo -e " ${GREEN}✓${NC} Homebrew cache cleaned" + echo -e " ${BLUE}✓${NC} Homebrew cache cleaned" note_activity fi @@ -774,7 +774,7 @@ perform_cleanup() { start_section "Orphaned app caches" # Build a list of installed application bundle identifiers - echo -n " ${BLUE}🔍${NC} Scanning installed applications..." + echo -n " ${BLUE}◎${NC} Scanning installed applications..." local installed_bundles=$(mktemp) # Scan both system and user application directories @@ -785,12 +785,12 @@ perform_cleanup() { fi done local app_count=$(wc -l < "$installed_bundles" | tr -d ' ') - echo " ${GREEN}✓${NC} Found $app_count apps" + echo " ${BLUE}✓${NC} Found $app_count apps" local cache_count=0 # Check for orphaned caches (safe to remove - caches are regenerable) - echo -n " ${BLUE}🔍${NC} Scanning orphaned cache directories..." + echo -n " ${BLUE}◎${NC} Scanning orphaned cache directories..." if ls ~/Library/Caches/com.* >/dev/null 2>&1; then for cache_dir in ~/Library/Caches/com.*; do [[ -d "$cache_dir" ]] || continue @@ -805,7 +805,7 @@ perform_cleanup() { fi done fi - echo " ${GREEN}✓${NC} Complete ($cache_count removed)" + echo " ${BLUE}✓${NC} Complete ($cache_count removed)" # Clean up temp file rm -f "$installed_bundles" diff --git a/bin/uninstall.sh b/bin/uninstall.sh index d8b426c..a6d965f 100755 --- a/bin/uninstall.sh +++ b/bin/uninstall.sh @@ -144,11 +144,11 @@ scan_applications() { # Smart display name selection - prefer descriptive names over generic ones local candidates=() - + # Get all potential names local bundle_display_name=$(plutil -extract CFBundleDisplayName raw "$app_path/Contents/Info.plist" 2>/dev/null) local bundle_name=$(plutil -extract CFBundleName raw "$app_path/Contents/Info.plist" 2>/dev/null) - + # Check if executable name is generic/technical (should be avoided) local is_generic_executable=false if [[ -n "$bundle_executable" ]]; then @@ -158,35 +158,35 @@ scan_applications() { ;; esac fi - + # Priority order for name selection: # 1. App folder name (if ASCII and descriptive) - often the most complete name if [[ "$app_name" =~ ^[A-Za-z0-9\ ._-]+$ && ${#app_name} -gt 3 ]]; then candidates+=("$app_name") fi - + # 2. CFBundleDisplayName (if meaningful and ASCII) if [[ -n "$bundle_display_name" && "$bundle_display_name" =~ ^[A-Za-z0-9\ ._-]+$ ]]; then candidates+=("$bundle_display_name") fi - - # 3. CFBundleName (if meaningful and ASCII) + + # 3. CFBundleName (if meaningful and ASCII) if [[ -n "$bundle_name" && "$bundle_name" =~ ^[A-Za-z0-9\ ._-]+$ && "$bundle_name" != "$bundle_display_name" ]]; then candidates+=("$bundle_name") fi - + # 4. CFBundleExecutable (only if not generic and ASCII) if [[ -n "$bundle_executable" && "$bundle_executable" =~ ^[A-Za-z0-9._-]+$ && "$is_generic_executable" == false ]]; then candidates+=("$bundle_executable") fi - + # 5. Fallback to non-ASCII names if no ASCII found if [[ ${#candidates[@]} -eq 0 ]]; then [[ -n "$bundle_display_name" ]] && candidates+=("$bundle_display_name") [[ -n "$bundle_name" && "$bundle_name" != "$bundle_display_name" ]] && candidates+=("$bundle_name") candidates+=("$app_name") fi - + # Select the first (best) candidate display_name="${candidates[0]:-$app_name}" @@ -404,11 +404,11 @@ uninstall_applications() { # Show what will be removed echo -e " ${YELLOW}Files to be removed:${NC}" - echo -e " ${GREEN}✓${NC} Application: $(echo "$app_path" | sed "s|$HOME|~|")" + echo -e " ${BLUE}✓${NC} Application: $(echo "$app_path" | sed "s|$HOME|~|")" # Show user-level files while IFS= read -r file; do - [[ -n "$file" && -e "$file" ]] && echo -e " ${GREEN}✓${NC} $(echo "$file" | sed "s|$HOME|~|")" + [[ -n "$file" && -e "$file" ]] && echo -e " ${BLUE}✓${NC} $(echo "$file" | sed "s|$HOME|~|")" done <<< "$related_files" # Show system-level files @@ -435,7 +435,7 @@ uninstall_applications() { if [[ $REPLY =~ ^[Yy]$ ]]; then # Remove the application if rm -rf "$app_path" 2>/dev/null; then - echo -e " ${GREEN}✓${NC} Removed application" + echo -e " ${BLUE}✓${NC} Removed application" else log_error "Failed to remove $app_path" continue @@ -445,7 +445,7 @@ uninstall_applications() { while IFS= read -r file; do if [[ -n "$file" && -e "$file" ]]; then if rm -rf "$file" 2>/dev/null; then - echo -e " ${GREEN}✓${NC} Removed $(echo "$file" | sed "s|$HOME|~|" | xargs basename)" + echo -e " ${BLUE}✓${NC} Removed $(echo "$file" | sed "s|$HOME|~|" | xargs basename)" fi fi done <<< "$related_files" @@ -456,7 +456,7 @@ uninstall_applications() { while IFS= read -r file; do if [[ -n "$file" && -e "$file" ]]; then if sudo rm -rf "$file" 2>/dev/null; then - echo -e " ${GREEN}✓${NC} Removed [System] $(basename "$file")" + echo -e " ${BLUE}✓${NC} Removed [System] $(basename "$file")" else log_warning "Failed to remove system file: $file" fi @@ -508,7 +508,7 @@ trap cleanup EXIT INT TERM main() { # Hide cursor during operation hide_cursor - + # Scan applications local apps_file=$(scan_applications) diff --git a/install.sh b/install.sh index 733fe5a..a62126a 100755 --- a/install.sh +++ b/install.sh @@ -85,7 +85,7 @@ resolve_source_dir() { # Expand tmp now so trap doesn't depend on local scope trap "rm -rf '$tmp'" EXIT - echo "Fetching Mole source..." + echo -e "${BLUE}◎${NC} Fetching Mole source..." if command -v curl >/dev/null 2>&1; then # Download main branch tarball if curl -fsSL -o "$tmp/mole.tar.gz" "https://github.com/tw93/mole/archive/refs/heads/main.tar.gz"; then @@ -448,17 +448,17 @@ perform_update() { update_via_homebrew "$VERSION" else # Fallback: inline implementation - echo -e "${BLUE}→${NC} Updating Homebrew..." + echo -e "${BLUE}◎${NC} Updating Homebrew..." brew update 2>&1 | grep -Ev "^(==>|Already up-to-date)" || true - echo -e "${BLUE}→${NC} Upgrading Mole..." + echo -e "${BLUE}◎${NC} Upgrading Mole..." local upgrade_output upgrade_output=$(brew upgrade mole 2>&1) || true if echo "$upgrade_output" | grep -q "already installed"; then local current_version current_version=$(brew list --versions mole 2>/dev/null | awk '{print $2}') - echo -e "${GREEN}✓${NC} Already on latest version (${current_version:-$VERSION})" + echo -e "${BLUE}✓${NC} Already on latest version (${current_version:-$VERSION})" elif echo "$upgrade_output" | grep -q "Error:"; then log_error "Homebrew upgrade failed" echo "$upgrade_output" | grep "Error:" >&2 @@ -467,7 +467,7 @@ perform_update() { echo "$upgrade_output" | grep -Ev "^(==>|Updating Homebrew|Warning:)" || true local new_version new_version=$(brew list --versions mole 2>/dev/null | awk '{print $2}') - echo -e "${GREEN}✓${NC} Updated to latest version (${new_version:-$VERSION})" + echo -e "${BLUE}✓${NC} Updated to latest version (${new_version:-$VERSION})" fi rm -f "$HOME/.cache/mole/version_check" "$HOME/.cache/mole/update_message" @@ -494,7 +494,7 @@ perform_update() { fi if [[ "$installed_version" == "$target_version" ]]; then - echo -e "${GREEN}✓${NC} Already on latest version ($installed_version)" + echo -e "${BLUE}✓${NC} Already on latest version ($installed_version)" exit 0 fi @@ -514,7 +514,7 @@ perform_update() { updated_version="$target_version" fi - echo -e "${GREEN}✓${NC} Updated to latest version ($updated_version)" + echo -e "${BLUE}✓${NC} Updated to latest version ($updated_version)" } # Run requested action diff --git a/lib/batch_uninstall.sh b/lib/batch_uninstall.sh index ca3bcae..80e95aa 100755 --- a/lib/batch_uninstall.sh +++ b/lib/batch_uninstall.sh @@ -185,14 +185,14 @@ batch_uninstall_applications() { if [[ "$needs_sudo" == "true" ]]; then if sudo rm -rf "$app_path" 2>/dev/null; then removal_success=true - echo -e " ${GREEN}✓${NC} Removed application" + echo -e " ${BLUE}✓${NC} Removed application" else error_msg="Failed to remove with sudo (check permissions or SIP protection)" fi else if rm -rf "$app_path" 2>/dev/null; then removal_success=true - echo -e " ${GREEN}✓${NC} Removed application" + echo -e " ${BLUE}✓${NC} Removed application" else error_msg="Failed to remove (check if app is running or protected)" fi @@ -211,7 +211,7 @@ batch_uninstall_applications() { done <<< "$related_files" if [[ $files_removed -gt 0 ]]; then - echo -e " ${GREEN}✓${NC} Cleaned $files_removed related files" + echo -e " ${BLUE}✓${NC} Cleaned $files_removed related files" fi ((total_size_freed += total_kb)) diff --git a/lib/common.sh b/lib/common.sh index 279f3ba..da4e763 100755 --- a/lib/common.sh +++ b/lib/common.sh @@ -36,7 +36,7 @@ log_info() { log_success() { rotate_log - echo -e " ${GREEN}✓${NC} $1" + echo -e " ${BLUE}✓${NC} $1" echo "[$(date '+%Y-%m-%d %H:%M:%S')] SUCCESS: $1" >> "$LOG_FILE" 2>/dev/null || true } @@ -48,7 +48,7 @@ log_warning() { log_error() { rotate_log - echo -e "${RED}❌ $1${NC}" >&2 + echo -e "${RED}$1${NC}" >&2 echo "[$(date '+%Y-%m-%d %H:%M:%S')] ERROR: $1" >> "$LOG_FILE" 2>/dev/null || true } @@ -264,11 +264,11 @@ request_sudo() { update_via_homebrew() { local version="${1:-unknown}" - echo -e "${BLUE}→${NC} Updating Homebrew..." + echo -e "${BLUE}◎${NC} Updating Homebrew..." # Filter out common noise but show important info brew update 2>&1 | grep -Ev "^(==>|Already up-to-date)" || true - echo -e "${BLUE}→${NC} Upgrading Mole..." + echo -e "${BLUE}◎${NC} Upgrading Mole..." local upgrade_output upgrade_output=$(brew upgrade mole 2>&1) || true @@ -276,7 +276,7 @@ update_via_homebrew() { # Get current version local current_version current_version=$(brew list --versions mole 2>/dev/null | awk '{print $2}') - echo -e "${GREEN}✓${NC} Already on latest version (${current_version:-$version})" + echo -e "${BLUE}✓${NC} Already on latest version (${current_version:-$version})" elif echo "$upgrade_output" | grep -q "Error:"; then log_error "Homebrew upgrade failed" echo "$upgrade_output" | grep "Error:" >&2 @@ -287,7 +287,7 @@ update_via_homebrew() { # Get new version local new_version new_version=$(brew list --versions mole 2>/dev/null | awk '{print $2}') - echo -e "${GREEN}✓${NC} Updated to latest version (${new_version:-$version})" + echo -e "${BLUE}✓${NC} Updated to latest version (${new_version:-$version})" fi # Clear version check cache @@ -368,7 +368,7 @@ readonly DATA_PROTECTED_BUNDLES=( "com.tunabellysoftware.*" # Disk Utility apps "com.grandperspectiv.*" # GrandPerspective "com.binaryfruit.*" # FusionCast - + # ============================================================================ # Password Managers & Security # ============================================================================ @@ -381,7 +381,7 @@ readonly DATA_PROTECTED_BUNDLES=( "org.keepassx.*" # KeePassX "com.authy.*" # Authy "com.yubico.*" # YubiKey Manager - + # ============================================================================ # Development Tools - IDEs & Editors # ============================================================================ @@ -398,7 +398,7 @@ readonly DATA_PROTECTED_BUNDLES=( "com.panic.Nova" # Nova "abnerworks.Typora" # Typora (Markdown editor) "com.uranusjr.macdown" # MacDown - + # ============================================================================ # Development Tools - Database Clients # ============================================================================ @@ -413,7 +413,7 @@ readonly DATA_PROTECTED_BUNDLES=( "com.eggerapps.Sequel-Pro" # Sequel Pro legacy "com.valentina-db.Valentina-Studio" # Valentina Studio "com.dbvis.DbVisualizer" # DbVisualizer - + # ============================================================================ # Development Tools - API & Network # ============================================================================ @@ -426,7 +426,7 @@ readonly DATA_PROTECTED_BUNDLES=( "com.charlesproxy.charles" # Charles "com.telerik.Fiddler" # Fiddler "com.usebruno.app" # Bruno (API client) - + # ============================================================================ # Development Tools - Git & Version Control # ============================================================================ @@ -438,7 +438,7 @@ readonly DATA_PROTECTED_BUNDLES=( "com.github.Gitify" # Gitify "com.fork.Fork" # Fork "com.axosoft.gitkraken" # GitKraken - + # ============================================================================ # Development Tools - Terminal & Shell # ============================================================================ @@ -451,7 +451,7 @@ readonly DATA_PROTECTED_BUNDLES=( "com.fig.Fig" # Fig (terminal assistant) "dev.warp.Warp-Stable" # Warp "com.termius-dmg" # Termius (SSH client) - + # ============================================================================ # Development Tools - Docker & Virtualization # ============================================================================ @@ -462,7 +462,7 @@ readonly DATA_PROTECTED_BUNDLES=( "org.virtualbox.app.VirtualBox" # VirtualBox "com.vagrant.*" # Vagrant "com.orbstack.OrbStack" # OrbStack - + # ============================================================================ # System Monitoring & Performance # ============================================================================ @@ -473,7 +473,7 @@ readonly DATA_PROTECTED_BUNDLES=( "com.mediaatelier.MenuMeters" # MenuMeters "com.activity-indicator.app" # Activity Indicator "net.cindori.sensei" # Sensei - + # ============================================================================ # Window Management & Productivity # ============================================================================ @@ -493,7 +493,7 @@ readonly DATA_PROTECTED_BUNDLES=( "com.surteesstudios.Bartender" # Bartender "com.gaosun.eul" # eul (system monitor) "com.pointum.hazeover" # HazeOver - + # ============================================================================ # Launcher & Automation # ============================================================================ @@ -506,7 +506,7 @@ readonly DATA_PROTECTED_BUNDLES=( "com.pilotmoon.scroll-reverser" # Scroll Reverser "org.pqrs.Karabiner-Elements" # Karabiner-Elements "com.apple.Automator" # Automator (system, but keep user workflows) - + # ============================================================================ # Note-Taking & Documentation # ============================================================================ @@ -527,7 +527,7 @@ readonly DATA_PROTECTED_BUNDLES=( "com.roamresearch.*" # Roam Research "com.reflect.ReflectApp" # Reflect "com.inkdrop.*" # Inkdrop - + # ============================================================================ # Design & Creative Tools # ============================================================================ @@ -547,7 +547,7 @@ readonly DATA_PROTECTED_BUNDLES=( "com.maxon.cinema4d" # Cinema 4D "com.autodesk.*" # Autodesk products "com.sketchup.*" # SketchUp - + # ============================================================================ # Communication & Collaboration # ============================================================================ @@ -571,7 +571,7 @@ readonly DATA_PROTECTED_BUNDLES=( "com.airmail.*" # Airmail "com.postbox-inc.postbox" # Postbox "com.tinyspeck.slackmacgap" # Slack legacy - + # ============================================================================ # Task Management & Productivity # ============================================================================ @@ -588,7 +588,7 @@ readonly DATA_PROTECTED_BUNDLES=( "com.airtable.airtable" # Airtable "com.notion.id" # Notion (also note-taking) "com.linear.linear" # Linear - + # ============================================================================ # File Transfer & Sync # ============================================================================ @@ -599,7 +599,7 @@ readonly DATA_PROTECTED_BUNDLES=( "io.filezilla.FileZilla" # FileZilla "com.apple.Xcode.CloudDocuments" # Xcode Cloud Documents "com.synology.*" # Synology apps - + # ============================================================================ # Screenshot & Recording # ============================================================================ @@ -615,7 +615,7 @@ readonly DATA_PROTECTED_BUNDLES=( "com.getkap.*" # Kap legacy "com.linebreak.CloudApp" # CloudApp "com.droplr.droplr-mac" # Droplr - + # ============================================================================ # Media & Entertainment # ============================================================================ @@ -632,7 +632,7 @@ readonly DATA_PROTECTED_BUNDLES=( "com.noodlesoft.Hazel" # Hazel (automation) "tv.plex.player.desktop" # Plex "com.netease.163music" # NetEase Music - + # ============================================================================ # License Management & App Stores # ============================================================================ diff --git a/lib/whitelist_manager.sh b/lib/whitelist_manager.sh index 932b2fa..3fc7fdb 100755 --- a/lib/whitelist_manager.sh +++ b/lib/whitelist_manager.sh @@ -42,7 +42,7 @@ collect_files_to_be_cleaned() { local clean_sh="$SCRIPT_DIR/../bin/clean.sh" local -a items=() - echo -e "${BLUE}🔍${NC} Scanning cache files..." + echo -e "${BLUE}◎${NC} Scanning cache files..." echo "" # Run clean.sh in dry-run mode @@ -298,7 +298,7 @@ manage_whitelist() { fi if [[ ${#all_items[@]} -eq 0 ]]; then - echo -e "${GREEN}✨${NC} No cache files found - system is clean!" + echo -e "${BLUE}✓${NC} No cache files found - system is clean!" echo "" echo "Press any key to exit..." read -n 1 -s @@ -308,7 +308,7 @@ manage_whitelist() { # Update global array with all items AVAILABLE_CACHE_ITEMS=("${all_items[@]}") - echo -e "${GREEN}✓${NC} Found ${#AVAILABLE_CACHE_ITEMS[@]} items" + echo -e "${BLUE}✓${NC} Found ${#AVAILABLE_CACHE_ITEMS[@]} items" echo "" local -a menu_options=() @@ -432,7 +432,7 @@ EOF fi echo "" - echo -e "${GREEN}✓${NC} Protected $total_count items${summary}" + echo -e "${BLUE}✓${NC} Protected $total_count items${summary}" echo -e "${GRAY}Config: ${WHITELIST_CONFIG}${NC}" } diff --git a/mole b/mole index 2542be9..159949c 100755 --- a/mole +++ b/mole @@ -22,7 +22,7 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "$SCRIPT_DIR/lib/common.sh" # Version info -VERSION="1.6.0" +VERSION="1.6.1" MOLE_TAGLINE="can dig deep to clean your Mac." # Check for updates (non-blocking, cached) @@ -148,7 +148,7 @@ update_mole() { fi # Download and run installer with progress - echo -e "${BLUE}→${NC} Downloading latest version..." + echo -e "${BLUE}◎${NC} Downloading latest version..." local installer_url="https://raw.githubusercontent.com/tw93/mole/main/install.sh" local tmp_installer @@ -181,7 +181,7 @@ update_mole() { local install_dir install_dir="$(cd "$(dirname "$mole_path")" && pwd)" - echo -e "${BLUE}→${NC} Installing update..." + echo -e "${BLUE}◎${NC} Installing update..." # Run installer with visible output (but capture for error handling) local install_output @@ -189,14 +189,14 @@ update_mole() { echo "$install_output" | grep -Ev "^$" || true local new_version new_version=$("$mole_path" --version 2>/dev/null | awk 'NF {print $NF}' || echo "") - echo -e "${GREEN}✓${NC} Updated to latest version (${new_version:-unknown})" + echo -e "${BLUE}✓${NC} Updated to latest version (${new_version:-unknown})" else # Retry without --update flag if install_output=$("$tmp_installer" --prefix "$install_dir" --config "$HOME/.config/mole" 2>&1); then echo "$install_output" | grep -Ev "^$" || true local new_version new_version=$("$mole_path" --version 2>/dev/null | awk 'NF {print $NF}' || echo "") - echo -e "${GREEN}✓${NC} Updated to latest version (${new_version:-unknown})" + echo -e "${BLUE}✓${NC} Updated to latest version (${new_version:-unknown})" else rm -f "$tmp_installer" log_error "Update failed" @@ -259,28 +259,28 @@ remove_mole() { echo "" if [[ "$is_homebrew" == "true" ]]; then - echo -e " ${GREEN}✓${NC} Mole (via Homebrew)" + echo -e " ${BLUE}✓${NC} Mole (via Homebrew)" fi if [[ ${#manual_installs[@]} -gt 0 ]]; then for install in "${manual_installs[@]}"; do - echo -e " ${GREEN}✓${NC} $install" + echo -e " ${BLUE}✓${NC} $install" local install_dir="$(dirname "$install")" local install_root="$(dirname "$install_dir")" if [[ -d "$install_root/lib" ]]; then - echo -e " ${GREEN}✓${NC} $install_root/lib/" + echo -e " ${BLUE}✓${NC} $install_root/lib/" fi done fi if [[ ${#alias_installs[@]} -gt 0 ]]; then for alias in "${alias_installs[@]}"; do - echo -e " ${GREEN}✓${NC} $alias" + echo -e " ${BLUE}✓${NC} $alias" done fi - echo -e " ${GREEN}✓${NC} ~/.config/mole/ (configuration)" - echo -e " ${GREEN}✓${NC} ~/.cache/mole/ (cache)" + echo -e " ${BLUE}✓${NC} ~/.config/mole/ (configuration)" + echo -e " ${BLUE}✓${NC} ~/.cache/mole/ (cache)" if [[ "$is_homebrew" == "false" && ${#manual_installs[@]} -eq 0 && ${#alias_installs[@]} -eq 0 ]]; then echo ""