Last active
November 27, 2025 04:21
-
-
Save MedRedha/eb8b8d4b1c4d7492e09d04360adc5812 to your computer and use it in GitHub Desktop.
Pulse - Checking the vital signs of your developer toolchain
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # ____ ___ | |
| # /\ _`\ /\_ \ | |
| # \ \ \L\ \ __ __\//\ \ ____ __ | |
| # \ \ ,__//\ \/\ \ \ \ \ /',__\ /'__`\ | |
| # \ \ \/ \ \ \_\ \ \_\ \_ /\__, `\/\ __/ | |
| # \ \_\ \ \____/ /\____\/\____/\ \____\ | |
| # \/_/ \/___/ \/____/ \/___/ \/____/ | |
| # | |
| # Checking the vital signs of your developer toolchain. | |
| # | |
| # by Med Redha Khelifi (@MedRedha) | |
| # Enhanced for flexibility, robustness, and aesthetics. | |
| set -o pipefail | |
| VERSION="1.2.2" | |
| SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" | |
| NOTIFICATION_SOUND="Glass" | |
| NOTIFICATION_ICON="$SCRIPT_DIR/icon.png" | |
| GREEN='\033[0;92m' | |
| RED='\033[0;31m' | |
| YELLOW='\033[1;93m' | |
| ORANGE='\033[38;5;202m' | |
| CYAN='\033[0;96m' | |
| GRAY='\033[0;90m' | |
| BLUE='\033[0;34m' | |
| MAGENTA="\033[1;94m" | |
| NC='\033[0m' | |
| ERASE_LINE='\033[K' | |
| updates_available=0 | |
| tools_ok=0 | |
| current_check=0 | |
| total_checks=0 | |
| start_time=0 | |
| first_check=true | |
| outdated_npm_packages=() | |
| BASH_MAJOR_VERSION="${BASH_VERSION%%.*}" | |
| if [ "$BASH_MAJOR_VERSION" -ge 4 ]; then | |
| declare -A GH_API_CACHE | |
| declare -A NPM_CACHE | |
| declare -A check_results | |
| USE_CACHE=true | |
| else | |
| USE_CACHE=false | |
| fi | |
| source_nvm() { | |
| export NVM_DIR="$HOME/.nvm" | |
| [ -s "$NVM_DIR/nvm.sh" ] && source "$NVM_DIR/nvm.sh" --no-use | |
| } | |
| source_nvm | |
| fetch_gh_release() { | |
| local repo="$1" | |
| local result="" | |
| if [ "$USE_CACHE" = true ]; then | |
| local cache_key="${repo//\//_}" | |
| if [ -z "${GH_API_CACHE[$cache_key]}" ]; then | |
| result=$(curl -s "https://api.github.com/repos/$repo/releases/latest" 2>/dev/null | jq -r '.tag_name // empty' 2>/dev/null) | |
| GH_API_CACHE[$cache_key]="$result" | |
| else | |
| result="${GH_API_CACHE[$cache_key]}" | |
| fi | |
| else | |
| result=$(curl -s "https://api.github.com/repos/$repo/releases/latest" 2>/dev/null | jq -r '.tag_name // empty' 2>/dev/null) | |
| fi | |
| echo "$result" | |
| } | |
| fetch_npm_version() { | |
| local package="$1" | |
| local result="" | |
| if [ "$USE_CACHE" = true ]; then | |
| if [ -z "${NPM_CACHE[$package]}" ]; then | |
| result=$(npm view "$package" version 2>/dev/null) | |
| NPM_CACHE[$package]="$result" | |
| else | |
| result="${NPM_CACHE[$package]}" | |
| fi | |
| else | |
| result=$(npm view "$package" version 2>/dev/null) | |
| fi | |
| echo "$result" | |
| } | |
| is_latest_newer() { | |
| local current_ver=${1#v} latest_ver=${2#v} | |
| current_ver=${current_ver#\~}; current_ver=${current_ver#\^} | |
| [ -z "$current_ver" ] && current_ver="0" | |
| [ -z "$latest_ver" ] && latest_ver="0" | |
| if [ "$current_ver" == "$latest_ver" ]; then return 1; fi | |
| if [ "$(printf '%s\n' "$current_ver" "$latest_ver" | sort -V | tail -n1)" == "$latest_ver" ]; then | |
| return 0 | |
| else | |
| return 1 | |
| fi | |
| } | |
| draw_progress_bar() { | |
| local tool_name="$1" | |
| local percentage=$((current_check * 100 / total_checks)) | |
| local filled=$((current_check * 40 / total_checks)) | |
| local empty=$((40 - filled)) | |
| local elapsed=$(($(date +%s) - start_time)) | |
| local eta=0 | |
| if [ "$current_check" -gt 0 ]; then | |
| local avg_time=$((elapsed / current_check)) | |
| local remaining=$((total_checks - current_check)) | |
| eta=$((avg_time * remaining)) | |
| fi | |
| local bar="" | |
| for ((i=0; i<filled; i++)); do bar+="█"; done | |
| for ((i=0; i<empty; i++)); do bar+="░"; done | |
| printf "\r${ERASE_LINE}${CYAN}${bar}${NC} ${YELLOW}${percentage}%%${NC} | ${GRAY}ETA: ${eta}s${NC} | ${ORANGE}${current_check}/${total_checks}${NC} | Checking ${tool_name}..." | |
| } | |
| process_check_parallel() { | |
| local icon="$1" tool_name="$2" current_ver="$3" latest_ver="$4" update_cmd="$5" | |
| local display_ver="$current_ver" | |
| [ -z "$current_ver" ] && display_ver="not installed" | |
| [ -z "$latest_ver" ] && latest_ver="unknown" | |
| local result="" | |
| if [ "$latest_ver" = "unknown" ]; then | |
| result="${YELLOW}⚠ ${icon} ${tool_name} ${NC}version check unavailable ${CYAN}(${display_ver})${NC}|ok" | |
| elif is_latest_newer "$current_ver" "$latest_ver"; then | |
| result="${RED}⚠ ${icon} ${tool_name} ${NC}needs an update!\n ├─ Installed: ${YELLOW}${display_ver}${NC}\n ├─ Latest: ${GREEN}${latest_ver}${NC}\n └─ Action: ${CYAN}${update_cmd}${NC}|update" | |
| else | |
| result="${GREEN}✓ ${icon} ${tool_name} ${NC}is up-to-date ${CYAN}(${display_ver})${NC}|ok" | |
| fi | |
| if [ "$USE_CACHE" = true ]; then | |
| check_results["$tool_name"]="$result" | |
| fi | |
| echo "$result" | |
| } | |
| process_check() { | |
| local icon="$1" tool_name="$2" current_ver="$3" latest_ver="$4" update_cmd="$5" | |
| local display_ver="$current_ver" | |
| local is_not_installed=false | |
| [ -z "$current_ver" ] && display_ver="not installed" && is_not_installed=true | |
| [ -z "$latest_ver" ] && latest_ver="unknown" | |
| printf "\r${ERASE_LINE}" | |
| echo -e "---------------------------------" | |
| if [ "$latest_ver" = "unknown" ]; then | |
| echo -e "${YELLOW}⚠ ${icon} ${tool_name} ${NC}version check unavailable ${CYAN}(${display_ver})${NC}" | |
| ((tools_ok++)) | |
| elif is_latest_newer "$current_ver" "$latest_ver"; then | |
| ((updates_available++)) | |
| if [ "$is_not_installed" = true ]; then | |
| echo -e "${RED}✗ ${icon} ${tool_name} is not installed!${NC}" | |
| echo -e " ├─ Latest: ${GREEN}${latest_ver}${NC}" | |
| echo -e " └─ Install: ${CYAN}${update_cmd}${NC}" | |
| else | |
| echo -e "${RED}⚠ ${icon} ${tool_name} needs an update!${NC}" | |
| echo -e " ├─ Installed: ${YELLOW}${display_ver}${NC}" | |
| echo -e " ├─ Latest: ${GREEN}${latest_ver}${NC}" | |
| echo -e " └─ Action: ${CYAN}${update_cmd}${NC}" | |
| fi | |
| else | |
| ((tools_ok++)) | |
| echo -e "${GREEN}✓ ${icon} ${tool_name} ${NC}is up-to-date ${CYAN}(${display_ver})${NC}" | |
| fi | |
| } | |
| display_tool_version() { | |
| local icon="$1" tool_name="$2" current_ver="$3" | |
| [ -z "$current_ver" ] || [[ "$current_ver" == *"No such file or directory"* ]] && current_ver="not found" | |
| printf "\r${ERASE_LINE}" | |
| echo -e "---------------------------------" | |
| echo -e "${GREEN}✓ ${icon} ${tool_name}${NC}: ${CYAN}${current_ver}${NC}" | |
| } | |
| check_node_lts() { | |
| local icon="📟" | |
| local tool_name="Node (LTS)" | |
| local current_ver | |
| current_ver=$(node -v 2>/dev/null) | |
| local latest_lts_ver | |
| latest_lts_ver=$(nvm version-remote --lts 2>/dev/null) | |
| local display_ver="$current_ver" | |
| [ -z "$current_ver" ] && display_ver="not installed" | |
| printf "\r${ERASE_LINE}" | |
| echo -e "---------------------------------" | |
| if [ "$current_ver" == "$latest_lts_ver" ]; then | |
| ((tools_ok++)) | |
| echo -e "${GREEN}✓ ${icon} ${tool_name} ${NC}is correctly set ${CYAN}(${current_ver})${NC}" | |
| else | |
| ((updates_available++)) | |
| echo -e "${RED}⚠ ${icon} ${tool_name} ${NC}is not the active version." | |
| echo -e " ├─ Active: ${YELLOW}${display_ver}${NC}" | |
| echo -e " ├─ Latest LTS: ${GREEN}${latest_lts_ver}${NC}" | |
| echo -e " └─ Action: ${CYAN}nvm install --lts && nvm use --lts && nvm alias default 'lts/*'"${NC} | |
| fi | |
| } | |
| check_nvm() { | |
| local current_ver=$(nvm --version 2>/dev/null) | |
| local nvm_latest="" | |
| if command -v nvm &>/dev/null; then | |
| nvm_latest=$(fetch_gh_release "nvm-sh/nvm") | |
| if [ -z "$nvm_latest" ]; then | |
| nvm_latest=$(curl -s https://api.github.com/repos/nvm-sh/nvm/tags 2>/dev/null | jq -r '.[0].name' 2>/dev/null) | |
| fi | |
| local install_cmd="curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/\${latest_version}/install.sh | bash" | |
| else | |
| local install_cmd="curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash" | |
| fi | |
| process_check "🎒" "NVM" "$current_ver" "$nvm_latest" "$install_cmd" | |
| } | |
| check_yarn() { | |
| local current_ver=$(yarn -v 2>/dev/null) | |
| local latest_ver="" | |
| if command -v yarn &>/dev/null; then | |
| latest_ver=$(fetch_gh_release "yarnpkg/berry" | sed 's/^@yarnpkg\/cli\///') | |
| if [ -z "$latest_ver" ]; then | |
| latest_ver=$(curl -s https://api.github.com/repos/yarnpkg/berry/tags 2>/dev/null | jq -r '.[0].name' 2>/dev/null | sed 's/^@yarnpkg\/cli\///') | |
| fi | |
| local install_cmd="corepack enable && corepack prepare yarn@stable --activate" | |
| else | |
| local install_cmd="corepack enable && corepack prepare yarn@stable --activate" | |
| fi | |
| process_check "🧶" "Yarn" "$current_ver" "$latest_ver" "$install_cmd" | |
| } | |
| check_npm() { | |
| local current_ver=$(npm --version 2>/dev/null) | |
| local latest_ver="" | |
| if command -v npm &>/dev/null; then | |
| latest_ver=$(fetch_npm_version "npm") | |
| local install_cmd="npm install -g npm@latest" | |
| else | |
| local install_cmd="curl -L https://www.npmjs.com/install.sh | sh" | |
| fi | |
| process_check "📦" "npm" "$current_ver" "$latest_ver" "$install_cmd" | |
| } | |
| check_prettier() { | |
| process_check "💅" "Prettier" "$(prettier -v 2>/dev/null)" "$(fetch_npm_version "prettier")" "npm install -g prettier" | |
| } | |
| check_firebase_cli() { | |
| process_check "🔥" "Firebase CLI" "$(firebase --version 2>/dev/null)" "$(fetch_npm_version "firebase-tools")" "npm install -g firebase-tools" | |
| } | |
| check_ngrok() { | |
| local current_ver=$(ngrok version 2>/dev/null | awk '{print $NF}') | |
| local latest_ver=$(brew info ngrok 2>/dev/null | grep "^==> ngrok:" | awk '{print $3}' | cut -d',' -f1) | |
| process_check "🌍" "Ngrok" "$current_ver" "$latest_ver" "brew upgrade --cask ngrok" | |
| } | |
| check_askcli() { | |
| process_check "🎙️ " "ASK CLI" "$(ask --version 2>/dev/null)" "$(fetch_npm_version "ask-cli")" "npm install -g ask-cli" | |
| } | |
| check_n8n() { | |
| process_check "🔗" "n8n" "$(n8n --version 2>/dev/null)" "$(fetch_npm_version "n8n")" "npm update -g n8n" | |
| } | |
| check_ruby() { | |
| if command -v rbenv &>/dev/null; then | |
| process_check "💎" "Ruby (rbenv)" "$(rbenv version 2>/dev/null | cut -d' ' -f1)" "$(rbenv install -l 2>/dev/null | grep -E '^[0-9]+\.[0-9]+\.[0-9]+$' | tail -n 1)" "rbenv install <latest_version> && rbenv global <latest_version>" | |
| else | |
| process_check "💎" "Ruby (System)" "$(ruby -v 2>/dev/null | awk '{print $2}' | cut -d'p' -f1)" "$(brew info --json ruby 2>/dev/null | jq -r '.[0].versions.stable')" "brew upgrade ruby" | |
| fi | |
| } | |
| check_rubygems() { | |
| process_check "💍" "RubyGems" "$(gem -v 2>/dev/null)" "$(curl -s https://rubygems.org/api/v1/gems/rubygems-update.json 2>/dev/null | jq -r .version)" "gem update --system" | |
| } | |
| check_python() { | |
| process_check "🐍" "Python" "$(python3 --version 2>/dev/null | awk '{print $2}')" "$(brew info --json python@3 2>/dev/null | jq -r '.[0].versions.stable')" "brew upgrade python@3" | |
| } | |
| check_pip() { | |
| process_check "🪈" "pip" "$(pip3 --version 2>/dev/null | awk '{print $2}')" "$(curl -s https://pypi.org/pypi/pip/json 2>/dev/null | jq -r .info.version)" "pip3 install --upgrade pip" | |
| } | |
| check_bundler() { | |
| process_check "🛠️ " "Bundler" "$(bundle -v 2>/dev/null | awk '{print $3}')" "$(curl -s https://rubygems.org/api/v1/gems/bundler.json 2>/dev/null | jq -r .version)" "gem install bundler && bundle update --bundler" | |
| } | |
| check_fastlane() { | |
| local version=$(fastlane --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -n 1) | |
| process_check "🚀" "fastlane" "$version" "$(curl -s https://rubygems.org/api/v1/gems/fastlane.json 2>/dev/null | jq -r .version)" "gem install fastlane" | |
| } | |
| check_git() { | |
| process_check "🔀" "Git" "$(git --version 2>/dev/null | awk '{print $3}')" "$(brew info --json git 2>/dev/null | jq -r '.[0].versions.stable')" "brew upgrade git" | |
| } | |
| check_cocoapods() { | |
| process_check "🫘" "Cocoapods" "$(pod --version 2>/dev/null)" "$(curl -s https://rubygems.org/api/v1/gems/cocoapods.json 2>/dev/null | jq -r .version)" "gem install cocoapods" | |
| } | |
| check_typescript() { | |
| process_check "📘" "TypeScript" "$(tsc -v 2>/dev/null | awk '{print $2}')" "$(fetch_npm_version "typescript")" "npm install -g typescript" | |
| } | |
| check_homebrew() { | |
| local current_ver=$(brew --version 2>/dev/null | head -n 1 | awk '{print $2}') | |
| local latest_ver="" | |
| if command -v brew &>/dev/null; then | |
| latest_ver=$(fetch_gh_release "Homebrew/brew") | |
| if [ -z "$latest_ver" ]; then | |
| latest_ver=$(curl -s https://api.github.com/repos/Homebrew/brew/tags 2>/dev/null | jq -r '.[0].name' 2>/dev/null) | |
| fi | |
| local install_cmd="brew update && brew upgrade" | |
| else | |
| local install_cmd="/bin/bash -c \"\$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\"" | |
| fi | |
| process_check "🍺" "Homebrew" "$current_ver" "$latest_ver" "$install_cmd" | |
| } | |
| check_watchman() { | |
| process_check "👀" "Watchman" "$(watchman -v 2>/dev/null)" "$(brew info --json watchman 2>/dev/null | jq -r '.[0].versions.stable')" "brew upgrade watchman" | |
| } | |
| check_java() { | |
| local java_ver=$(java -version 2>&1 | awk -F '"' '/version/ {print $2}' | cut -d'_' -f1) | |
| process_check "☕" "Java" "$java_ver" "$(brew info --json openjdk 2>/dev/null | jq -r '.[0].versions.stable')" "brew upgrade openjdk" | |
| } | |
| check_jq() { | |
| process_check "🔧" "JQ" "$(jq --version 2>/dev/null | cut -d- -f2)" "$(brew info --json jq 2>/dev/null | jq -r '.[0].versions.stable')" "brew upgrade jq" | |
| } | |
| check_omzsh() { | |
| local omz_dir="${ZSH:-$HOME/.oh-my-zsh}" | |
| if [ -d "$omz_dir" ]; then | |
| local local_hash=$(cd "$omz_dir" 2>/dev/null && git rev-parse HEAD 2>/dev/null) | |
| local remote_hash=$(cd "$omz_dir" 2>/dev/null && git ls-remote origin HEAD 2>/dev/null | awk '{print $1}') | |
| local local_short="${local_hash:0:7}" | |
| local remote_short="${remote_hash:0:7}" | |
| printf "\r${ERASE_LINE}" | |
| echo -e "---------------------------------" | |
| if [ -z "$remote_hash" ]; then | |
| ((tools_ok++)) | |
| echo -e "${YELLOW}⚠ 🎨 Oh My Zsh ${NC}version check unavailable ${CYAN}(${local_short})${NC}" | |
| elif [ "$local_hash" = "$remote_hash" ]; then | |
| ((tools_ok++)) | |
| echo -e "${GREEN}✓ 🎨 Oh My Zsh ${NC}is up-to-date ${CYAN}(${local_short})${NC}" | |
| else | |
| if (cd "$omz_dir" 2>/dev/null && git fetch origin --quiet 2>/dev/null && git merge-base --is-ancestor HEAD origin/HEAD 2>/dev/null); then | |
| ((updates_available++)) | |
| echo -e "${RED}⚠ 🎨 Oh My Zsh needs an update!${NC}" | |
| echo -e " ├─ Installed: ${YELLOW}${local_short}${NC}" | |
| echo -e " ├─ Latest: ${GREEN}${remote_short}${NC}" | |
| echo -e " └─ Action: ${CYAN}omz update${NC}" | |
| else | |
| ((tools_ok++)) | |
| echo -e "${GREEN}✓ 🎨 Oh My Zsh ${NC}is up-to-date ${CYAN}(${local_short})${NC}" | |
| fi | |
| fi | |
| else | |
| printf "\r${ERASE_LINE}" | |
| echo -e "---------------------------------" | |
| ((updates_available++)) | |
| echo -e "${RED}✗ 🎨 Oh My Zsh is not installed!${NC}" | |
| echo -e " └─ Install: ${CYAN}sh -c \"\$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)\"${NC}" | |
| fi | |
| } | |
| check_claude_code() { | |
| local current_ver=$(claude --version 2>/dev/null | awk '{print $1}') | |
| local latest_ver=$(curl -s "https://formulae.brew.sh/api/cask/claude-code.json" 2>/dev/null | jq -r '.version' 2>/dev/null) | |
| process_check "👾" "Claude Code" "$current_ver" "$latest_ver" "brew upgrade --cask claude-code" | |
| } | |
| check_gradle() { | |
| local current_ver=$(gradle --version 2>/dev/null | grep "Gradle" | awk '{print $2}') | |
| local latest_ver=$(curl -s https://services.gradle.org/versions/current 2>/dev/null | jq -r '.version') | |
| process_check "🐘" "Gradle" "$current_ver" "$latest_ver" "brew upgrade gradle" | |
| } | |
| display_xcode() { | |
| display_tool_version "🔨" "Xcode" "$(xcrun xctrace version 2>/dev/null | head -n 1)" | |
| } | |
| display_android_sdk() { | |
| local sdk_path="${ANDROID_HOME:-$HOME/Library/Android/sdk}/build-tools" | |
| if [ -d "$sdk_path" ]; then | |
| display_tool_version "🤖" "Android SDK" "$(ls "$sdk_path" 2>/dev/null | tail -n 1)" | |
| fi | |
| } | |
| display_android_ndk() { | |
| local ndk_path="${ANDROID_HOME:-$HOME/Library/Android/sdk}/ndk" | |
| if [ -d "$ndk_path" ]; then | |
| display_tool_version "🔩" "Android NDK" "$(ls "$ndk_path" 2>/dev/null | tail -n 1)" | |
| fi | |
| } | |
| check_npm_global_outdated() { | |
| printf "\r${ERASE_LINE}" | |
| echo -e "---------------------------------" | |
| local outdated_output=$(npm outdated -g --json 2>/dev/null) | |
| if [ -n "$outdated_output" ] && [ "$outdated_output" != "{}" ]; then | |
| local count=$(echo "$outdated_output" | jq 'length' 2>/dev/null) | |
| if [ "$count" -gt 0 ]; then | |
| ((updates_available += count)) | |
| echo -e "${RED}⚠ $count global npm package(s) outdated${NC}" | |
| echo "$outdated_output" | jq -r 'to_entries[] | " ├─ \(.key): \(.value.current) → \(.value.latest)"' 2>/dev/null | |
| echo -e " └─ Action: ${CYAN}npm update -g${NC}" | |
| else | |
| ((tools_ok++)) | |
| echo -e "${GREEN}✓ All global npm packages are up-to-date${NC}" | |
| fi | |
| else | |
| ((tools_ok++)) | |
| echo -e "${GREEN}✓ All global npm packages are up-to-date${NC}" | |
| fi | |
| } | |
| send_notification() { | |
| local title="$1" | |
| local message="$2" | |
| local sound="${3:-default}" | |
| if command -v terminal-notifier &>/dev/null; then | |
| if [ -n "$NOTIFICATION_ICON" ] && [ -f "$NOTIFICATION_ICON" ]; then | |
| if [[ "$NOTIFICATION_ICON" == *.png ]]; then | |
| (terminal-notifier -title "$title" -message "$message" -sound "$sound" -contentImage "$NOTIFICATION_ICON" &) >/dev/null 2>&1 | |
| else | |
| local temp_icon="/tmp/pulse_icon.png" | |
| if command -v sips &>/dev/null; then | |
| sips -s format png "$NOTIFICATION_ICON" --out "$temp_icon" &>/dev/null | |
| (terminal-notifier -title "$title" -message "$message" -sound "$sound" -contentImage "$temp_icon" &) >/dev/null 2>&1 | |
| else | |
| (terminal-notifier -title "$title" -message "$message" -sound "$sound" -appIcon "$NOTIFICATION_ICON" &) >/dev/null 2>&1 | |
| fi | |
| fi | |
| else | |
| (terminal-notifier -title "$title" -message "$message" -sound "$sound" &) >/dev/null 2>&1 | |
| fi | |
| return 0 | |
| fi | |
| title="${title//\\/\\\\}" | |
| title="${title//\"/\\\"}" | |
| message="${message//\\/\\\\}" | |
| message="${message//\"/\\\"}" | |
| osascript -e "display notification \"$message\" with title \"$title\" sound name \"$sound\"" 2>/dev/null | |
| return $? | |
| } | |
| display_logo() { | |
| echo -e "${ORANGE}$(figlet -c -k -f larry3d "Pulse" 2>/dev/null | sed '/^ *$/d')${NC}" | |
| echo -e "\n${CYAN}$(figlet -c -f term "Checking the vital signs of your developer toolchain." 2>/dev/null | sed '/^ *$/d')${NC}" | |
| echo -e "\n${GRAY}$(figlet -c -f term "by Med Redha Khelifi ${MAGENTA}(v${VERSION})" 2>/dev/null | sed '/^ *$/d')${NC}" | |
| } | |
| check_dependencies() { | |
| local missing_deps=0 | |
| for dep in curl jq figlet; do | |
| if ! command -v "$dep" &> /dev/null; then | |
| echo -e "${RED}Error: Required dependency '$dep' is not installed.${NC}" | |
| missing_deps=1 | |
| fi | |
| done | |
| [ "$missing_deps" -eq 1 ] && exit 1 | |
| } | |
| run_with_progress() { | |
| local tool_name="$1" function_to_call="$2" | |
| ((current_check++)) | |
| draw_progress_bar "$tool_name" | |
| "$function_to_call" | |
| } | |
| check_rn_package() { | |
| local pkg="$1" icon="$2" name="$3" update_cmd="$4" | |
| local current_ver=$(jq -r ".dependencies[\"$pkg\"] // .devDependencies[\"$pkg\"] // \"\"" package.json 2>/dev/null) | |
| if [ -n "$current_ver" ]; then | |
| local latest_ver=$(fetch_npm_version "$pkg") | |
| process_check "$icon" "$name" "$current_ver" "$latest_ver" "$update_cmd" | |
| else | |
| printf "\r${ERASE_LINE}" | |
| fi | |
| } | |
| print_category_header() { | |
| local category="$1" | |
| local color="$2" | |
| printf "\r${ERASE_LINE}" | |
| echo "" | |
| echo -e "${color}${category}${NC}" | |
| } | |
| count_checks() { | |
| total_checks=23 | |
| if [ -f "package.json" ]; then | |
| [ -n "$(jq -r '.dependencies["react-native"] // .devDependencies["react-native"] // ""' package.json 2>/dev/null)" ] && ((total_checks++)) | |
| [ -n "$(jq -r '.dependencies["@react-native-community/cli"] // .devDependencies["@react-native-community/cli"] // ""' package.json 2>/dev/null)" ] && ((total_checks++)) | |
| fi | |
| total_checks=$((total_checks + 4)) | |
| } | |
| main() { | |
| check_dependencies | |
| display_logo | |
| count_checks | |
| start_time=$(date +%s) | |
| print_category_header "• Core Tools:" "${ORANGE}" | |
| run_with_progress "Node (LTS)" "check_node_lts" | |
| run_with_progress "NVM" "check_nvm" | |
| run_with_progress "npm" "check_npm" | |
| run_with_progress "Yarn" "check_yarn" | |
| run_with_progress "Git" "check_git" | |
| run_with_progress "Homebrew" "check_homebrew" | |
| print_category_header "• React Native Stack:" "${ORANGE}" | |
| run_with_progress "Watchman" "check_watchman" | |
| run_with_progress "Cocoapods" "check_cocoapods" | |
| if [ -f "package.json" ]; then | |
| if [ -n "$(jq -r '.dependencies["@react-native-community/cli"] // .devDependencies["@react-native-community/cli"] // ""' package.json 2>/dev/null)" ]; then | |
| run_with_progress "React Native CLI" "check_rn_package '@react-native-community/cli' '⚛️' 'React Native CLI' 'yarn add -D @react-native-community/cli@latest'" | |
| fi | |
| if [ -n "$(jq -r '.dependencies["react-native"] // .devDependencies["react-native"] // ""' package.json 2>/dev/null)" ]; then | |
| run_with_progress "React Native" "check_rn_package 'react-native' '⚛️' 'React Native' 'yarn add react-native@latest'" | |
| fi | |
| fi | |
| run_with_progress "Xcode" "display_xcode" | |
| run_with_progress "Android SDK" "display_android_sdk" | |
| run_with_progress "Android NDK" "display_android_ndk" | |
| run_with_progress "Gradle" "check_gradle" | |
| run_with_progress "Java" "check_java" | |
| print_category_header "• CLI Tools:" "${ORANGE}" | |
| run_with_progress "Firebase CLI" "check_firebase_cli" | |
| run_with_progress "ngrok" "check_ngrok" | |
| run_with_progress "Claude Code" "check_claude_code" | |
| run_with_progress "ASK CLI" "check_askcli" | |
| run_with_progress "JQ" "check_jq" | |
| run_with_progress "Oh My Zsh" "check_omzsh" | |
| print_category_header "• Ruby Stack:" "${ORANGE}" | |
| run_with_progress "Ruby" "check_ruby" | |
| run_with_progress "RubyGems" "check_rubygems" | |
| run_with_progress "Bundler" "check_bundler" | |
| run_with_progress "fastlane" "check_fastlane" | |
| print_category_header "• Python Stack:" "${ORANGE}" | |
| run_with_progress "Python" "check_python" | |
| run_with_progress "pip" "check_pip" | |
| print_category_header "• Code Quality:" "${ORANGE}" | |
| run_with_progress "TypeScript" "check_typescript" | |
| run_with_progress "Prettier" "check_prettier" | |
| print_category_header "• Global npm packages:" "${ORANGE}" | |
| run_with_progress "Global npm packages" "check_npm_global_outdated" | |
| local end_time=$(date +%s) | |
| local elapsed=$((end_time - start_time)) | |
| printf "\r${ERASE_LINE}" | |
| echo "" | |
| echo -e "🏁 ${BLUE}Pulse Check Complete!${NC}" | |
| echo "" | |
| echo -e " ${GREEN}✓ ${tools_ok} tools are up-to-date.${NC}" | |
| if [ "$updates_available" -gt 0 ]; then | |
| echo -e " ${RED}⚠ ${updates_available} update(s) available.${NC}" | |
| fi | |
| echo -e " ${CYAN}⏱ ${elapsed}s until completion${NC}" | |
| echo "" | |
| if [ "$updates_available" -gt 0 ]; then | |
| send_notification "Pulse Check Complete" "${updates_available} update(s) available, ${tools_ok} tools up-to-date" "$NOTIFICATION_SOUND" | |
| else | |
| send_notification "Pulse Check Complete" "All ${tools_ok} tools are up-to-date! ✨" "$NOTIFICATION_SOUND" | |
| fi | |
| } | |
| main |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment