#!/bin/sh
# Claude Flow MCP Server launcher with automatic npm/npx cache repair.
#
# Handles two common npm bugs in remote/CI environments:
#   - ENOTEMPTY: stale rename artifacts from interrupted installs
#   - ECOMPROMISED: corrupted package-lock / integrity check failures
#
# Strategy:
#   1. Pre-flight: clean stale npx cache artifacts
#   2. Attempt normal npx launch
#   3. On failure, identify error type and apply targeted fix
#   4. Retry (up to 3 attempts, escalating cleanup)
#
# Usage:
#   claude mcp add claude-flow -- sh bin/claude-flow-mcp.sh
#   CLAUDE_FLOW_PACKAGE=claude-flow@latest sh bin/claude-flow-mcp.sh

PACKAGE="${CLAUDE_FLOW_PACKAGE:-claude-flow@alpha}"
MAX_RETRIES=3
ATTEMPT=0

# Clean stale npx cache rename artifacts (.package-XxXxXxXx dirs)
clean_stale_artifacts() {
  NPX_DIR="$HOME/.npm/_npx"
  [ -d "$NPX_DIR" ] || return 0

  for dir in "$NPX_DIR"/*/node_modules; do
    [ -d "$dir" ] || continue
    find "$dir" -maxdepth 1 -name '.*' -type d 2>/dev/null | while read -r stale; do
      base=$(basename "$stale")
      if echo "$base" | grep -qE '^\.[a-zA-Z@].*-[A-Za-z]{8,}$'; then
        rm -rf "$stale" 2>/dev/null
      fi
    done
  done
}

# Remove a specific npx cache entry by hash
nuke_cache_hash() {
  hash="$1"
  [ -n "$hash" ] && [ -d "$HOME/.npm/_npx/$hash" ] && rm -rf "$HOME/.npm/_npx/$hash" 2>/dev/null
}

# Extract cache hash from npm error output
extract_hash() {
  echo "$1" | grep -oE '_npx/[a-f0-9]{16}' | head -1 | sed 's|_npx/||'
}

# Fix ECOMPROMISED: clear npm cache store + lock files
fix_compromised() {
  # Clear the npm _cacache store (contains integrity manifests)
  rm -rf "$HOME/.npm/_cacache" 2>/dev/null
  # Remove any stale lock files
  find "$HOME/.npm" -name '.package-lock.json' -delete 2>/dev/null
  find "$HOME/.npm/_npx" -name 'package-lock.json' -delete 2>/dev/null
}

# Pre-flight cleanup
clean_stale_artifacts

while [ $ATTEMPT -lt $MAX_RETRIES ]; do
  ATTEMPT=$((ATTEMPT + 1))

  # Capture stderr for error detection, pass stdout through for MCP protocol
  ERROR_LOG=$(mktemp 2>/dev/null || echo "/tmp/claude-flow-mcp-err.$$")
  npx -y "$PACKAGE" mcp start 2>"$ERROR_LOG"
  EXIT_CODE=$?

  if [ $EXIT_CODE -eq 0 ]; then
    rm -f "$ERROR_LOG" 2>/dev/null
    exit 0
  fi

  ERROR_OUTPUT=$(cat "$ERROR_LOG" 2>/dev/null)
  rm -f "$ERROR_LOG" 2>/dev/null

  # Classify error and apply targeted fix
  if echo "$ERROR_OUTPUT" | grep -q "ENOTEMPTY"; then
    HASH=$(extract_hash "$ERROR_OUTPUT")
    if [ -n "$HASH" ]; then
      nuke_cache_hash "$HASH"
      echo "[claude-flow] Cleared corrupted npx cache ($HASH), retrying ($ATTEMPT/$MAX_RETRIES)..." >&2
    else
      clean_stale_artifacts
      echo "[claude-flow] Cleaned stale npx cache entries, retrying ($ATTEMPT/$MAX_RETRIES)..." >&2
    fi

  elif echo "$ERROR_OUTPUT" | grep -q "ECOMPROMISED\|Lock compromised"; then
    fix_compromised
    echo "[claude-flow] Fixed compromised npm cache, retrying ($ATTEMPT/$MAX_RETRIES)..." >&2

  elif echo "$ERROR_OUTPUT" | grep -q "EACCES\|permission denied"; then
    # Permission issues — try fixing ownership
    chown -R "$(whoami)" "$HOME/.npm" 2>/dev/null
    echo "[claude-flow] Fixed npm cache permissions, retrying ($ATTEMPT/$MAX_RETRIES)..." >&2

  else
    # Unknown error — print and exit
    echo "$ERROR_OUTPUT" >&2
    exit $EXIT_CODE
  fi
done

# All retries exhausted — nuclear option: nuke entire npx + cache
echo "[claude-flow] Retries exhausted. Full npm cache reset..." >&2
rm -rf "$HOME/.npm/_npx" "$HOME/.npm/_cacache" 2>/dev/null
exec npx -y "$PACKAGE" mcp start
