#!/bin/bash # Colors and formatting PINK='\033[38;5;213m' BLUE='\033[38;5;117m' GREEN='\033[38;5;156m' YELLOW='\033[38;5;229m' CYAN='\033[38;5;123m' WHITE='\033[1;37m' DIM='\033[2m' BOLD='\033[1m' RESET='\033[0m' # Box drawing characters TOP_LEFT='╭' TOP_RIGHT='╮' BOTTOM_LEFT='╰' BOTTOM_RIGHT='╯' HORIZONTAL='─' VERTICAL='│' ARROW='❯' SPARKLE='✨' STAR='★' # Clear screen and show header clear echo -e "${PINK}${BOLD} ${TOP_LEFT}────────────────────────────────────${TOP_RIGHT}" echo -e " ${VERTICAL} ${SPARKLE} ${WHITE}Ephemere Script Runner${PINK} ${SPARKLE} ${VERTICAL}" echo -e " ${BOTTOM_LEFT}────────────────────────────────────${BOTTOM_RIGHT}${RESET}" # Function to display a menu and get selection select_option() { local prompt="$1" shift local options=("$@") local selected=0 local key # Hide cursor tput civis # Trap to restore cursor on exit trap 'tput cnorm' EXIT while true; do # Clear previous menu (move up and clear lines) if [ -n "$menu_drawn" ]; then for ((i=0; i<=${#options[@]}+1; i++)); do tput cuu1 tput el done fi menu_drawn=1 # Print prompt echo -e "${CYAN}${BOLD} $prompt${RESET}" echo "" # Print options for i in "${!options[@]}"; do if [ $i -eq $selected ]; then echo -e " ${PINK}${BOLD}$ARROW ${WHITE}${options[$i]}${RESET}" else echo -e " ${DIM}${options[$i]}${RESET}" fi done # Read a single keypress read -rsn1 key # Handle arrow keys (they come as escape sequences) if [[ $key == $'\x1b' ]]; then read -rsn2 key case $key in '[A') # Up arrow ((selected--)) [ $selected -lt 0 ] && selected=$((${#options[@]}-1)) ;; '[B') # Down arrow ((selected++)) [ $selected -ge ${#options[@]} ] && selected=0 ;; esac elif [[ $key == "" ]]; then # Enter pressed tput cnorm # Show cursor unset menu_drawn return $selected elif [[ $key == "q" || $key == "Q" ]]; then tput cnorm echo -e "\n${YELLOW} Bye bye! $SPARKLE${RESET}\n" exit 0 fi done } # Step 1: Select Language echo "" languages=("TypeScript" "Python" "Bash") select_option "Select a language:" "${languages[@]}" lang_index=$? language="${languages[$lang_index]}" echo -e "\n ${GREEN}$STAR Selected: ${WHITE}$language${RESET}\n" # Step 2: Get categories based on language if [ "$language" == "TypeScript" ]; then script_dir="typescript/src" runner="pnpm tsx" # Get subdirectories as categories (excluding utils and interfaces) mapfile -t categories < <(find "$script_dir" -mindepth 1 -maxdepth 1 -type d ! -name 'utils' ! -name 'interfaces' -exec basename {} \; | sort) elif [ "$language" == "Python" ]; then script_dir="python" runner="uv run python" # Get subdirectories as categories (excluding __pycache__ and .venv) mapfile -t categories < <(find "$script_dir" -mindepth 1 -maxdepth 1 -type d ! -name '__pycache__' ! -name '.venv' ! -name '*.egg-info' -exec basename {} \; | sort) # Add "Root Scripts" option for Python files in root if ls "$script_dir"/*.py &>/dev/null 2>&1; then categories=("Root Scripts" "${categories[@]}") fi else # Bash script_dir="bash" runner="bash" # Get subdirectories as categories mapfile -t categories < <(find "$script_dir" -mindepth 1 -maxdepth 1 -type d -exec basename {} \; | sort) # Add "Root Scripts" option for bash files in root fi if [ ${#categories[@]} -eq 0 ]; then echo -e " ${YELLOW}No script categories found!${RESET}\n" exit 1 fi select_option "Select a category:" "${categories[@]}" cat_index=$? category="${categories[$cat_index]}" echo -e "\n ${GREEN}$STAR Selected: ${WHITE}$category${RESET}\n" # Step 3: Get scripts in category if [ "$category" == "Root Scripts" ]; then search_dir="$script_dir" if [ "$language" == "Python" ]; then mapfile -t scripts < <(find "$search_dir" -maxdepth 1 -name "*.py" -exec basename {} \; | sort) elif [ "$language" == "Bash" ]; then mapfile -t scripts < <(find "$search_dir" -maxdepth 1 -name "*.sh" -exec basename {} \; | sort) fi elif [ "$language" == "TypeScript" ]; then search_dir="$script_dir/$category" mapfile -t scripts < <(find "$search_dir" -name "*.ts" -exec basename {} \; | sort) elif [ "$language" == "Python" ]; then search_dir="$script_dir/$category" mapfile -t scripts < <(find "$search_dir" -name "*.py" ! -name "__init__.py" -exec basename {} \; | sort) else # Bash search_dir="$script_dir/$category" mapfile -t scripts < <(find "$search_dir" -name "*.sh" -exec basename {} \; | sort) fi if [ ${#scripts[@]} -eq 0 ]; then echo -e " ${YELLOW}No scripts found in this category!${RESET}\n" exit 1 fi select_option "Select a script:" "${scripts[@]}" script_index=$? script="${scripts[$script_index]}" echo -e "\n ${GREEN}$STAR Selected: ${WHITE}$script${RESET}\n" # Build the full script path if [ "$category" == "Root Scripts" ]; then script_path="$script" elif [ "$language" == "TypeScript" ]; then script_path="src/$category/$script" elif [ "$language" == "Python" ]; then script_path="$category/$script" else # Bash script_path="bash/$category/$script" fi # Show what we're about to run echo -e "${BLUE}${BOLD} ${TOP_LEFT}───────────────────────${TOP_RIGHT}" echo -e " ${VERTICAL} ${WHITE}Running script...${BLUE} ${VERTICAL}" echo -e " ${BOTTOM_LEFT}───────────────────────${BOTTOM_RIGHT}${RESET}" echo "" echo -e " ${DIM}Language:${RESET} $language" echo -e " ${DIM}Category:${RESET} $category" echo -e " ${DIM}Script:${RESET} $script" echo "" # Run the script with 1Password env injection if [ "$language" == "TypeScript" ]; then cd typescript echo -e " ${DIM}$ op run --env-file=../prod.env -- $runner $script_path${RESET}\n" op run --env-file=../prod.env --no-masking -- $runner "$script_path" elif [ "$language" == "Python" ]; then cd python echo -e " ${DIM}$ op run --env-file=../prod.env -- $runner $script_path${RESET}\n" op run --env-file=../prod.env --no-masking -- $runner "$script_path" else # Bash echo -e " ${DIM}$ op run --env-file=prod.env -- $runner $script_path${RESET}\n" op run --env-file=prod.env --no-masking -- $runner "$script_path" fi exit_code=$? echo "" if [ $exit_code -eq 0 ]; then echo -e " ${GREEN}${BOLD}$SPARKLE Script completed successfully! $SPARKLE${RESET}\n" else echo -e " ${YELLOW}${BOLD}Script exited with code $exit_code${RESET}\n" fi