#!/bin/bash # review-ai-code.sh - Comprehensive AI code review using Claude and Gemini # Usage: ./tools/scripts/review-ai-code.sh set -e # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color echo -e "${BLUE}=== AI Code Review Starting ===${NC}" # Check if we're in a git repository if ! git rev-parse --git-dir > /dev/null 2>&1; then echo -e "${RED}Error: Not in a git repository${NC}" exit 1 fi # Check for unstaged changes if ! git diff --quiet; then echo -e "${YELLOW}Found unstaged changes to audit${NC}" else echo -e "${YELLOW}No unstaged changes found. Checking staged changes...${NC}" if ! git diff --cached --quiet; then echo -e "${YELLOW}Found staged changes to audit${NC}" else echo -e "${RED}No changes to audit. Please make some changes first.${NC}" exit 1 fi fi # Get changed files CHANGED_FILES=$(git diff --name-only) STAGED_FILES=$(git diff --cached --name-only) ALL_CHANGED_FILES="$CHANGED_FILES $STAGED_FILES" if [ -z "$ALL_CHANGED_FILES" ]; then echo -e "${RED}No files to review${NC}" exit 1 fi echo -e "${BLUE}Files to review:${NC}" echo "$ALL_CHANGED_FILES" | tr ' ' '\n' | sort -u | while read -r file; do if [ -n "$file" ]; then echo " - $file" fi done # Count total lines of changes TOTAL_LINES=$(git diff --stat | tail -1 | grep -o '[0-9]\+ insertions\|[0-9]\+ deletions' | grep -o '[0-9]\+' | awk '{sum += $1} END {print sum}') if [ -z "$TOTAL_LINES" ]; then TOTAL_LINES=0 fi echo -e "${BLUE}Total lines changed: $TOTAL_LINES${NC}" if [ "$TOTAL_LINES" -gt 2000 ]; then echo -e "${RED}Warning: Total changes exceed 2000 lines ($TOTAL_LINES). Consider breaking into smaller PRs.${NC}" fi # Create temporary directory for review outputs REVIEW_DIR="/tmp/ai-code-review-$(date +%Y%m%d-%H%M%S)" mkdir -p "$REVIEW_DIR" echo -e "${BLUE}Review outputs will be saved to: $REVIEW_DIR${NC}" # Protect files for Gemini (read-only) echo -e "${YELLOW}Setting up read-only environment for Gemini...${NC}" find . \( -name "*.ts" -o -name "*.tsx" -o -name "*.js" -o -name "*.jsx" -o -name "*.py" -o -name "*.astro" \) -print0 | xargs -0 chmod 444 2>/dev/null || true # Function to run Claude review run_claude_review() { echo -e "${GREEN}=== Running Claude Code Review ===${NC}" # Run Claude with the AI coding management guidelines claude -p "Read the AI coding management guidelines from @tools/guidelines/manage-coding-ai.md and perform a comprehensive code review on the current unstaged and staged changes. Focus only on the changed code, not the entire codebase. Provide specific feedback with file names and line numbers where issues are found." \ --add-dir ./tools/guidelines \ --add-dir ./ \ --output-format json > "$REVIEW_DIR/claude-review.json" 2>&1 # Extract content from JSON and save as readable text if [ -f "$REVIEW_DIR/claude-review.json" ]; then # Try to extract content from JSON, fallback to raw content if JSON parsing fails python3 -c " import json import sys try: with open('$REVIEW_DIR/claude-review.json', 'r') as f: data = json.load(f) if isinstance(data, dict) and 'content' in data: print(data['content']) elif isinstance(data, list) and len(data) > 0 and 'content' in data[0]: print(data[0]['content']) else: print(str(data)) except: with open('$REVIEW_DIR/claude-review.json', 'r') as f: print(f.read()) " > "$REVIEW_DIR/claude-review.txt" fi echo -e "${GREEN}Claude review completed. Output saved to $REVIEW_DIR/claude-review.txt${NC}" } # Function to run Gemini review run_gemini_review() { echo -e "${GREEN}=== Running Gemini Code Review ===${NC}" # Run Gemini with the AI coding management guidelines gemini "Read the AI coding management guidelines from @tools/guidelines/manage-coding-ai.md and perform a comprehensive code review on the current unstaged and staged git changes. Analyze only the changed lines of code, not the entire codebase. Focus on security vulnerabilities, performance issues, code quality problems, and adherence to the project's coding standards. Provide specific recommendations with file paths and line numbers." > "$REVIEW_DIR/gemini-review.txt" 2>&1 echo -e "${GREEN}Gemini review completed. Output saved to $REVIEW_DIR/gemini-review.txt${NC}" } # Run both reviews in parallel echo -e "${BLUE}Starting parallel reviews...${NC}" run_claude_review & CLAUDE_PID=$! run_gemini_review & GEMINI_PID=$! # Wait for both to complete wait $CLAUDE_PID CLAUDE_EXIT_CODE=$? wait $GEMINI_PID GEMINI_EXIT_CODE=$? # Restore file permissions echo -e "${YELLOW}Restoring file permissions...${NC}" find . \( -name "*.ts" -o -name "*.tsx" -o -name "*.js" -o -name "*.jsx" -o -name "*.py" -o -name "*.astro" \) -print0 | xargs -0 chmod 644 2>/dev/null || true # Create combined review report echo -e "${BLUE}=== Creating Combined Review Report ===${NC}" cat > "$REVIEW_DIR/combined-review.md" << EOF # AI Code Review Report Generated: $(date) Total lines changed: $TOTAL_LINES ## Files Reviewed $(echo "$ALL_CHANGED_FILES" | tr ' ' '\n' | sort -u | while read -r file; do if [ -n "$file" ]; then echo "- $file" fi done) ## Claude Review Results \`\`\` $(cat "$REVIEW_DIR/claude-review.txt" 2>/dev/null || echo "Claude review failed or produced no output") \`\`\` ## Gemini Review Results \`\`\` $(cat "$REVIEW_DIR/gemini-review.txt" 2>/dev/null || echo "Gemini review failed or produced no output") \`\`\` ## Summary - Claude review exit code: $CLAUDE_EXIT_CODE - Gemini review exit code: $GEMINI_EXIT_CODE - Review files saved to: $REVIEW_DIR EOF # Display results echo -e "${BLUE}=== Review Results Summary ===${NC}" echo -e "${GREEN}Claude Review:${NC}" if [ -f "$REVIEW_DIR/claude-review.txt" ]; then head -20 "$REVIEW_DIR/claude-review.txt" echo -e "${YELLOW}... (truncated, see full output in $REVIEW_DIR/claude-review.txt)${NC}" else echo -e "${RED}Claude review output not found${NC}" fi echo "" echo -e "${GREEN}Gemini Review:${NC}" if [ -f "$REVIEW_DIR/gemini-review.txt" ]; then head -20 "$REVIEW_DIR/gemini-review.txt" echo -e "${YELLOW}... (truncated, see full output in $REVIEW_DIR/gemini-review.txt)${NC}" else echo -e "${RED}Gemini review output not found${NC}" fi echo "" echo -e "${BLUE}=== AI Code Review Complete ===${NC}" echo -e "${GREEN}Full review report saved to: $REVIEW_DIR/combined-review.md${NC}" echo -e "${YELLOW}Individual outputs:${NC}" echo " - Claude: $REVIEW_DIR/claude-review.txt" echo " - Gemini: $REVIEW_DIR/gemini-review.txt" echo " - Combined: $REVIEW_DIR/combined-review.md" # Check for critical issues if [ $CLAUDE_EXIT_CODE -ne 0 ] || [ $GEMINI_EXIT_CODE -ne 0 ]; then echo -e "${RED}Warning: One or more reviews failed. Please review the outputs.${NC}" exit 1 fi echo -e "${GREEN}AI code review completed successfully!${NC}"