| 1 | #!/bin/bash |
| 2 | |
| 3 | # Parrot shell hook - source this in your .bashrc or .zshrc |
| 4 | |
| 5 | # Path to parrot binary - update this if needed |
| 6 | PARROT_BIN="parrot" |
| 7 | |
| 8 | # Function to check if parrot binary exists |
| 9 | parrot_check() { |
| 10 | if ! command -v "$PARROT_BIN" &> /dev/null; then |
| 11 | echo "⚠️ Parrot binary not found. Make sure 'parrot' is in your PATH." |
| 12 | return 1 |
| 13 | fi |
| 14 | return 0 |
| 15 | } |
| 16 | |
| 17 | # Function called after each command in bash |
| 18 | parrot_prompt_command() { |
| 19 | local exit_code=$? |
| 20 | local last_cmd=$(history 1 | sed 's/^[ ]*[0-9]*[ ]*//') |
| 21 | |
| 22 | # Only mock if command failed and we have a command |
| 23 | if [ $exit_code -ne 0 ] && [ -n "$last_cmd" ] && parrot_check; then |
| 24 | # Run parrot in background to avoid blocking shell if PARROT_ASYNC is set |
| 25 | if [ "${PARROT_ASYNC:-}" = "true" ]; then |
| 26 | "$PARROT_BIN" mock "$last_cmd" "$exit_code" & |
| 27 | else |
| 28 | "$PARROT_BIN" mock "$last_cmd" "$exit_code" |
| 29 | fi |
| 30 | fi |
| 31 | } |
| 32 | |
| 33 | # Function called before each command in zsh |
| 34 | parrot_preexec() { |
| 35 | PARROT_LAST_CMD="$1" |
| 36 | } |
| 37 | |
| 38 | # Function called after each command in zsh |
| 39 | parrot_precmd() { |
| 40 | local exit_code=$? |
| 41 | |
| 42 | # Only mock if command failed and we have a command |
| 43 | if [ $exit_code -ne 0 ] && [ -n "$PARROT_LAST_CMD" ] && parrot_check; then |
| 44 | # Run parrot in background to avoid blocking shell if PARROT_ASYNC is set |
| 45 | if [ "${PARROT_ASYNC:-}" = "true" ]; then |
| 46 | "$PARROT_BIN" mock "$PARROT_LAST_CMD" "$exit_code" & |
| 47 | else |
| 48 | "$PARROT_BIN" mock "$PARROT_LAST_CMD" "$exit_code" |
| 49 | fi |
| 50 | fi |
| 51 | } |
| 52 | |
| 53 | # Setup based on shell type (only show messages if not already initialized) |
| 54 | if [ -z "$PARROT_INITIALIZED" ]; then |
| 55 | if [ -n "$BASH_VERSION" ]; then |
| 56 | # Bash setup |
| 57 | PROMPT_COMMAND="parrot_prompt_command${PROMPT_COMMAND:+;$PROMPT_COMMAND}" |
| 58 | # Only show message in interactive shells |
| 59 | if [[ $- == *i* ]]; then |
| 60 | echo "🦜 Parrot is now watching your bash commands..." |
| 61 | fi |
| 62 | elif [ -n "$ZSH_VERSION" ]; then |
| 63 | # Zsh setup |
| 64 | autoload -Uz add-zsh-hook |
| 65 | add-zsh-hook preexec parrot_preexec |
| 66 | add-zsh-hook precmd parrot_precmd |
| 67 | # Only show message in interactive shells |
| 68 | if [[ -o interactive ]]; then |
| 69 | echo "🦜 Parrot is now watching your zsh commands..." |
| 70 | fi |
| 71 | else |
| 72 | echo "⚠️ Parrot: Unsupported shell. Only bash, zsh, and fish are supported." |
| 73 | echo "💡 For fish shell, use parrot-hook.fish instead." |
| 74 | fi |
| 75 | |
| 76 | # Show performance tip only in interactive shells |
| 77 | if [[ $- == *i* ]] || [[ -o interactive ]] 2>/dev/null; then |
| 78 | if [ "${PARROT_ASYNC:-}" != "true" ]; then |
| 79 | echo "💡 Tip: Set PARROT_ASYNC=true to prevent terminal hangs on slow networks" |
| 80 | fi |
| 81 | fi |
| 82 | |
| 83 | # Mark as initialized for this shell session |
| 84 | export PARROT_INITIALIZED=1 |
| 85 | else |
| 86 | # Silent re-initialization (e.g., when sourcing .zshrc again) |
| 87 | if [ -n "$BASH_VERSION" ]; then |
| 88 | PROMPT_COMMAND="parrot_prompt_command${PROMPT_COMMAND:+;$PROMPT_COMMAND}" |
| 89 | elif [ -n "$ZSH_VERSION" ]; then |
| 90 | autoload -Uz add-zsh-hook |
| 91 | add-zsh-hook preexec parrot_preexec |
| 92 | add-zsh-hook precmd parrot_precmd |
| 93 | fi |
| 94 | fi |