|
27 | 27 |
|
28 | 28 | set -e |
29 | 29 |
|
30 | | -VERSION="0.2.0" |
| 30 | +VERSION="0.3.0" |
31 | 31 | CONFIG_DIR="$HOME/.crabcode" |
32 | 32 | CONFIG_FILE="$CONFIG_DIR/config.yaml" |
33 | 33 | WIP_BASE="$CONFIG_DIR/wip" |
@@ -1209,6 +1209,9 @@ cleanup_workspace() { |
1209 | 1209 |
|
1210 | 1210 | reset_submodules "$dir" |
1211 | 1211 |
|
| 1212 | + # Record mood event |
| 1213 | + mood_record_event "cleanup" "workspace $num" |
| 1214 | + |
1212 | 1215 | success "Workspace $num cleaned and reset to origin/main" |
1213 | 1216 | } |
1214 | 1217 |
|
@@ -1287,6 +1290,9 @@ restart_workspace() { |
1287 | 1290 | sleep 0.5 |
1288 | 1291 | [ -n "$claude_cmd" ] && tmux send-keys -t "$SESSION_NAME:$window_name.$p_main" "clear && $claude_cmd" C-m |
1289 | 1292 |
|
| 1293 | + # Record mood event |
| 1294 | + mood_record_event "restart" "workspace $num" |
| 1295 | + |
1290 | 1296 | success "Workspace $num restarted!" |
1291 | 1297 | else |
1292 | 1298 | echo -e "${YELLOW} Not in tmux session - run 'crabcode $num' to start${NC}" |
@@ -1587,6 +1593,9 @@ wip_save() { |
1587 | 1593 | } |
1588 | 1594 | EOF |
1589 | 1595 |
|
| 1596 | + # Record mood event |
| 1597 | + mood_record_event "wip_save" "$slug" |
| 1598 | + |
1590 | 1599 | success "WIP saved: $slug" |
1591 | 1600 | echo -e " ${BLUE}$summary${NC}" |
1592 | 1601 | echo " Location: $wip_path" |
@@ -3718,6 +3727,268 @@ show_doctor() { |
3718 | 3727 | fi |
3719 | 3728 | } |
3720 | 3729 |
|
| 3730 | +# ============================================================================= |
| 3731 | +# Crab Mood - Fun ASCII crab that reacts to your work |
| 3732 | +# ============================================================================= |
| 3733 | + |
| 3734 | +MOOD_FILE="$CONFIG_DIR/mood.json" |
| 3735 | + |
| 3736 | +# ASCII art for different moods |
| 3737 | +crab_art_happy() { |
| 3738 | + cat << 'EOF' |
| 3739 | + \o/ |
| 3740 | + ( ˆ ᴗ ˆ ) |
| 3741 | + /)🦀(\ |
| 3742 | +
|
| 3743 | +EOF |
| 3744 | +} |
| 3745 | + |
| 3746 | +crab_art_excited() { |
| 3747 | + cat << 'EOF' |
| 3748 | + \(★ω★)/ |
| 3749 | + /) 🎉 (\ |
| 3750 | + 🦀 |
| 3751 | +
|
| 3752 | +EOF |
| 3753 | +} |
| 3754 | + |
| 3755 | +crab_art_working() { |
| 3756 | + cat << 'EOF' |
| 3757 | + 💻 |
| 3758 | + ( •_•) |
| 3759 | + /)🦀(\ |
| 3760 | +
|
| 3761 | +EOF |
| 3762 | +} |
| 3763 | + |
| 3764 | +crab_art_nervous() { |
| 3765 | + cat << 'EOF' |
| 3766 | + 😰 |
| 3767 | + (°△°;) |
| 3768 | + /)🦀(\ |
| 3769 | +
|
| 3770 | +EOF |
| 3771 | +} |
| 3772 | + |
| 3773 | +crab_art_sleepy() { |
| 3774 | + cat << 'EOF' |
| 3775 | + 💤 |
| 3776 | + ( -_-) |
| 3777 | + /)🦀(\ |
| 3778 | +
|
| 3779 | +EOF |
| 3780 | +} |
| 3781 | + |
| 3782 | +crab_art_chill() { |
| 3783 | + cat << 'EOF' |
| 3784 | + 🌴 |
| 3785 | + ( ˘ω˘) |
| 3786 | + /)🦀(\ 🍹 |
| 3787 | +
|
| 3788 | +EOF |
| 3789 | +} |
| 3790 | + |
| 3791 | +crab_art_celebrating() { |
| 3792 | + cat << 'EOF' |
| 3793 | + 🎊\(^o^)/🎊 |
| 3794 | + /) 🦀 (\ |
| 3795 | + 🎉 🎉 🎉 |
| 3796 | +
|
| 3797 | +EOF |
| 3798 | +} |
| 3799 | + |
| 3800 | +# Record a mood event |
| 3801 | +mood_record_event() { |
| 3802 | + local event_type="$1" |
| 3803 | + local details="${2:-}" |
| 3804 | + local timestamp=$(date +%s) |
| 3805 | + |
| 3806 | + mkdir -p "$CONFIG_DIR" |
| 3807 | + |
| 3808 | + # Initialize mood file if doesn't exist |
| 3809 | + if [ ! -f "$MOOD_FILE" ]; then |
| 3810 | + echo '{"events":[],"stats":{"commits":0,"cleanups":0,"restarts":0,"wip_saves":0,"prs_merged":0}}' > "$MOOD_FILE" |
| 3811 | + fi |
| 3812 | + |
| 3813 | + # Add event (keep last 50 events) |
| 3814 | + if command_exists jq; then |
| 3815 | + local tmp_file="/tmp/mood_$$" |
| 3816 | + jq --arg type "$event_type" --arg details "$details" --arg ts "$timestamp" \ |
| 3817 | + '.events = ([{type: $type, details: $details, timestamp: ($ts | tonumber)}] + .events)[:50] | |
| 3818 | + if $type == "commit" then .stats.commits += 1 |
| 3819 | + elif $type == "cleanup" then .stats.cleanups += 1 |
| 3820 | + elif $type == "restart" then .stats.restarts += 1 |
| 3821 | + elif $type == "wip_save" then .stats.wip_saves += 1 |
| 3822 | + elif $type == "pr_merged" then .stats.prs_merged += 1 |
| 3823 | + else . end' "$MOOD_FILE" > "$tmp_file" && mv "$tmp_file" "$MOOD_FILE" |
| 3824 | + fi |
| 3825 | +} |
| 3826 | + |
| 3827 | +# Calculate current mood based on events and context |
| 3828 | +mood_calculate() { |
| 3829 | + local now=$(date +%s) |
| 3830 | + local hour=$(date +%H) |
| 3831 | + local day_of_week=$(date +%u) # 1=Monday, 7=Sunday |
| 3832 | + |
| 3833 | + # Default mood |
| 3834 | + local mood="working" |
| 3835 | + local message="Keep coding!" |
| 3836 | + |
| 3837 | + # Check if we have jq for JSON parsing |
| 3838 | + if ! command_exists jq; then |
| 3839 | + echo "working:No jq installed - but keep up the great work!" |
| 3840 | + return |
| 3841 | + fi |
| 3842 | + |
| 3843 | + # Check if mood file exists |
| 3844 | + if [ ! -f "$MOOD_FILE" ]; then |
| 3845 | + echo "working:Fresh start - let's build something awesome!" |
| 3846 | + return |
| 3847 | + fi |
| 3848 | + |
| 3849 | + # Get recent events (last hour) |
| 3850 | + local recent_commits=$(jq "[.events[] | select(.type == \"commit\" and .timestamp > ($now - 3600))] | length" "$MOOD_FILE" 2>/dev/null || echo 0) |
| 3851 | + local recent_prs=$(jq "[.events[] | select(.type == \"pr_merged\" and .timestamp > ($now - 86400))] | length" "$MOOD_FILE" 2>/dev/null || echo 0) |
| 3852 | + local total_commits=$(jq ".stats.commits // 0" "$MOOD_FILE" 2>/dev/null || echo 0) |
| 3853 | + local last_event_time=$(jq ".events[0].timestamp // 0" "$MOOD_FILE" 2>/dev/null || echo 0) |
| 3854 | + local last_event_type=$(jq -r ".events[0].type // \"none\"" "$MOOD_FILE" 2>/dev/null || echo "none") |
| 3855 | + |
| 3856 | + # Calculate time since last event |
| 3857 | + local time_since_last=$((now - last_event_time)) |
| 3858 | + |
| 3859 | + # Check workspace state |
| 3860 | + local has_dirty_workspace=false |
| 3861 | + if [ -n "${WORKSPACE_BASE:-}" ] && [ -d "$WORKSPACE_BASE" ]; then |
| 3862 | + for ws_dir in "$WORKSPACE_BASE"/"${WORKSPACE_PREFIX:-workspace}"-*; do |
| 3863 | + if [ -d "$ws_dir/.git" ]; then |
| 3864 | + if [ -n "$(git -C "$ws_dir" status --porcelain 2>/dev/null)" ]; then |
| 3865 | + has_dirty_workspace=true |
| 3866 | + break |
| 3867 | + fi |
| 3868 | + fi |
| 3869 | + done |
| 3870 | + fi |
| 3871 | + |
| 3872 | + # Determine mood |
| 3873 | + if [ "$recent_prs" -ge 2 ]; then |
| 3874 | + mood="celebrating" |
| 3875 | + message="$recent_prs PRs merged today! You're on fire! 🔥" |
| 3876 | + elif [ "$recent_prs" -ge 1 ]; then |
| 3877 | + mood="excited" |
| 3878 | + message="PR merged! Time to celebrate! 🎉" |
| 3879 | + elif [ "$recent_commits" -ge 5 ]; then |
| 3880 | + mood="excited" |
| 3881 | + message="$recent_commits commits in the last hour! Crushing it!" |
| 3882 | + elif [ "$last_event_type" = "cleanup" ] && [ "$time_since_last" -lt 300 ]; then |
| 3883 | + mood="happy" |
| 3884 | + message="Fresh workspace, fresh start! ✨" |
| 3885 | + elif [ "$has_dirty_workspace" = true ]; then |
| 3886 | + mood="nervous" |
| 3887 | + message="You have uncommitted changes... don't forget to commit!" |
| 3888 | + elif [ "$time_since_last" -gt 7200 ]; then # More than 2 hours since last event |
| 3889 | + mood="sleepy" |
| 3890 | + message="Been quiet... taking a break? 😴" |
| 3891 | + elif [ "$day_of_week" -ge 6 ] && [ "$hour" -ge 18 ]; then # Weekend evening |
| 3892 | + mood="chill" |
| 3893 | + message="Weekend vibes... maybe time to relax? 🌴" |
| 3894 | + elif [ "$hour" -ge 22 ] || [ "$hour" -lt 6 ]; then # Late night / early morning |
| 3895 | + mood="sleepy" |
| 3896 | + message="It's late... get some rest! 🌙" |
| 3897 | + elif [ "$recent_commits" -ge 1 ]; then |
| 3898 | + mood="happy" |
| 3899 | + message="$recent_commits commits recently - nice progress!" |
| 3900 | + else |
| 3901 | + mood="working" |
| 3902 | + message="In the zone... keep it up! 💪" |
| 3903 | + fi |
| 3904 | + |
| 3905 | + echo "$mood:$message" |
| 3906 | +} |
| 3907 | + |
| 3908 | +# Show current crab mood |
| 3909 | +show_mood() { |
| 3910 | + load_config 2>/dev/null || true |
| 3911 | + |
| 3912 | + local result=$(mood_calculate) |
| 3913 | + local mood=$(echo "$result" | cut -d: -f1) |
| 3914 | + local message=$(echo "$result" | cut -d: -f2-) |
| 3915 | + |
| 3916 | + echo "" |
| 3917 | + echo -e "${CYAN}╭──────────────────────────────────────╮${NC}" |
| 3918 | + |
| 3919 | + # Show the ASCII art |
| 3920 | + case "$mood" in |
| 3921 | + "happy") |
| 3922 | + echo -e "${GREEN}" |
| 3923 | + crab_art_happy |
| 3924 | + echo -e "${NC}" |
| 3925 | + ;; |
| 3926 | + "excited") |
| 3927 | + echo -e "${YELLOW}" |
| 3928 | + crab_art_excited |
| 3929 | + echo -e "${NC}" |
| 3930 | + ;; |
| 3931 | + "celebrating") |
| 3932 | + echo -e "${MAGENTA}" |
| 3933 | + crab_art_celebrating |
| 3934 | + echo -e "${NC}" |
| 3935 | + ;; |
| 3936 | + "nervous") |
| 3937 | + echo -e "${YELLOW}" |
| 3938 | + crab_art_nervous |
| 3939 | + echo -e "${NC}" |
| 3940 | + ;; |
| 3941 | + "sleepy") |
| 3942 | + echo -e "${GRAY}" |
| 3943 | + crab_art_sleepy |
| 3944 | + echo -e "${NC}" |
| 3945 | + ;; |
| 3946 | + "chill") |
| 3947 | + echo -e "${CYAN}" |
| 3948 | + crab_art_chill |
| 3949 | + echo -e "${NC}" |
| 3950 | + ;; |
| 3951 | + *) |
| 3952 | + echo -e "${BLUE}" |
| 3953 | + crab_art_working |
| 3954 | + echo -e "${NC}" |
| 3955 | + ;; |
| 3956 | + esac |
| 3957 | + |
| 3958 | + echo -e "${CYAN}╰──────────────────────────────────────╯${NC}" |
| 3959 | + echo "" |
| 3960 | + echo -e " ${BOLD}Mood:${NC} $mood" |
| 3961 | + echo -e " ${message}" |
| 3962 | + echo "" |
| 3963 | + |
| 3964 | + # Show quick stats if available |
| 3965 | + if command_exists jq && [ -f "$MOOD_FILE" ]; then |
| 3966 | + local total_commits=$(jq ".stats.commits // 0" "$MOOD_FILE" 2>/dev/null || echo 0) |
| 3967 | + local total_cleanups=$(jq ".stats.cleanups // 0" "$MOOD_FILE" 2>/dev/null || echo 0) |
| 3968 | + local total_wip=$(jq ".stats.wip_saves // 0" "$MOOD_FILE" 2>/dev/null || echo 0) |
| 3969 | + |
| 3970 | + if [ "$total_commits" -gt 0 ] || [ "$total_cleanups" -gt 0 ]; then |
| 3971 | + echo -e " ${GRAY}Stats: $total_commits commits, $total_cleanups cleanups, $total_wip WIPs saved${NC}" |
| 3972 | + echo "" |
| 3973 | + fi |
| 3974 | + fi |
| 3975 | +} |
| 3976 | + |
| 3977 | +# Check for git events in a workspace and record them |
| 3978 | +mood_check_git_activity() { |
| 3979 | + local workspace_dir="$1" |
| 3980 | + |
| 3981 | + if [ ! -d "$workspace_dir/.git" ]; then |
| 3982 | + return |
| 3983 | + fi |
| 3984 | + |
| 3985 | + # Check for new commits in last 5 minutes |
| 3986 | + local recent_commits=$(git -C "$workspace_dir" log --oneline --since="5 minutes ago" 2>/dev/null | wc -l | tr -d ' ') |
| 3987 | + if [ "$recent_commits" -gt 0 ]; then |
| 3988 | + mood_record_event "commit" "$recent_commits new commits" |
| 3989 | + fi |
| 3990 | +} |
| 3991 | + |
3721 | 3992 | # ============================================================================= |
3722 | 3993 | # Help / Cheat Sheet |
3723 | 3994 | # ============================================================================= |
@@ -3828,6 +4099,7 @@ show_cheat() { |
3828 | 4099 | ║ crab doctor Diagnose common issues ║ |
3829 | 4100 | ║ crab ports Show port usage across workspaces ║ |
3830 | 4101 | ║ crab shared Show shared volume info ║ |
| 4102 | +║ crab mood Show your crab's current mood 🦀 ║ |
3831 | 4103 | ║ crab update Update crabcode to latest version ║ |
3832 | 4104 | ║ crab cheat Show this cheat sheet ║ |
3833 | 4105 | ║ ║ |
@@ -4184,6 +4456,9 @@ main() { |
4184 | 4456 | ;; |
4185 | 4457 | esac |
4186 | 4458 | ;; |
| 4459 | + "mood") |
| 4460 | + show_mood |
| 4461 | + ;; |
4187 | 4462 | "update"|"upgrade") |
4188 | 4463 | # Self-update from GitHub |
4189 | 4464 | echo -e "${CYAN}Updating crabcode...${NC}" |
|
0 commit comments