Files
rUv 5c5ede94b6 fix: 5 critical bugs — cwd, intelligence hang, memory init, ruvector v3.5.52
- #1532: Add getProjectCwd() to all 16 MCP tool files, respecting CLAUDE_FLOW_CWD
  env var instead of bare process.cwd(). Fixes macOS global install where cwd='/'.
  Install script now passes -e CLAUDE_FLOW_CWD="$HOME" to claude mcp add.

- #1530/#1531: Add 10MB file size guard and 5000-node PageRank cap to
  intelligence.cjs. Add 3s timeout wrapper on intelligence.init()/consolidate()
  in hook-handler.cjs. Prevents indefinite hang on large graph-state.json.

- #1524: Auto-initialize memory database on MCP server startup in mcp-server.ts
  with graceful degradation. Fixes "Database not initialized" for memory_store.

- #1522/#1520/#1523: Detect ruvector extension before falling back to pgvector
  in all ruvector CLI commands. Dynamic vector type names in DDL/indexes.
  Fix -d flag mapping to --database in benchmark/optimize.

Closes #1532, #1531, #1530, #1524, #1522, #1520, #1523

Co-authored-by: Reuven <cohen@ruv-mac-mini.local>
2026-04-06 11:47:30 -04:00

393 lines
12 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
#
# Ruflo Installer (formerly Claude Flow)
# https://github.com/ruvnet/ruflo
#
# Usage:
# curl -fsSL https://cdn.jsdelivr.net/gh/ruvnet/claude-flow@main/scripts/install.sh | bash
# curl -fsSL https://cdn.jsdelivr.net/gh/ruvnet/claude-flow@main/scripts/install.sh | bash -s -- --full
# curl -fsSL https://cdn.jsdelivr.net/gh/ruvnet/claude-flow@main/scripts/install.sh | bash -s -- --global
# curl -fsSL https://cdn.jsdelivr.net/gh/ruvnet/claude-flow@main/scripts/install.sh | bash -s -- --minimal
#
# Options (via arguments):
# --global Global install (npm install -g)
# --minimal Minimal install (no optional deps)
# --full Full setup (global + MCP + doctor + init)
# --version=X.X.X Specific version
#
# Options (via environment - requires export):
# export CLAUDE_FLOW_VERSION=alpha
# export CLAUDE_FLOW_MINIMAL=1
# export CLAUDE_FLOW_GLOBAL=1
#
set -euo pipefail
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
BOLD='\033[1m'
DIM='\033[2m'
NC='\033[0m' # No Color
# Default configuration (can be overridden by env vars)
VERSION="${RUFLO_VERSION:-${CLAUDE_FLOW_VERSION:-latest}}"
MINIMAL="${CLAUDE_FLOW_MINIMAL:-0}"
GLOBAL="${CLAUDE_FLOW_GLOBAL:-0}"
SETUP_MCP="${CLAUDE_FLOW_SETUP_MCP:-0}"
RUN_DOCTOR="${CLAUDE_FLOW_DOCTOR:-0}"
RUN_INIT="${CLAUDE_FLOW_INIT:-1}"
# Parse command line arguments
while [[ $# -gt 0 ]]; do
case $1 in
--global|-g)
GLOBAL="1"
shift
;;
--minimal|-m)
MINIMAL="1"
shift
;;
--setup-mcp|--mcp)
SETUP_MCP="1"
shift
;;
--doctor|-d)
RUN_DOCTOR="1"
shift
;;
--init|-i)
RUN_INIT="1"
shift
;;
--no-init)
RUN_INIT="0"
shift
;;
--full|-f)
GLOBAL="1"
SETUP_MCP="1"
RUN_DOCTOR="1"
RUN_INIT="1"
shift
;;
--version=*)
VERSION="${1#*=}"
shift
;;
--help|-h)
echo "Ruflo Installer"
echo ""
echo "Usage: curl -fsSL .../install.sh | bash -s -- [OPTIONS]"
echo ""
echo "Options:"
echo " --global, -g Install globally (npm install -g ruflo)"
echo " --minimal, -m Minimal install (skip optional deps)"
echo " --setup-mcp Auto-configure MCP server for Claude Code"
echo " --doctor, -d Run diagnostics after install"
echo " --no-init Skip project initialization (enabled by default)"
echo " --full, -f Full setup (global + mcp + doctor + init)"
echo " --version=X.X.X Install specific version (default: alpha)"
echo " --help, -h Show this help"
exit 0
;;
*)
shift
;;
esac
done
PACKAGE="ruflo@${VERSION}"
# Progress animation
SPINNER_CHARS="⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏"
SPINNER_INDEX=0
spinner() {
printf "\r${CYAN}${SPINNER_CHARS:SPINNER_INDEX++:1}${NC} $1"
SPINNER_INDEX=$((SPINNER_INDEX % 10))
}
print_banner() {
echo ""
echo -e "${CYAN}╔═══════════════════════════════════════════════════════════╗${NC}"
echo -e "${CYAN}${NC} ${BOLD}Ruflo${NC} — AI Agent Orchestration for Claude Code ${CYAN}${NC}"
echo -e "${CYAN}╚═══════════════════════════════════════════════════════════╝${NC}"
echo ""
}
print_step() {
echo -e "${GREEN}${NC} $1"
}
print_substep() {
echo -e " ${DIM}├─${NC} $1"
}
print_success() {
echo -e "${GREEN}${NC} $1"
}
print_warning() {
echo -e "${YELLOW}${NC} $1"
}
print_error() {
echo -e "${RED}${NC} $1"
}
print_info() {
echo -e "${BLUE}${NC} $1"
}
check_requirements() {
print_step "Checking requirements..."
# Check Node.js
if command -v node &> /dev/null; then
NODE_VERSION=$(node -v | sed 's/v//')
NODE_MAJOR=$(echo "$NODE_VERSION" | cut -d. -f1)
if [ "$NODE_MAJOR" -ge 20 ]; then
print_substep "Node.js ${GREEN}v${NODE_VERSION}${NC}"
else
print_error "Node.js 20+ required (found v${NODE_VERSION})"
echo ""
echo "Install Node.js 20+:"
echo " curl -fsSL https://fnm.vercel.app/install | bash"
echo " fnm install 20"
exit 1
fi
else
print_error "Node.js not found"
echo ""
echo "Install Node.js 20+:"
echo " curl -fsSL https://fnm.vercel.app/install | bash"
echo " fnm install 20"
exit 1
fi
# Check npm
if command -v npm &> /dev/null; then
NPM_VERSION=$(npm -v)
print_substep "npm ${GREEN}v${NPM_VERSION}${NC}"
else
print_error "npm not found"
exit 1
fi
# Check Claude Code CLI
if command -v claude &> /dev/null; then
CLAUDE_VERSION=$(claude --version 2>/dev/null | head -1 || echo "installed")
print_substep "Claude Code ${GREEN}${CLAUDE_VERSION}${NC}"
else
print_warning "Claude Code CLI not found"
print_substep "Installing Claude Code CLI via npm..."
if npm install -g @anthropic-ai/claude-code 2>/dev/null; then
if command -v claude &> /dev/null; then
CLAUDE_VERSION=$(claude --version 2>/dev/null | head -1 || echo "installed")
print_substep "Claude Code ${GREEN}${CLAUDE_VERSION}${NC}"
else
print_substep "Installed. Restart terminal to use 'claude' command"
fi
else
print_warning "npm install failed. Try manually:"
print_substep "${BOLD}npm install -g @anthropic-ai/claude-code${NC}"
fi
fi
echo ""
}
show_install_options() {
print_step "Installation options:"
print_substep "Package: ${BOLD}${PACKAGE}${NC}"
if [ "$GLOBAL" = "1" ]; then
print_substep "Mode: ${BOLD}Global${NC} (npm install -g)"
else
print_substep "Mode: ${BOLD}npx${NC} (on-demand)"
fi
if [ "$MINIMAL" = "1" ]; then
print_substep "Profile: ${BOLD}Minimal${NC} (--omit=optional)"
else
print_substep "Profile: ${BOLD}Full${NC} (all features)"
fi
echo ""
}
install_package() {
local START_TIME=$(date +%s)
if [ "$GLOBAL" = "1" ]; then
print_step "Installing globally..."
if [ "$MINIMAL" = "1" ]; then
npm install -g "$PACKAGE" --omit=optional 2>&1 | while read -r line; do
if [[ "$line" == *"added"* ]]; then
print_substep "$line"
fi
done
else
npm install -g "$PACKAGE" 2>&1 | while read -r line; do
if [[ "$line" == *"added"* ]]; then
print_substep "$line"
fi
done
fi
else
print_step "Installing for npx usage..."
# Actually run npx to pre-install the package
npx -y "$PACKAGE" --version >/dev/null 2>&1 || true
print_substep "Package installed for npx"
fi
local END_TIME=$(date +%s)
local DURATION=$((END_TIME - START_TIME))
echo ""
print_success "Installed in ${BOLD}${DURATION}s${NC}"
}
verify_installation() {
print_step "Verifying installation..."
local VERSION_OUTPUT
if [ "$GLOBAL" = "1" ]; then
VERSION_OUTPUT=$(ruflo --version 2>/dev/null || claude-flow --version 2>/dev/null || echo "")
if [ -z "$VERSION_OUTPUT" ]; then
print_warning "Global command not found in PATH"
print_substep "Try: ${BOLD}npm install -g ruflo@${VERSION}${NC}"
return 0 # Don't fail - npm might need PATH refresh
fi
else
# For npx mode, package was already installed during install_package
VERSION_OUTPUT=$(npx "$PACKAGE" --version 2>/dev/null || echo "")
fi
if [ -n "$VERSION_OUTPUT" ]; then
print_substep "Version: ${GREEN}${VERSION_OUTPUT}${NC}"
echo ""
return 0
else
print_error "Installation verification failed"
return 1
fi
}
show_quickstart() {
echo -e "${CYAN}╔═══════════════════════════════════════════════════════════╗${NC}"
echo -e "${CYAN}${NC} ${BOLD}Quick Start${NC} ${CYAN}${NC}"
echo -e "${CYAN}╚═══════════════════════════════════════════════════════════╝${NC}"
echo ""
if [ "$GLOBAL" = "1" ]; then
echo -e " ${DIM}# Initialize project${NC}"
echo -e " ${BOLD}ruflo init --wizard${NC}"
echo ""
echo -e " ${DIM}# Run system diagnostics${NC}"
echo -e " ${BOLD}ruflo doctor${NC}"
echo ""
echo -e " ${DIM}# Add as MCP server to Claude Code${NC}"
echo -e " ${BOLD}claude mcp add ruflo -- ruflo mcp start${NC}"
else
echo -e " ${DIM}# Initialize project${NC}"
echo -e " ${BOLD}npx ruflo@latest init --wizard${NC}"
echo ""
echo -e " ${DIM}# Run system diagnostics${NC}"
echo -e " ${BOLD}npx ruflo@latest doctor${NC}"
echo ""
echo -e " ${DIM}# Add as MCP server to Claude Code${NC}"
echo -e " ${BOLD}claude mcp add ruflo -- npx -y ruflo@latest mcp start${NC}"
fi
echo ""
echo -e "${DIM}Documentation: https://github.com/ruvnet/ruflo${NC}"
echo -e "${DIM}Issues: https://github.com/ruvnet/ruflo/issues${NC}"
echo ""
}
setup_mcp_server() {
if [ "$SETUP_MCP" != "1" ]; then
return 0
fi
print_step "Setting up MCP server..."
if ! command -v claude &> /dev/null; then
print_warning "Claude CLI not found, skipping MCP setup"
return 0
fi
# Check if already configured
if claude mcp list 2>/dev/null | grep -q "ruflo\|claude-flow"; then
print_substep "MCP server already configured ✓"
return 0
fi
# Add MCP server (pass CLAUDE_FLOW_CWD so tools resolve paths correctly
# even when the MCP server is spawned with cwd='/')
if [ "$GLOBAL" = "1" ]; then
claude mcp add ruflo -e CLAUDE_FLOW_CWD="$HOME" -- ruflo mcp start 2>/dev/null && \
print_substep "MCP server configured ✓" || \
print_warning "MCP setup failed - run manually: claude mcp add ruflo -e CLAUDE_FLOW_CWD=\"\$HOME\" -- ruflo mcp start"
else
claude mcp add ruflo -e CLAUDE_FLOW_CWD="$HOME" -- npx -y ruflo@${VERSION} mcp start 2>/dev/null && \
print_substep "MCP server configured ✓" || \
print_warning "MCP setup failed - run manually: claude mcp add ruflo -e CLAUDE_FLOW_CWD=\"\$HOME\" -- npx -y ruflo@latest mcp start"
fi
echo ""
}
run_doctor() {
if [ "$RUN_DOCTOR" != "1" ]; then
return 0
fi
print_step "Running diagnostics..."
echo ""
if [ "$GLOBAL" = "1" ]; then
ruflo doctor 2>&1 || true
else
npx ruflo@${VERSION} doctor 2>&1 || true
fi
echo ""
}
run_init() {
if [ "$RUN_INIT" != "1" ]; then
return 0
fi
print_step "Initializing project..."
echo ""
if [ "$GLOBAL" = "1" ]; then
ruflo init --yes 2>&1 || true
else
npx ruflo@${VERSION} init --yes 2>&1 || true
fi
echo ""
}
# Main
main() {
print_banner
check_requirements
show_install_options
install_package
verify_installation
setup_mcp_server
run_doctor
run_init
show_quickstart
print_success "${BOLD}Ruflo is ready!${NC}"
echo ""
}
main "$@"