#!/bin/bash # CLI Coverage Audit Script # Compares API endpoints to CLI commands to ensure sync # Usage: ./scripts/audit-cli-coverage.sh set -e SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" API_DIR="${PROJECT_ROOT}/src/app/api" RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' log_info() { echo -e "${GREEN}✓${NC} $1"; } log_warn() { echo -e "${YELLOW}⚠${NC} $1"; } log_error() { echo -e "${RED}✗${NC} $1"; } echo "═══════════════════════════════════════════════════════════" echo " CLI Coverage Audit" echo "═══════════════════════════════════════════════════════════" echo "" # Check if API directory exists if [ ! -d "$API_DIR" ]; then log_error "API directory not found: $API_DIR" exit 1 fi # Find all API route files echo "📁 Scanning API routes in $API_DIR..." echo "" # Extract API endpoints from route.ts files declare -a API_ENDPOINTS=() while IFS= read -r -d '' route_file; do # Get the directory path relative to api/ rel_path=$(dirname "$route_file" | sed "s|$API_DIR/||") # Check for HTTP methods in the file if grep -q "export async function GET" "$route_file"; then API_ENDPOINTS+=("GET /api/$rel_path") fi if grep -q "export async function POST" "$route_file"; then API_ENDPOINTS+=("POST /api/$rel_path") fi if grep -q "export async function PATCH" "$route_file"; then API_ENDPOINTS+=("PATCH /api/$rel_path") fi if grep -q "export async function DELETE" "$route_file"; then API_ENDPOINTS+=("DELETE /api/$rel_path") fi if grep -q "export async function PUT" "$route_file"; then API_ENDPOINTS+=("PUT /api/$rel_path") fi done < <(find "$API_DIR" -name "route.ts" -print0) # Sort and dedupe API endpoints IFS=$'\n' API_ENDPOINTS=($(sort <<< "${API_ENDPOINTS[*]}")) unset IFS echo "Found ${#API_ENDPOINTS[@]} API endpoint(s):" for endpoint in "${API_ENDPOINTS[@]}"; do echo " • $endpoint" done echo "" # Check CLI coverage echo "🔍 Checking CLI coverage..." echo "" # Extract CLI commands from gantt.sh (or similar unified CLI) CLI_FILE="${SCRIPT_DIR}/gantt.sh" if [ ! -f "$CLI_FILE" ]; then log_warn "Unified CLI not found at $CLI_FILE" log_info "Checking for individual scripts..." # Look for any shell scripts CLI_SCRIPTS=($(find "$SCRIPT_DIR" -name "*.sh" -type f ! -name "audit-cli-coverage.sh" | sort)) if [ ${#CLI_SCRIPTS[@]} -eq 0 ]; then log_error "No CLI scripts found!" exit 1 fi echo "Found CLI scripts:" for script in "${CLI_SCRIPTS[@]}"; do echo " • $(basename "$script")" done fi # Compare API to CLI coverage echo "" echo "═══════════════════════════════════════════════════════════" echo " Coverage Report" echo "═══════════════════════════════════════════════════════════" echo "" # This is project-specific - customize based on your CLI structure # For gantt-board, we check against known CLI commands declare -A CLI_MAP=( ["GET /api/tasks"]='task list' ["POST /api/tasks"]='task create' ["DELETE /api/tasks"]='task delete' ["POST /api/tasks/natural"]='task natural' ) MISSING=0 COVERED=0 for endpoint in "${API_ENDPOINTS[@]}"; do if [ -n "${CLI_MAP[$endpoint]}" ]; then log_info "$endpoint → ${CLI_MAP[$endpoint]}" ((COVERED++)) else log_error "$endpoint → NO CLI COMMAND" ((MISSING++)) fi done echo "" echo "═══════════════════════════════════════════════════════════" echo " Summary" echo "═══════════════════════════════════════════════════════════" echo "" if [ $MISSING -eq 0 ]; then log_info "All API endpoints have CLI coverage!" echo "" echo " Total endpoints: ${#API_ENDPOINTS[@]}" echo " Covered: $COVERED" echo " Missing: $MISSING" echo "" exit 0 else log_error "CLI coverage incomplete!" echo "" echo " Total endpoints: ${#API_ENDPOINTS[@]}" echo " Covered: $COVERED" echo " Missing: $MISSING" echo "" echo "Add CLI commands for missing endpoints before committing." echo "See Rule 2.5 in MEMORY.md for details." echo "" exit 1 fi