From 58526ae36fc4d45359567bd2d189fc1dff45f328 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 11 Oct 2025 22:39:52 +0000 Subject: [PATCH 1/4] Initial plan From 1808982883589900aa28a7bd234edde0c5c9d0b9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 11 Oct 2025 22:53:22 +0000 Subject: [PATCH 2/4] Fix critical syntax errors in install.sh - remove orphaned code and fix structure Co-authored-by: RLuf <74881309+RLuf@users.noreply.github.com> --- install.sh | 329 +------ install.sh.new | 2339 +++++++++++++++++++++++++++++++++++++++++++++++ install.sh.new2 | 2296 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 4671 insertions(+), 293 deletions(-) create mode 100644 install.sh.new create mode 100644 install.sh.new2 diff --git a/install.sh b/install.sh index 1e85d16..5784b95 100755 --- a/install.sh +++ b/install.sh @@ -1,304 +1,41 @@ #!/bin/bash set -e -echo "=== FazAI v2.0 Installer ===" - -# Observabilidade via Prometheus/Grafana movida para repositório externo (~/fazaiserverlogs) -# Ajuste ENABLE_FAZAI_MONITORING=true para reinstalar esses componentes. -ENABLE_FAZAI_MONITORING="${ENABLE_FAZAI_MONITORING:-false}" - -# Verifica root -if [[ $EUID -ne 0 ]]; then - echo "❌ Execute como root: sudo ./install.sh" - exit 1 -fi - -# Cria estrutura de diretórios -echo "📁 Criando estrutura..." -mkdir -p /opt/fazai/{bin,lib,etc,tools} -mkdir -p /var/log/fazai -mkdir -p /run/fazai -chmod 777 /run/fazai || true -mkdir -p /etc/fazai - -# Remove serviços de monitoramento legados (Prometheus/Grafana) se existirem -echo "🔻 Removendo monitoramento Prometheus/Grafana legado..." -remove_monitoring_service() { - local svc="$1" - if systemctl list-unit-files 2>/dev/null | grep -q "^${svc}\.service"; then - systemctl stop "$svc" 2>/dev/null || true - systemctl disable "$svc" 2>/dev/null || true - rm -f "/etc/systemd/system/${svc}.service" - fi -} - -remove_monitoring_service "fazai-prometheus" -remove_monitoring_service "fazai-grafana" - -if command -v docker >/dev/null 2>&1; then - docker rm -f fazai-prometheus >/dev/null 2>&1 || true - docker rm -f fazai-grafana >/dev/null 2>&1 || true -fi - -systemctl daemon-reload 2>/dev/null || true - -# Instala dependências Python -echo "🐍 Instalando dependências Python..." -apt-get update -apt-get install -y python3 python3-pip python3-venv poppler-utils pandoc docx2txt lynx w3m jq curl -# Dependências do worker FazAI (fazai_gemma_worker.py) -# Pinar qdrant-client para compatibilidade com servidor 1.7.3 (Docker) -pip3 install aiohttp asyncio 'qdrant-client==1.7.3' httpx openai requests - -if command -v npm >/dev/null 2>&1; then - echo "📦 Instalando dependências Node..." - npm install --production -else - echo "⚠️ npm não encontrado; instale Node.js para executar o console web." -fi - -# Copia binários -echo "📦 Instalando binários..." -cp worker/bin/fazai_gemma_worker.py /opt/fazai/bin/ -cp worker/bin/fazai_mcp_client.py /opt/fazai/bin/ -cp worker/bin/fazai_integration_adapter.py /opt/fazai/lib/ -cp worker/bin/gemma_worker_client.py /opt/fazai/bin/ - -# Instala bindings Gemma nativos -echo "🧠 Instalando bindings Gemma nativos..." -mkdir -p /opt/fazai/lib/python -if [ -f "worker/bin/gemma_native.cpython-310-x86_64-linux-gnu.so" ]; then - cp worker/bin/gemma_native.cpython-310-x86_64-linux-gnu.so /opt/fazai/lib/python/gemma_native.so - echo "✅ Bindings Gemma nativos instalados" -else - echo "⚠️ Bindings Gemma nativos não encontrados - worker usará fallbacks" -fi - -chmod +x /opt/fazai/bin/*.py - -echo "🖥️ Preparando assets do console web..." -mkdir -p /opt/fazai/web/hp-console/assets -mkdir -p /opt/fazai/web/hp-console/data -rm -rf /opt/fazai/web/hp-console/assets/rag-viewer -cp -R opt/fazai/web/hp-console/assets/rag-viewer /opt/fazai/web/hp-console/assets/rag-viewer - -# CLI principal -echo "⚡ Instalando CLI /bin/fazai..." -cat > /bin/fazai << 'EOF' -#!/bin/bash -exec /opt/fazai/bin/fazai_mcp_client.py "$@" -EOF -chmod +x /bin/fazai - -// Apenas cria configuração padrão se não existir -echo "⚙️ Preparando configuração..." -if [ ! -f /etc/fazai/fazai.conf ]; then -cat > /etc/fazai/fazai.conf << 'EOF' -############################################################################### -# FazAI v2.0 - Arquivo de Configuração Padrão -# ----------------------------------------------------------- -# Copie este arquivo para /etc/fazai/fazai.conf e ajuste os -# valores de acordo com seu ambiente. -############################################################################### - -############################################################################### -# SISTEMA -############################################################################### - -[system] -# Nível de log global dos componentes escritos em Python/Node -log_level = INFO - -############################################################################### -# PROVEDOR PRINCIPAL -############################################################################### - -[ai_provider] -provider = gemma_cpp -enable_fallback = true -max_retries = 3 -retry_delay = 2 - -############################################################################### -# WORKER PYTHON (fazai_gemma_worker.py) -############################################################################### - -[gemma_worker] -# Endereços onde o worker escutará requisições MCP/ND-JSON -host = 0.0.0.0 -port = 5556 -# Socket Unix compartilhado com dispatcher/CLIs -unix_socket = /run/fazai/gemma.sock -# Nível de log específico do worker -log_level = INFO - -############################################################################### -# GEMMA LOCAL (gemma.cpp) -############################################################################### - -[gemma_cpp] -weights = /opt/fazai/models/gemma/2.0-2b-it-sfp.sbs -# Informe somente se o peso não possuir tokenizer embutido -tokenizer = /opt/fazai/models/gemma/tokenizer.spm -enable_native = true -# Parâmetros de geração padrões -max_tokens = 512 -temperature = 0.2 -top_k = 1 -deterministic = true -multiturn = false -prefill_tbatch = 256 -generation_timeout = 120 - -############################################################################### -# DISPATCHER (fazai_dispatcher.py) -############################################################################### - -[dispatcher] -mode = smart -# Socket principal do worker Gemma (pode ser sobrescrito por CLI) -gemma_socket = /run/fazai/gemma.sock -timeout_seconds = 30 -shell_timeout = 60 -fallback_timeout = 45 -health_check_interval = 60 -fallback_order = openai,openrouter,context7 - -############################################################################### -# QDRANT (Memória vetorial) -############################################################################### - -[qdrant] -enabled = true -host = 127.0.0.1 -port = 6333 -personality_collection = fazai_memory -knowledge_collection = fazai_kb -vector_dim = 1024 - -############################################################################### -# OLLAMA (Embeddings locais) -############################################################################### - -[ollama] -endpoint = http://127.0.0.1:11434 -embeddings_endpoint = -embedding_model = mxbai-embed-large -timeout = 30 - ############################################################################### -# FALLBACKS (APIs externas) +# FazAI v2.0 Installer +# Sistema de Agente Inteligente Cognitivo e Persistente ############################################################################### -[openai] -api_key = -model = gpt-4 -max_tokens = 2048 - -[openrouter] -api_key = -endpoint = https://openrouter.ai/api/v1 -default_model = openai/gpt-4o -models = anthropic/claude-3-opus, google/gemini-pro, meta/llama-3-70b -temperature = 0.3 -max_tokens = 2000 - -[context7] -endpoint = -timeout = 20 -api_key = - -############################################################################### -# SERVIÇOS LEGADOS / INTEGRAÇÕES OPCIONAIS -############################################################################### - -[daemon] -host = 0.0.0.0 -port = 3120 - -[cloudflare] -storage = /opt/fazai/web/hp-console/data/cloudflare_accounts.json -api_token = - -[opnsense] -storage = /opt/fazai/web/hp-console/data/opnsense_servers.json -enabled = false -host = 127.0.0.1 -port = 443 -use_ssl = true -api_key = -api_secret = -verifySSL = false -timeout = 30000 - -############################################################################### -# TELEMETRIA / PROMETHEUS (Opcional) -############################################################################### - -[telemetry] -enable_ingest = true -enable_metrics = true -udp_port = 0 - -############################################################################### -# BANCO DE DADOS (Opcional / legado) -############################################################################### - -[mysql] -enabled = false -host = 127.0.0.1 -port = 3306 -database = fazai -user = fazai -password = trocar_senha - -EOF -else - echo "ℹ️ Mantendo configuração existente em /etc/fazai/fazai.conf" -fi - -# Systemd service -echo "🔧 Criando serviço systemd..." -cat > /etc/systemd/system/fazai-gemma-worker.service << 'EOF' -[Unit] -Description=FazAI Gemma Worker v2.0 -After=network.target fazai-qdrant.service -Wants=fazai-qdrant.service - -[Service] -Type=simple -User=root -WorkingDirectory=/opt/fazai -EnvironmentFile=-/etc/fazai/env -RuntimeDirectory=fazai -RuntimeDirectoryMode=0777 -UMask=0000 -ExecStartPre=/usr/bin/install -d -m 0777 -o root -g root /run/fazai -ExecStartPre=/bin/rm -f /run/fazai/gemma.sock -ExecStart=/opt/fazai/bin/fazai_gemma_worker.py -ExecStopPost=/bin/rm -f /run/fazai/gemma.sock -Restart=always -RestartSec=5 -StandardOutput=journal -StandardError=journal - -[Install] -WantedBy=multi-user.target -EOF - -# Habilita e inicia serviço -systemctl daemon-reload -systemctl enable fazai-gemma-worker -systemctl start fazai-gemma-worker - -echo "✅ FazAI v2.0 instalado com sucesso!" -echo "📍 Teste: fazai ask 'olá mundo'" -echo "📍 Status: systemctl status fazai-gemma-worker" -echo "📍 Logs: journalctl -u fazai-gemma-worker -f" - mkdir -p $(dirname $LOG_FILE) +# Variáveis globais +VERSION="2.0.0" +LOG_FILE="/var/log/fazai/install.log" +INSTALL_STATE_FILE="/var/log/fazai/install_state.txt" +DEBUG_MODE="${DEBUG_MODE:-false}" +WITH_LLAMA="${WITH_LLAMA:-false}" + +# Cores para output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +PURPLE='\033[0;35m' +CYAN='\033[0;36m' +NC='\033[0m' # No Color + +# Array associativo para estado da instalação +declare -A INSTALL_STATE + +# Função de logging +log() { + local level="$1" + local message="$2" + local timestamp=$(date '+%Y-%m-%d %H:%M:%S') + + # Cria diretório de log se não existir + mkdir -p "$(dirname "$LOG_FILE")" # Escreve log ao arquivo - echo "[$timestamp] [$level] $message" >> $LOG_FILE + echo "[$timestamp] [$level] $message" >> "$LOG_FILE" # Mostra no console com cores case $level in @@ -321,6 +58,12 @@ echo "📍 Logs: journalctl -u fazai-gemma-worker -f" ;; esac } + +# Verifica root +if [[ $EUID -ne 0 ]]; then + log "ERROR" "Execute como root: sudo ./install.sh" + exit 1 +fi # Consulta ajuda da IA em caso de erro (simplificada) ai_help() { local prompt="$1" diff --git a/install.sh.new b/install.sh.new new file mode 100644 index 0000000..4a43c95 --- /dev/null +++ b/install.sh.new @@ -0,0 +1,2339 @@ +#!/bin/bash +set -e + +############################################################################### +# FazAI v2.0 Installer +# Sistema de Agente Inteligente Cognitivo e Persistente +############################################################################### + +# Variáveis globais +VERSION="2.0.0" +LOG_FILE="/var/log/fazai/install.log" +INSTALL_STATE_FILE="/var/log/fazai/install_state.txt" +DEBUG_MODE="${DEBUG_MODE:-false}" +WITH_LLAMA="${WITH_LLAMA:-false}" + +# Cores para output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +PURPLE='\033[0;35m' +CYAN='\033[0;36m' +NC='\033[0m' # No Color + +# Array associativo para estado da instalação +declare -A INSTALL_STATE + +# Função de logging +log() { + local level="$1" + local message="$2" + local timestamp=$(date '+%Y-%m-%d %H:%M:%S') + + # Cria diretório de log se não existir + mkdir -p "$(dirname "$LOG_FILE")" + + # Escreve log ao arquivo + echo "[$timestamp] [$level] $message" >> "$LOG_FILE" + + # Mostra no console com cores + case $level in + "INFO") + echo -e "${BLUE}[INFO]${NC} $message" + ;; + "SUCCESS") + echo -e "${GREEN}[SUCESSO]${NC} $message" + ;; + "ERROR") + echo -e "${RED}[ERRO]${NC} $message" + ;; + "WARNING") + echo -e "${YELLOW}[AVISO]${NC} $message" + ;; + "DEBUG") + if [ "$DEBUG_MODE" = true ]; then + echo -e "${PURPLE}[DEBUG]${NC} $message" + fi + ;; + esac +} + +# Verifica root +if [[ $EUID -ne 0 ]]; then + log "ERROR" "Execute como root: sudo ./install.sh" + exit 1 +fi +RestartSec=5 +StandardOutput=journal +StandardError=journal + +[Install] +WantedBy=multi-user.target +EOF + +# Habilita e inicia serviço +systemctl daemon-reload +systemctl enable fazai-gemma-worker +systemctl start fazai-gemma-worker + +echo "✅ FazAI v2.0 instalado com sucesso!" +echo "📍 Teste: fazai ask 'olá mundo'" +echo "📍 Status: systemctl status fazai-gemma-worker" +echo "📍 Logs: journalctl -u fazai-gemma-worker -f" + mkdir -p $(dirname $LOG_FILE) + + # Escreve log ao arquivo + echo "[$timestamp] [$level] $message" >> $LOG_FILE + + # Mostra no console com cores + case $level in + "INFO") + echo -e "${BLUE}[INFO]${NC} $message" + ;; + "SUCCESS") + echo -e "${GREEN}[SUCESSO]${NC} $message" + ;; + "ERROR") + echo -e "${RED}[ERRO]${NC} $message" + ;; + "WARNING") + echo -e "${YELLOW}[AVISO]${NC} $message" + ;; + "DEBUG") + if [ "$DEBUG_MODE" = true ]; then + echo -e "${PURPLE}[DEBUG]${NC} $message" + fi + ;; + esac +} +# Consulta ajuda da IA em caso de erro (simplificada) +ai_help() { + local prompt="$1" + log "INFO" "Erro detectado: $prompt" + log "INFO" "Verifique os logs em $LOG_FILE para mais detalhes" +} + + +# Função para salvar estado da instalação +save_install_state() { + local step=$1 + local status=$2 + INSTALL_STATE["$step"]="$status" + mkdir -p $(dirname "$INSTALL_STATE_FILE") + + # Limpa o arquivo antes de reescrever + > "$INSTALL_STATE_FILE" + for key in "${!INSTALL_STATE[@]}"; do + echo "$key=${INSTALL_STATE[$key]}" >> "$INSTALL_STATE_FILE" + done + log "DEBUG" "Estado salvo: $step = $status" +} + +# Função para carregar estado da instalação +load_install_state() { + if [ -f "$INSTALL_STATE_FILE" ]; then + while IFS='=' read -r key value; do + if [ -n "$key" ] && [ -n "$value" ]; then + INSTALL_STATE["$key"]="$value" + fi + done < "$INSTALL_STATE_FILE" + log "INFO" "Estado da instalação carregado de $INSTALL_STATE_FILE" + fi +} + +# Função para verificar versão de uma dependência +check_dependency_version() { + local cmd=$1 + local min_version=$2 + + if ! command -v "$cmd" &> /dev/null; then + log "DEBUG" "Comando $cmd não encontrado" + return 1 + fi + + local current_version + case $cmd in + "node") + current_version=$(node -v | sed 's/v//') + ;; + "npm") + current_version=$(npm -v) + ;; + "python3") + current_version=$(python3 --version | awk '{print $2}') + ;; + "pip3") + current_version=$(pip3 --version | awk '{print $2}') + ;; + "gcc") + current_version=$(gcc --version | head -n1 | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -n1) + ;; + *) + current_version=$($cmd --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -n1) + ;; + esac + + if [ -z "$current_version" ]; then + log "WARNING" "Não foi possível determinar a versão de $cmd" + return 2 + fi + + # Comparação de versões usando sort -V + if printf '%s\n' "$min_version" "$current_version" | sort -V | head -n1 | grep -q "^$min_version$"; then + log "SUCCESS" "$cmd versão $current_version atende requisito mínimo ($min_version)" + return 0 + else + log "WARNING" "$cmd versão $current_version é menor que a mínima requerida ($min_version)" + return 3 + fi +} + +# Função para converter arquivos para formato Linux (dos2unix) +convert_files_to_unix() { + log "INFO" "Convertendo arquivos para formato Linux..." + + # Instala dos2unix se não estiver disponível + if ! command -v dos2unix &> /dev/null; then + log "INFO" "Instalando dos2unix..." + apt-get update && apt-get install -y dos2unix + + if ! command -v dos2unix &> /dev/null; then + log "WARNING" "dos2unix não pôde ser instalado. Tentando método alternativo..." + # Método alternativo usando sed + convert_with_sed() { + local file="$1" + if [ -f "$file" ]; then + sed -i 's/\r$//' "$file" 2>/dev/null + if [ $? -eq 0 ]; then + log "DEBUG" "Convertido com sed: $file" + else + log "WARNING" "Falha ao converter: $file" + fi + fi + } + + # Converte arquivos críticos usando sed + find . -type f \( -name "*.sh" -o -name "*.bash" -o -name "*.conf" \) -exec bash -c 'convert_with_sed "$0"' {} \; + log "SUCCESS" "Conversão concluída usando método alternativo" + return 0 + fi + fi + + # Executa o script dos2unixAll.sh se existir + if [ -f "etc/fazai/dos2unixAll.sh" ]; then + log "INFO" "Executando script dos2unixAll.sh..." + chmod +x "etc/fazai/dos2unixAll.sh" + cd "$(dirname "$(readlink -f "$0")")" || cd /opt/fazai + bash etc/fazai/dos2unixAll.sh + log "SUCCESS" "Script dos2unixAll.sh executado" + else + log "INFO" "Script dos2unixAll.sh não encontrado. Executando conversão manual..." + + # Encontra e converte todos os arquivos relevantes + find . -type f \ + \( -name "*.sh" \ + -o -name "*.bash" \ + -o -name "*.conf" \ + -o -name "*.yml" \ + -o -name "*.yaml" \ + -o -name "*.json" \ + -o -name "Dockerfile" \) \ + -exec sh -c ' + for file do + echo "🔄 Convertendo: $file" + dos2unix "$file" 2>/dev/null + if [ $? -eq 0 ]; then + echo "✅ Convertido com sucesso: $file" + else + echo "❌ Erro ao converter: $file" + fi + done + ' sh {} + + fi + + log "SUCCESS" "Conversão de arquivos para formato Linux concluída" +} + +# Função para instalar bash completion +install_bash_completion() { + log "INFO" "Instalando bash completion..." + + # Verifica se o bash-completion está instalado + if ! dpkg -l | grep -q bash-completion 2>/dev/null; then + log "INFO" "Instalando pacote bash-completion..." + apt-get update && apt-get install -y bash-completion + fi + + local completion_dir="/etc/bash_completion.d" + mkdir -p "$completion_dir" + + if [ -f "etc/fazai/fazai-completion.sh" ]; then + cp "etc/fazai/fazai-completion.sh" "$completion_dir/fazai" + else + log "WARNING" "etc/fazai/fazai-completion.sh não encontrado, gerando script simples" + cat > "$completion_dir/fazai" <<'EOF' +#!/bin/bash +complete -W "install uninstall status config help version" fazai +EOF + fi + chmod 644 "$completion_dir/fazai" + log "SUCCESS" "Script de completion instalado em $completion_dir/fazai" + + # Adiciona ao .bashrc se não existir + if ! grep -q "source $completion_dir/fazai" /root/.bashrc 2>/dev/null; then + echo "# FazAI bash completion" >> /root/.bashrc + echo "if [ -f /etc/bash_completion ]; then" >> /root/.bashrc + echo " source /etc/bash_completion" >> /root/.bashrc + echo "fi" >> /root/.bashrc + echo "source $completion_dir/fazai" >> /root/.bashrc + log "SUCCESS" "Bash completion configurado no .bashrc" + fi +} + +# Função para verificar e criar diretório de logs +setup_logging() { + mkdir -p $(dirname $LOG_FILE) + touch $LOG_FILE + log "INFO" "Inicializando log de instalação em $LOG_FILE" + log "INFO" "====== Início da instalação do FazAI v$VERSION ======" + log "INFO" "Data e hora: $(date)" + log "INFO" "Sistema: $(uname -a)" +} + +# Função para verificar permissões de root +check_root() { + log "DEBUG" "Verificando permissões de root..." + if [ "$EUID" -ne 0 ]; then + log "ERROR" "Este script precisa ser executado como root (sudo)." + exit 1 + fi + log "SUCCESS" "Verificação de permissões de root concluída." +} + +# Função para verificar o sistema operacional +check_system() { + log "DEBUG" "Verificando sistema operacional..." + if [ -f /etc/os-release ]; then + . /etc/os-release + # Trata derivados como Ubuntu (ex.: Pop!_OS) + if echo "${ID_LIKE:-}" | grep -qi ubuntu; then + ID=ubuntu + fi + case "$ID" in + debian|ubuntu|pop) + log "SUCCESS" "Sistema Debian/Ubuntu detectado: $NAME $VERSION_ID" + ;; + fedora|rhel|centos) + log "SUCCESS" "Sistema Fedora/RedHat/CentOS detectado: $NAME $VERSION_ID" + ;; + *) + log "WARNING" "Este script foi projetado para Debian, Ubuntu ou Fedora. Detectado: $NAME $VERSION_ID." + read -p "Deseja continuar mesmo assim? (s/n): " -n 1 -r + echo + if [[ ! $REPLY =~ ^[Ss]$ ]]; then + log "INFO" "Instalação cancelada pelo usuário." + exit 1 + fi + log "WARNING" "Prosseguindo instalação em sistema não suportado oficialmente." + ;; + esac + else + log "WARNING" "Não foi possível detectar o sistema operacional. Prosseguindo com cautela." + fi +} + +# Garante runtime de contêiner (Docker) para serviços opcionais (Qdrant/Prometheus/Grafana) +ensure_container_runtime() { + if command -v docker >/dev/null 2>&1 || command -v podman >/dev/null 2>&1; then + log "INFO" "Runtime de contêiner já disponível" + return 0 + fi + log "INFO" "Instalando Docker (runtime de contêiner)" + if command -v apt-get >/dev/null 2>&1; then + apt-get update && apt-get install -y docker.io || log "WARNING" "Falha ao instalar Docker (apt)." + systemctl enable --now docker || true + elif command -v dnf >/dev/null 2>&1; then + dnf install -y docker || log "WARNING" "Falha ao instalar Docker (dnf)." + systemctl enable --now docker || true + elif command -v yum >/dev/null 2>&1; then + yum install -y docker || log "WARNING" "Falha ao instalar Docker (yum)." + systemctl enable --now docker || true + elif command -v zypper >/dev/null 2>&1; then + zypper install -y docker || log "WARNING" "Falha ao instalar Docker (zypper)." + systemctl enable --now docker || true + else + log "WARNING" "Gerenciador de pacotes não suportado para instalação automática do Docker." + fi +} + +# Garantir utilitários de rede usados por scripts e testes +ensure_network_utils() { + log "INFO" "Verificando utilitários de rede (curl, jq, netcat)" + local pkgs=(curl jq netcat) + for p in "${pkgs[@]}"; do + if ! command -v "$p" &>/dev/null; then + log "INFO" "Instalando $p" + if command -v apt-get &>/dev/null; then + apt-get update && apt-get install -y $p || { log "WARNING" "Falha ao instalar $p"; } + elif command -v dnf &>/dev/null; then + dnf install -y $p || { log "WARNING" "Falha ao instalar $p"; } + else + log "WARNING" "Gerenciador de pacotes não detectado; instale $p manualmente" + fi + else + log "DEBUG" "$p já presente" + fi + done +} + +# Função para instalar Node.js com retry e múltiplas versões +install_nodejs() { + if command -v node &> /dev/null; then + NODE_VERSION=$(node -v) + log "SUCCESS" "Node.js já instalado: $NODE_VERSION" + + # Verifica versão mínima do Node.js (>=22.0.0) + NODE_VERSION_NUM=$(echo $NODE_VERSION | cut -c 2-) + NODE_MAJOR=$(echo $NODE_VERSION_NUM | cut -d. -f1) + + if [ $NODE_MAJOR -lt 22 ]; then + log "WARNING" "FazAI requer Node.js versão 22.0.0 ou superior. Versão atual: $NODE_VERSION" + log "INFO" "Tentando atualizar o Node.js..." + install_nodejs_from_source + fi + else + log "WARNING" "Node.js não encontrado. Iniciando instalação..." + install_nodejs_from_source + fi +} + +# Função para instalar Node.js a partir de diferentes fontes +install_nodejs_from_source() { + local success=false + # Detecta gerenciador de pacotes + local PKG_MGR="apt-get" + if [ -f /etc/os-release ]; then + . /etc/os-release + case "$ID" in + fedora|rhel|centos) + PKG_MGR="dnf" + ;; + *) + PKG_MGR="apt-get" + ;; + esac + fi + log "INFO" "Atualizando lista de pacotes..." + $PKG_MGR update -y + $PKG_MGR autoremove -y + $PKG_MGR upgrade -y + log "INFO" "Tentando instalar Node.js via $PKG_MGR..." + $PKG_MGR install -y nodejs npm + if command -v node &> /dev/null; then + NODE_VERSION=$(node -v) + NODE_VERSION_NUM=$(echo $NODE_VERSION | cut -c 2-) + NODE_MAJOR=$(echo $NODE_VERSION_NUM | cut -d. -f1) + if [ $NODE_MAJOR -ge 22 ]; then + log "SUCCESS" "Node.js instalado com sucesso via $PKG_MGR: $NODE_VERSION" + success=true + return 0 + else + log "WARNING" "Versão do Node.js instalada via $PKG_MGR é muito antiga: $NODE_VERSION" + fi + else + log "WARNING" "Falha ao instalar Node.js via $PKG_MGR." + fi + # Tenta instalar via NodeSource para diferentes versões (apenas para Debian/Ubuntu) + if [ "$success" = false ] && [ "$PKG_MGR" = "apt-get" ]; then + if ! command -v curl &> /dev/null; then + $PKG_MGR install -y curl + fi + for version in "${NODE_VERSIONS[@]}"; do + log "INFO" "Tentando instalar Node.js v$version via NodeSource..." + for attempt in $(seq 1 $RETRY_COUNT); do + log "DEBUG" "Tentativa $attempt de $RETRY_COUNT para Node.js v$version" + if curl -fsSL "https://deb.nodesource.com/setup_${version}.x" | bash - && $PKG_MGR install -y nodejs; then + if command -v node &> /dev/null; then + NODE_VERSION=$(node -v) + log "SUCCESS" "Node.js instalado com sucesso: $NODE_VERSION" + success=true + break 2 + fi + fi + log "WARNING" "Tentativa $attempt falhou para Node.js v$version" + sleep 2 + done + done + fi + if [ "$success" = false ]; then + log "ERROR" "Todas as tentativas de instalação do Node.js falharam." + log "ERROR" "Por favor, instale o Node.js manualmente e execute este script novamente." + log "ERROR" "Visite: https://nodejs.org/en/download/package-manager/" + exit 1 + fi +} + +# Função para verificar e instalar npm +install_npm() { + local PKG_MGR="apt-get" + if [ -f /etc/os-release ]; then + . /etc/os-release + case "$ID" in + fedora|rhel|centos) + PKG_MGR="dnf" + ;; + *) + PKG_MGR="apt-get" + ;; + esac + fi + if ! command -v npm &> /dev/null; then + log "WARNING" "npm não encontrado. Instalando..." + $PKG_MGR install -y npm + if ! command -v npm &> /dev/null; then + log "ERROR" "Falha ao instalar npm via $PKG_MGR." + exit 1 + else + NPM_VERSION=$(npm -v) + log "SUCCESS" "npm instalado com sucesso: $NPM_VERSION" + fi + else + NPM_VERSION=$(npm -v) + log "SUCCESS" "npm já instalado: $NPM_VERSION" + fi +} + +# Função para verificar e instalar Python 3 +install_python() { + local PKG_MGR="apt-get" + if [ -f /etc/os-release ]; then + . /etc/os-release + case "$ID" in + fedora|rhel|centos) + PKG_MGR="dnf" + ;; + *) + PKG_MGR="apt-get" + ;; + esac + fi + if command -v python3 &> /dev/null; then + PYTHON_VERSION=$(python3 --version | awk '{print $2}') + PYTHON_MAJOR=$(echo "$PYTHON_VERSION" | cut -d. -f1) + PYTHON_MINOR=$(echo "$PYTHON_VERSION" | cut -d. -f2) + if [ "$PYTHON_MAJOR" -lt 3 ] || { [ "$PYTHON_MAJOR" -eq 3 ] && [ "$PYTHON_MINOR" -lt 10 ]; }; then + log "WARNING" "FazAI requer Python 3.10 ou superior. Versão atual: $PYTHON_VERSION" + $PKG_MGR install -y python3 python3-pip + fi + else + log "WARNING" "Python3 não encontrado. Instalando..." + $PKG_MGR install -y python3 python3-pip + fi + if command -v python3 &> /dev/null; then + PYTHON_VERSION=$(python3 --version | awk '{print $2}') + log "SUCCESS" "python3 instalado: $PYTHON_VERSION" + else + log "ERROR" "Falha ao instalar python3." + exit 1 + fi +} + +# Função para verificar e instalar gcc +install_gcc() { + local PKG_MGR="apt-get" + if [ -f /etc/os-release ]; then + . /etc/os-release + case "$ID" in + fedora|rhel|centos) + PKG_MGR="dnf" + ;; + *) + PKG_MGR="apt-get" + ;; + esac + fi + if ! command -v gcc &> /dev/null; then + log "WARNING" "gcc não encontrado. Instalando build-essential..." + $PKG_MGR install -y gcc g++ make cmake + if ! command -v gcc &> /dev/null; then + log "ERROR" "Falha ao instalar gcc. Por favor, instale manualmente." + exit 1 + fi + GCC_VERSION=$(gcc --version | head -n1) + CMAKE_VERSION=$(cmake --version 2>/dev/null | head -n1) + log "SUCCESS" "gcc instalado com sucesso: $GCC_VERSION" + [ -n "$CMAKE_VERSION" ] && log "SUCCESS" "cmake disponível: $CMAKE_VERSION" + else + GCC_VERSION=$(gcc --version | head -n1) + CMAKE_VERSION=$(cmake --version 2>/dev/null | head -n1) + log "SUCCESS" "gcc já instalado: $GCC_VERSION" + [ -n "$CMAKE_VERSION" ] && log "SUCCESS" "cmake disponível: $CMAKE_VERSION" + fi +} + + + +# Função para criar estrutura de diretórios +create_directories() { + log "INFO" "Criando estrutura de diretórios..." + + # Garante a criação do diretório de logs + if [ ! -d "/var/log/fazai" ]; then + mkdir -p "/var/log/fazai" + log "SUCCESS" "Diretório /var/log/fazai criado" + fi + + local directories=( + "/opt/fazai/bin" + "/opt/fazai/lib" + "/opt/fazai/tools" + "/opt/fazai/mods" + " /opt/fazai/models" + "/etc/fazai" + "/var/log/fazai" + "/var/lib/fazai/history" + "/var/lib/fazai/cache" + "/var/lib/fazai/data" + "/var/backups/fazai" + ) + + for dir in "${directories[@]}"; do + if [ ! -d "$dir" ]; then + mkdir -p "$dir" + log "DEBUG" "Diretório criado: $dir" + else + log "DEBUG" "Diretório já existe: $dir" + fi + done + # Diretório de segredos OPNsense (permissões estritas) + mkdir -p /etc/fazai/secrets/opnsense && chmod 700 /etc/fazai/secrets/opnsense || true + + # Garantir diretório de modelos com permissões apropriadas + if [ ! -d "/opt/fazai/models" ]; then + mkdir -p /opt/fazai/models + chown root:root /opt/fazai/models + chmod 755 /opt/fazai/models + log "DEBUG" "Diretório /opt/fazai/models criado" + fi + + log "SUCCESS" "Estrutura de diretórios criada com sucesso." +} + +# Verifica saúde do serviço e tenta autorreparo básico +health_check_repair() { + log "INFO" "Executando health-check do FazAI (/agent/status)" + local API="http://127.0.0.1:3120" + local ok=false + for attempt in 1 2 3; do + if curl -fsS --max-time 3 "$API/agent/status" >/dev/null 2>&1; then + ok=true + break + fi + log "WARNING" "Health-check falhou (tentativa $attempt). Tentando reparo..." + # Reinicia o worker e o serviço mestre + systemctl restart fazai-gemma-worker 2>/dev/null || true + sleep 1 + # Garante diretório do socket + mkdir -p /run/fazai && chmod 755 /run/fazai || true + systemctl restart fazai 2>/dev/null || true + sleep 2 + # Se o binário do worker não existir, tenta compilar/instalar + if [ ! -x "/opt/fazai/bin/fazai-gemma-worker" ] && [ -d "worker" ] && [ -f "worker/CMakeLists.txt" ]; then + log "INFO" "Binário do worker ausente; tentando compilar/instalar..." + (cd worker && ./build.sh && sudo make install) || true + systemctl restart fazai-gemma-worker 2>/dev/null || true + sleep 1 + fi + done + if [ "$ok" = true ]; then + log "SUCCESS" "Health-check OK: /agent/status respondeu" + else + log "ERROR" "Health-check ainda falhou após tentativas de reparo. Verifique logs do serviço." + fi +} + +# Função para copiar arquivos +copy_files() { + log "INFO" "Copiando arquivos para diretórios de instalação..." + + local copy_errors=0 + + # Cria função auxiliar para cópia com verificação de erros + copy_with_verification() { + local source=$1 + local destination=$2 + local description=$3 + + if [ ! -e "$source" ]; then + log "ERROR" "Arquivo de origem ausente para $description: $source" + return 1 + fi + + local output + if output=$(cp -r "$source" "$destination" 2>&1); then + local dest_path="$destination" + if [ -d "$destination" ]; then + dest_path="$destination/$(basename "$source")" + fi + if [ -e "$dest_path" ]; then + log "DEBUG" "$description copiado de $source para $destination" + return 0 + else + log "ERROR" "Arquivo não encontrado após copiar $source para $destination" + return 1 + fi + else + log "ERROR" "Falha ao copiar $description ($source -> $destination): $output" + return 1 + fi + } + + + + # Cria CLI básico se não existir + if [ ! -f "bin/fazai" ]; then + log "INFO" "Criando CLI básico..." + mkdir -p "bin" + cat > "bin/fazai" << 'EOF' +#!/usr/bin/env node + +/** + * FazAI CLI + */ + +const { spawn } = require('child_process'); +const fs = require('fs'); + +const args = process.argv.slice(2); + +if (args.includes('--version')) { + console.log('FazAI v2.0.0'); + process.exit(0); +} + +if (args.includes('--help')) { + console.log('FazAI - Orquestrador Inteligente de Automação'); + console.log(''); + console.log('Uso: fazai [comando] [opções]'); + console.log(''); + console.log('Comandos:'); + console.log(' --version Mostra a versão'); + console.log(' --help Mostra esta ajuda'); + console.log(' --status Status do daemon'); + console.log(' --start Inicia o daemon'); + console.log(' --stop Para o daemon'); + console.log(' --restart Reinicia o daemon'); + process.exit(0); +} + +if (args.includes('--status')) { + const { execSync } = require('child_process'); + try { + const status = execSync('systemctl is-active fazai', { encoding: 'utf8' }).trim(); + console.log(`FazAI daemon: ${status}`); + } catch (error) { + console.log('FazAI daemon: inativo'); + } + process.exit(0); +} + +console.log('FazAI CLI v2.0.0 - Use --help para mais informações'); +EOF + chmod +x "bin/fazai" + fi + + # Garante que o arquivo de configuração exemplo exista + if [ ! -f "etc/fazai/fazai.conf.example" ]; then + log "ERROR" "etc/fazai/fazai.conf.example não encontrado. Verifique o repositório." + exit 1 + fi + + # Agora copia os arquivos + # Copia toda a biblioteca (inclui handlers, core, providers, etc.) + if ! copy_with_verification "opt/fazai/lib" "/opt/fazai/" "Biblioteca FazAI"; then + copy_errors=$((copy_errors+1)) + else + # Garante permissão de execução no entrypoint + chmod 755 /opt/fazai/lib/main.js 2>/dev/null || true + fi + + + + # Copia módulos e integrações adicionais necessários + for f in \ + "opt/fazai/lib/mcp_opnsense.js" \ + "opt/fazai/lib/complex_tasks.js" \ + "opt/fazai/tools/fazai_web_frontend.html" \ + "opt/fazai/tools/web_search.js" \ + "opt/fazai/tools/suricata_setup.js" \ + "opt/fazai/tools/modsecurity_setup.js" \ + "opt/fazai/tools/crowdsec_setup.js" \ + "opt/fazai/tools/spamexperts.js" \ + "opt/fazai/tools/cloudflare.js" \ + ; do + if [ -f "$f" ]; then + if ! copy_with_verification "$f" "/opt/fazai/$(dirname ${f#opt/fazai/})/" "$(basename $f)"; then + copy_errors=$((copy_errors+1)) + fi + fi + done + + # Copia todas as ferramentas para garantir que plugins sejam carregados + if [ -d "opt/fazai/tools" ]; then + if ! copy_with_verification "opt/fazai/tools" "/opt/fazai/" "Ferramentas FazAI"; then + copy_errors=$((copy_errors+1)) + fi + fi + + # Copia interface web (DOCLER) + if [ -d "opt/fazai/web" ]; then + if ! copy_with_verification "opt/fazai/web" "/opt/fazai/" "Interface Web"; then + copy_errors=$((copy_errors+1)) + fi + # Instalar dependências do web server (express, ws) + if [ -f "/opt/fazai/web/package.json" ]; then + log "INFO" "Instalando dependências da interface web (/opt/fazai/web)" + (cd /opt/fazai/web && npm install --omit=dev --no-audit --no-progress || true) + # Tenta instalar autenticação PAM (opcional) + (cd /opt/fazai/web && npm install authenticate-pam --no-audit --no-progress || true) + fi + + # Cria usuário de serviço não-root para o Docler + if ! id -u fazai-web >/dev/null 2>&1; then + log "INFO" "Criando usuário de serviço 'fazai-web' (sem shell de login)" + useradd --system --home /opt/fazai/web --shell /usr/sbin/nologin fazai-web || true + fi + # Corrige permissões para acesso do usuário fazai-web + chmod 755 /opt/fazai || true + chmod 755 /opt/fazai/web || true + chown -R fazai:fazai-web /opt/fazai/web || true + chmod -R g+rx /opt/fazai/web || true + fi + + # Instalar Qdrant Vector Database + log "INFO" "Instalando Qdrant Vector Database..." + if [ ! -f "/opt/fazai/bin/qdrant" ]; then + log "INFO" "Baixando Qdrant binário..." + if curl -L https://github.com/qdrant/qdrant/releases/latest/download/qdrant-x86_64-unknown-linux-gnu.tar.gz -o /tmp/qdrant.tar.gz 2>/dev/null; then + tar -xzf /tmp/qdrant.tar.gz -C /opt/fazai/bin/ 2>/dev/null || log "WARN" "Falha ao extrair Qdrant - usando Docker fallback" + chmod +x /opt/fazai/bin/qdrant 2>/dev/null || true + rm -f /tmp/qdrant.tar.gz + log "INFO" "Qdrant binário instalado" + else + log "WARN" "Falha no download do Qdrant - será usado via Docker" + fi + fi + + # Criar diretórios e configuração do Qdrant + mkdir -p /var/lib/qdrant /opt/fazai/web/static + chown -R fazai:fazai /var/lib/qdrant + + # Configuração Qdrant + cat > /etc/fazai/qdrant.yaml << 'EOF' +log_level: INFO +storage: + storage_path: /var/lib/qdrant/storage + snapshots_path: /var/lib/qdrant/snapshots + on_disk_payload: true + +service: + http_port: 6333 + grpc_port: 6334 + host: 0.0.0.0 + max_request_size_mb: 32 + max_workers: 0 + static_content_dir: /opt/fazai/web/static + enable_cors: true + +web_ui: + enabled: true + +cluster: + enabled: false + +telemetry_disabled: false +EOF + + # Copia binários auxiliares (inclui fazai-gemma-worker e utilitários) + if [ -d "opt/fazai/bin" ]; then + if ! copy_with_verification "opt/fazai/bin" "/opt/fazai/" "Binários FazAI"; then + copy_errors=$((copy_errors+1)) + else + chmod -R 755 /opt/fazai/bin 2>/dev/null || true + fi + fi + + # Copia modelos Gemma se estiverem no repositório (estrutura antiga) + if [ -d "opt/fazai/models/gemma" ]; then + if ! copy_with_verification "opt/fazai/models/gemma" "/opt/fazai/models/" "Modelos Gemma"; then + copy_errors=$((copy_errors+1)) + fi + else + # Nova estrutura: pesos e tokenizer embarcados junto ao fonte + # Preferir em worker/src/gemma.cpp/, fallback para gemma.cpp/ na raiz + SRC_DIR="" + if [ -f "worker/src/gemma.cpp/2.0-2b-it-sfp.sbs" ] || [ -f "worker/src/gemma.cpp/tokenizer.spm" ]; then + SRC_DIR="worker/src/gemma.cpp" + elif [ -f "gemma.cpp/2.0-2b-it-sfp.sbs" ] || [ -f "gemma.cpp/tokenizer.spm" ]; then + SRC_DIR="gemma.cpp" + fi + if [ -n "$SRC_DIR" ]; then + mkdir -p /opt/fazai/models/gemma + if [ -f "$SRC_DIR/2.0-2b-it-sfp.sbs" ]; then + log "INFO" "Copiando pesos Gemma de $SRC_DIR para /opt/fazai/models/gemma/" + cp -f "$SRC_DIR/2.0-2b-it-sfp.sbs" "/opt/fazai/models/gemma/" || copy_errors=$((copy_errors+1)) + fi + if [ -f "$SRC_DIR/tokenizer.spm" ]; then + log "INFO" "Copiando tokenizer Gemma de $SRC_DIR para /opt/fazai/models/gemma/" + cp -f "$SRC_DIR/tokenizer.spm" "/opt/fazai/models/gemma/" || copy_errors=$((copy_errors+1)) + fi + chmod 644 /opt/fazai/models/gemma/* 2>/dev/null || true + + # Atualiza fazai.conf com caminhos detectados + if [ -f "/etc/fazai/fazai.conf" ]; then + WEIGHTS_PATH="/opt/fazai/models/gemma/2.0-2b-it-sfp.sbs" + TOKENIZER_PATH="/opt/fazai/models/gemma/tokenizer.spm" + if [ -f "$WEIGHTS_PATH" ]; then + sed -i "/^\[gemma_cpp\]/,/^\[/ s|^weights\s*=.*|weights = $WEIGHTS_PATH|" /etc/fazai/fazai.conf || true + fi + if [ -f "$TOKENIZER_PATH" ]; then + sed -i "/^\[gemma_cpp\]/,/^\[/ s|^tokenizer\s*=.*|tokenizer = $TOKENIZER_PATH|" /etc/fazai/fazai.conf || true + fi + sed -i "/^\[gemma_cpp\]/,/^\[/ s|^endpoint\s*=.*|endpoint = /opt/fazai/bin/gemma_oneshot|" /etc/fazai/fazai.conf || true + sed -i "/^\[gemma_cpp\]/,/^\[/ s|^default_model\s*=.*|default_model = gemma2-2b-it|" /etc/fazai/fazai.conf || true + fi + else + # Fallback: caminho externo informado pelo usuário + if [ -d "/media/rluft/fedora/root/opt/fazai/models/gemma" ]; then + if ! copy_with_verification "/media/rluft/fedora/root/opt/fazai/models/gemma" "/opt/fazai/models/" "Modelos Gemma (externo)"; then + copy_errors=$((copy_errors+1)) + fi + fi + fi + fi + + # Compila e instala o binário real gemma_oneshot se as fontes estiverem em worker/src/gemma.cpp + if [ -d "worker/src/gemma.cpp" ] && [ -f "worker/src/gemma.cpp/CMakeLists.txt" ]; then + log "INFO" "Compilando gemma.cpp (gemma_oneshot) a partir de worker/src/gemma.cpp..." + ( + cd worker/src/gemma.cpp + mkdir -p build + cd build + cmake .. -DCMAKE_BUILD_TYPE=Release || true + make -j$(nproc) gemma_oneshot || make gemma_oneshot || true + ) + if [ -x "worker/src/gemma.cpp/build/gemma_oneshot" ]; then + install -m 0755 "worker/src/gemma.cpp/build/gemma_oneshot" "/opt/fazai/bin/gemma_oneshot.real" || true + log "SUCCESS" "gemma_oneshot.real instalado em /opt/fazai/bin" + else + log "WARNING" "Falha ao compilar gemma_oneshot. O wrapper tentará outros caminhos se existir um binário no sistema." + fi + fi + + # DeepSeek helper removido (no-op) + + if ! copy_with_verification "etc/fazai/fazai.conf.example" "/etc/fazai/fazai.conf.default" "Configuração padrão"; then + copy_errors=$((copy_errors+1)) + fi + + # Preserva configuracao atual antes de substituir + if [ -f "/etc/fazai/fazai.conf" ]; then + cp /etc/fazai/fazai.conf /etc/fazai/fazai.conf.bak && \ + log "INFO" "Backup criado em fazai.conf.bak" + mv /etc/fazai/fazai.conf /etc/fazai/fazai.conf.old + log "INFO" "Configuração existente renomeada para fazai.conf.old" + fi + + if ! copy_with_verification "etc/fazai/fazai.conf.example" "/etc/fazai/fazai.conf" "Configuração de sistema"; then + copy_errors=$((copy_errors+1)) + else + log "SUCCESS" "Novo arquivo de configuração criado em /etc/fazai/fazai.conf" + + if [ -f "/etc/fazai/fazai.conf.old" ]; then + for prov in openrouter requesty openai; do + key_val=$(awk -v sec="[$prov]" '$0==sec{f=1;next} /^\[/{f=0} f && /api_key/{print $3}' /etc/fazai/fazai.conf.old) + if [ -n "$key_val" ]; then + sed -i "/^\[$prov\]/,/^$/s|api_key =.*|api_key = $key_val|" /etc/fazai/fazai.conf + fi + done + fi + if [ -f "/root/.env" ]; then + /bin/bash /opt/fazai/tools/sync-keys.sh >/dev/null 2>&1 && log "INFO" "Chaves sincronizadas do .env" + fi + fi + + # Copia gemma_bootstrap + if [ -f "opt/fazai/tools/gemma_bootstrap.sh" ]; then + if ! copy_with_verification "opt/fazai/tools/gemma_bootstrap.sh" "/opt/fazai/tools/" "Gemma bootstrap"; then + copy_errors=$((copy_errors+1)) + else + chmod +x /opt/fazai/tools/gemma_bootstrap.sh + log "SUCCESS" "Gemma bootstrap instalado" + fi + fi + + # Copia complex_tasks.conf.example se existir + if [ -f "etc/fazai/complex_tasks.conf.example" ]; then + if ! copy_with_verification "etc/fazai/complex_tasks.conf.example" "/etc/fazai/complex_tasks.conf.default" "Configuração de tarefas complexas"; then + copy_errors=$((copy_errors+1)) + else + log "SUCCESS" "Configuração de tarefas complexas copiada" + fi + fi + + # Copia manual para /opt/fazai/MANUAL_COMPLETO.md (fallback para MANUAL_FERRAMENTAS.md) + if [ -f "MANUAL_COMPLETO.md" ]; then + if ! copy_with_verification "MANUAL_COMPLETO.md" "/opt/fazai/" "Manual completo"; then + copy_errors=$((copy_errors+1)) + fi + elif [ -f "MANUAL_FERRAMENTAS.md" ]; then + if ! copy_with_verification "MANUAL_FERRAMENTAS.md" "/opt/fazai/" "Manual de ferramentas"; then + copy_errors=$((copy_errors+1)) + else + # Mantém o nome esperado pelo CLI + cp -f "/opt/fazai/MANUAL_FERRAMENTAS.md" "/opt/fazai/MANUAL_COMPLETO.md" 2>/dev/null || true + fi + else + log "WARNING" "Manual não encontrado no repositório (MANUAL_COMPLETO.md/MANUAL_FERRAMENTAS.md)" + fi + + if ! copy_with_verification "bin/fazai" "/opt/fazai/bin/" "CLI"; then + copy_errors=$((copy_errors+1)) + fi + chmod 755 /opt/fazai/bin/fazai + ln -sf /opt/fazai/bin/fazai /usr/local/bin/fazai + log "SUCCESS" "CLI instalado em /usr/local/bin/fazai" + + # Instala GPT-Web2Shell (utilitário externo, exclusivo - OPT-IN via FAZAI_ENABLE_GPT_WEB2SHELL=1) + if [ "${FAZAI_ENABLE_GPT_WEB2SHELL}" = "1" ]; then + EXTRA_DIR="${FAZAI_LOCAL_EXTRAS_DIR:-}" + # Preferir extras externos + if [ -n "$EXTRA_DIR" ] && [ -f "$EXTRA_DIR/gpt-web2shell/bin/gpt-web2shell" ]; then + log "INFO" "Instalando GPT-Web2Shell a partir de FAZAI_LOCAL_EXTRAS_DIR=$EXTRA_DIR" + mkdir -p /opt/fazai/bin /opt/fazai/tools + cp -f "$EXTRA_DIR/gpt-web2shell/bin/gpt-web2shell" /opt/fazai/bin/gpt-web2shell + cp -f "$EXTRA_DIR/gpt-web2shell/opt/fazai/tools/gpt-web2shell.js" /opt/fazai/tools/gpt-web2shell.js + chmod 755 /opt/fazai/bin/gpt-web2shell /opt/fazai/tools/gpt-web2shell.js || true + ln -sf /opt/fazai/bin/gpt-web2shell /usr/local/bin/gpt-web2shell + log "SUCCESS" "GPT-Web2Shell instalado em /usr/local/bin/gpt-web2shell (extras externos)" + elif [ -f "bin/gpt-web2shell" ] && [ -f "opt/fazai/tools/gpt-web2shell.js" ]; then + # fallback: se os arquivos estiverem presentes no diretório do repositório + if copy_with_verification "bin/gpt-web2shell" "/opt/fazai/bin/" "GPT-Web2Shell"; then + mkdir -p /opt/fazai/tools + cp -f "opt/fazai/tools/gpt-web2shell.js" "/opt/fazai/tools/gpt-web2shell.js" + chmod 755 /opt/fazai/bin/gpt-web2shell /opt/fazai/tools/gpt-web2shell.js || true + ln -sf /opt/fazai/bin/gpt-web2shell /usr/local/bin/gpt-web2shell + log "SUCCESS" "GPT-Web2Shell instalado em /usr/local/bin/gpt-web2shell" + else + log "WARNING" "Falha ao instalar GPT-Web2Shell (arquivos locais)" + fi + else + log "WARNING" "FAZAI_ENABLE_GPT_WEB2SHELL=1 definido, mas arquivos não encontrados. Use scripts/install-web2shell.sh com FAZAI_LOCAL_EXTRAS_DIR." + fi + else + log "INFO" "GPT-Web2Shell não instalado (exclusivo). Para instalar, exporte FAZAI_ENABLE_GPT_WEB2SHELL=1 e forneça os arquivos via FAZAI_LOCAL_EXTRAS_DIR." + fi + + # Copia ferramentas do bin/tools para /opt/fazai/tools + if [ -d "bin/tools" ]; then + log "INFO" "Copiando ferramentas do bin/tools..." + if ! copy_with_verification "bin/tools/github-setup.sh" "/opt/fazai/tools/" "GitHub Setup Script"; then + copy_errors=$((copy_errors+1)) + fi + if ! copy_with_verification "bin/tools/sync-changes.sh" "/opt/fazai/tools/" "Sync Changes Script"; then + copy_errors=$((copy_errors+1)) + fi + if ! copy_with_verification "bin/tools/sync-keys.sh" "/opt/fazai/tools/" "Sync Keys Script"; then + copy_errors=$((copy_errors+1)) + fi + if ! copy_with_verification "bin/tools/system-check.sh" "/opt/fazai/tools/" "System Check Script"; then + copy_errors=$((copy_errors+1)) + fi + if ! copy_with_verification "bin/tools/test-all-tools.sh" "/opt/fazai/tools/" "Test All Tools Script"; then + copy_errors=$((copy_errors+1)) + fi + if ! copy_with_verification "bin/tools/version-bump.sh" "/opt/fazai/tools/" "Version Bump Script"; then + copy_errors=$((copy_errors+1)) + fi + if ! copy_with_verification "bin/tools/install-llamacpp.sh" "/opt/fazai/tools/" "LLaMA Install Script"; then + copy_errors=$((copy_errors+1)) + fi + + # Torna os scripts executáveis + chmod +x /opt/fazai/tools/*.sh 2>/dev/null + log "SUCCESS" "Ferramentas copiadas e tornadas executáveis" + fi + + # Copia módulos nativos se existirem + if [ -f "opt/fazai/mods/system_mod.so" ]; then + if ! copy_with_verification "opt/fazai/mods/system_mod.so" "/opt/fazai/mods/" "Módulo nativo system_mod"; then + copy_errors=$((copy_errors+1)) + else + log "SUCCESS" "Módulo nativo copiado" + fi + fi + + # Compila módulo system_mod.c se existir + if [ -f "opt/fazai/lib/mods/system_mod.c" ]; then + log "INFO" "Compilando módulo system_mod.c..." + mkdir -p /opt/fazai/lib/mods/ + cp -r opt/fazai/lib/mods/* /opt/fazai/lib/mods/ 2>/dev/null || true + + cd /opt/fazai/lib/mods/ + if [ -f "compile_system_mod.sh" ]; then + chmod +x compile_system_mod.sh + # Verifica dependências primeiro (sem instalar) + ./compile_system_mod.sh --check || log "WARNING" "Pendências detectadas; tentando auto-instalação e compilação." + # Compila (com auto-instalação de pacotes quando necessário) + ./compile_system_mod.sh || log "WARNING" "Falha na compilação do system_mod.c" + # Publica .so + mkdir -p /opt/fazai/mods + cp -f /opt/fazai/lib/mods/*.so /opt/fazai/mods/ 2>/dev/null || true + if ls /opt/fazai/mods/*.so >/dev/null 2>&1; then + log "SUCCESS" "Módulos nativos disponibilizados em /opt/fazai/mods" + else + log "WARNING" "Nenhum módulo .so encontrado após compilação" + fi + else + # Compilação manual se o script não existir + log "WARNING" "Script de compilação não encontrado, tentando compilação manual..." + gcc -shared -fPIC -o system_mod.so system_mod.c -lclamav -lcurl -ljson-c -lpthread 2>/dev/null || log "WARNING" "Falha na compilação do system_mod.c (dependências podem estar faltando)" + mkdir -p /opt/fazai/mods + cp -f /opt/fazai/lib/mods/system_mod.so /opt/fazai/mods/ 2>/dev/null || true + fi + cd - > /dev/null + fi + + + + # Copia novas tools + for t in \ + "opt/fazai/tools/auto_tool.js" \ + "opt/fazai/tools/net_qos_monitor.js" \ + "opt/fazai/tools/agent_supervisor.js" \ + "opt/fazai/tools/qdrant_setup.js" \ + "opt/fazai/tools/snmp_monitor.js" \ + "opt/fazai/tools/modsecurity_setup.js" \ + "opt/fazai/tools/suricata_setup.js" \ + "opt/fazai/tools/crowdsec_setup.js" \ + "opt/fazai/tools/monit_setup.js" \ + "opt/fazai/tools/rag_ingest.js" \ + "opt/fazai/tools/download_gemma2.sh" \ + "opt/fazai/tools/install_python_deps.sh" \ + "opt/fazai/tools/alerts.js" \ + "opt/fazai/tools/blacklist_check.js" \ + "opt/fazai/tools/email_relay.js" \ + "opt/fazai/tools/geoip_lookup.js" \ + "opt/fazai/tools/http_fetch.js" \ + "opt/fazai/tools/ports_monitor.js" \ + "opt/fazai/tools/system_info.js" \ + "opt/fazai/tools/test_complex_tasks.js" \ + "opt/fazai/tools/weather.js" \ + "opt/fazai/tools/crowdsec.js" \ + "opt/fazai/tools/modsecurity.js" \ + "opt/fazai/tools/spamexperts.js" \ + "opt/fazai/tools/web_search.js" \ + "opt/fazai/tools/cloudflare.js"; do + if [ -f "$t" ]; then + if ! copy_with_verification "$t" "/opt/fazai/tools/" "Tool $(basename $t)"; then + copy_errors=$((copy_errors+1)) + else + chmod 755 "/opt/fazai/tools/$(basename $t)" || true + fi + fi + done + + # Instala dependência dialog para alguns scripts + install_dialog + + # Copia interface web front-end + if [ -f "opt/fazai/tools/fazai_web_frontend.html" ]; then + if ! copy_with_verification "opt/fazai/tools/fazai_web_frontend.html" "/opt/fazai/tools/" "Interface web"; then + copy_errors=$((copy_errors+1)) + else + chmod 644 "/opt/fazai/tools/fazai_web_frontend.html" + log "SUCCESS" "Interface web instalada" + fi + else + log "WARNING" "Interface web não encontrado, crio fallback básico..." + cat > "/opt/fazai/tools/fazai_web_frontend.html" << 'EOF' + + + + + + FazAI - Interface Web + + +

FazAI Interface Web

+

Interface básica gerada automaticamente.

+ + +EOF + log "SUCCESS" "Interface web fallback criada" + fi + if [ -f "opt/fazai/tools/fazai-tui.sh" ]; then + if ! copy_with_verification "opt/fazai/tools/fazai-tui.sh" "/opt/fazai/tools/" "Dashboard TUI completo"; then + copy_errors=$((copy_errors+1)) + else + chmod +x /opt/fazai/tools/fazai-tui.sh + ln -sf /opt/fazai/tools/fazai-tui.sh /usr/local/bin/fazai-tui + log "SUCCESS" "Dashboard TUI completo instalado em /usr/local/bin/fazai-tui" + fi + if command -v cargo >/dev/null 2>&1; then + log "INFO" "Compilando TUI em Rust..." + if cargo build --release --manifest-path=tui/Cargo.toml >/tmp/fazai_tui_build.log 2>&1; then + cp tui/target/release/fazai-tui /opt/fazai/tools/fazai-tui-rs + ln -sf /opt/fazai/tools/fazai-tui-rs /usr/local/bin/fazai-tui + log "SUCCESS" "TUI Rust instalado em /usr/local/bin/fazai-tui" + else + log "WARNING" "Falha ao compilar TUI Rust, utilizando script bash" + fi + fi + else + log "WARNING" "Dashboard TUI não encontrado, criando versão básica..." + cat > "/opt/fazai/tools/fazai-tui.sh" << 'EOF' +#!/bin/bash +# FazAI Dashboard TUI - Versão Básica +echo "FazAI Dashboard TUI v2.0.0" +echo "Opções:" +echo " [l] Ver logs | [s] Status | [q] Sair" +while read -r -n1 -p "Selecione: " k; do + echo + case "$k" in + l) curl -fsS http://localhost:3120/logs | jq . || true ;; + s) curl -fsS http://localhost:3120/status | jq . || true ;; + q) echo "Saindo..."; exit 0 ;; + *) echo "Opção inválida" ;; + esac +done +EOF + chmod +x "/opt/fazai/tools/fazai-tui.sh" + ln -sf /opt/fazai/tools/fazai-tui.sh /usr/local/bin/fazai-tui + log "SUCCESS" "Dashboard TUI básico instalado em /usr/local/bin/fazai-tui" + + log "WARNING" "Interface web não encontrada, criando versão básica..." + # Cria uma versão básica se não existir + cat > "/opt/fazai/tools/fazai_web_frontend.html" << 'EOF' + + + + + + FazAI - Interface Web + + + +
+

FazAI - Interface Web

+
+

Gerenciamento de Logs

+ + + +
+
+

Status do Sistema

+ +
+
+
+ + + +EOF + log "SUCCESS" "Interface web básica criada" + fi + + # Copia script de lançamento da interface web + if [ -f "opt/fazai/tools/fazai_web.sh" ]; then + if ! copy_with_verification "opt/fazai/tools/fazai_web.sh" "/opt/fazai/tools/" "Script de lançamento web"; then + copy_errors=$((copy_errors+1)) + else + chmod +x "/opt/fazai/tools/fazai_web.sh" + log "SUCCESS" "Script de lançamento web instalado" + fi + else + log "WARNING" "Script de lançamento web não encontrado, criando versão básica..." + cat > "/opt/fazai/tools/fazai_web.sh" << 'EOF' + #!/bin/bash + # FazAI Web Frontend Launcher + # Caminho: /opt/fazai/tools/fazai_web.sh + + FRONTEND_FILE="/opt/fazai/tools/fazai_web_frontend.html" + + if [ ! -f "$FRONTEND_FILE" ]; then + echo "Erro: Interface web não encontrada: $FRONTEND_FILE" + exit 1 + fi + + echo "Iniciando interface web do FazAI..." + + # Detecta o sistema e abre o navegador + if [[ "$OSTYPE" == "linux-gnu"* ]]; then + if command -v xdg-open > /dev/null; then + xdg-open "$FRONTEND_FILE" + elif command -v firefox > /dev/null; then + firefox "$FRONTEND_FILE" + else + echo "Abra manualmente: $FRONTEND_FILE" + fi + elif [[ "$OSTYPE" == "darwin"* ]]; then + open "$FRONTEND_FILE" + elif [[ "$OSTYPE" == "cygwin" || "$OSTYPE" == "msys" ]]; then + start "$FRONTEND_FILE" + else + echo "Abra manualmente: $FRONTEND_FILE" + fi + + echo "Interface web disponível em: file://$FRONTEND_FILE" +EOF + chmod +x "/opt/fazai/tools/fazai_web.sh" + log "SUCCESS" "Script de lançamento web básico criado" + fi + + # Copia gerador de visualização HTML + if [ -f "opt/fazai/tools/fazai_html_v1.sh" ]; then + if ! copy_with_verification "opt/fazai/tools/fazai_html_v1.sh" "/opt/fazai/tools/" "Gerador HTML"; then + copy_errors=$((copy_errors+1)) + else + chmod +x "/opt/fazai/tools/fazai_html_v1.sh" + ln -sf /opt/fazai/tools/fazai_html_v1.sh /usr/local/bin/fazai-html + log "SUCCESS" "Gerador HTML instalado em /usr/local/bin/fazai-html" + fi + fi + + if [ "$copy_errors" -ne 0 ]; then + log "ERROR" "$copy_errors falha(s) ao copiar arquivos. Veja $LOG_FILE para detalhes." + return 1 + fi + + log "SUCCESS" "Arquivos copiados com sucesso." + } + + # Função para importar configurações de .env + import_env_config() { + log "INFO" "Verificando configurações de ambiente..." + + # Locais possíveis do arquivo .env + local env_locations=( + "/root/.env" + "$HOME/.env" + "./.env" + ".env.example" + ) + + local env_file="" + + # Procura o primeiro arquivo .env disponível + for location in "${env_locations[@]}"; do + if [ -f "$location" ]; then + env_file="$location" + log "INFO" "Arquivo .env encontrado em $env_file" + break + fi + done + + if [ -n "$env_file" ]; then + log "INFO" "Arquivo .env encontrado. Importando configurações..." + + # Extrai chaves de API + local api_keys=( + "OPENAI_API_KEY" + "ANTHROPIC_API_KEY" + "GOOGLE_API_KEY" + "AZURE_API_KEY" + ) + + local fazai_conf="/etc/fazai/fazai.conf" + local changes_made=false + + for key in "${api_keys[@]}"; do + local value=$(grep "^$key=" "$env_file" 2>/dev/null | cut -d'=' -f2 | tr -d '"' | tr -d "'") + if [ -n "$value" ]; then + local config_key=$(echo "$key" | tr '[:upper:]' '[:lower:]') + + # Verifica se a chave já existe no arquivo de configuração + if grep -q "^$config_key" "$fazai_conf"; then + # Substitui o valor existente + sed -i "s|^$config_key.*|$config_key = $value|" "$fazai_conf" + else + # Adiciona nova entrada na seção de APIs + if grep -q "^\[apis\]" "$fazai_conf"; then + sed -i "/^\[apis\]/a $config_key = $value" "$fazai_conf" + else + # Se não houver seção de APIs, adiciona ao final do arquivo + echo -e "\n[apis]\n$config_key = $value" >> "$fazai_conf" + fi + fi + + log "SUCCESS" "Chave $key importada com sucesso." + changes_made=true + fi + done + + if [ "$changes_made" = true ]; then + log "SUCCESS" "Configurações importadas para $fazai_conf" + else + log "WARNING" "Nenhuma configuração relevante encontrada em $env_file" + fi + else + log "INFO" "Nenhum arquivo .env encontrado nas localizações padrão." + fi + } + + # Função para configurar o serviço systemd +configure_systemd() { + log "INFO" "Configurando serviço systemd..." + + local service_file="/etc/systemd/system/fazai.service" + + # Gera um arquivo de serviço melhorado + cat > "$service_file" << EOF + [Unit] + Description=FazAI Service + After=network.target fazai-gemma-worker.service fazai-docler.service fazai-qdrant.service + Wants=fazai-gemma-worker.service fazai-docler.service + Wants=fazai-qdrant.service + StartLimitIntervalSec=0 + + [Service] + Type=simple + Restart=always + RestartSec=1 + User=root + ExecStart=/usr/bin/node /opt/fazai/lib/main.js + WorkingDirectory=/opt/fazai + Environment=NODE_ENV=production + StandardOutput=append:/var/log/fazai/stdout.log + StandardError=append:/var/log/fazai/stderr.log + + # Limites de recursos + LimitNOFILE=65535 + LimitMEMLOCK=512M + + [Install] + WantedBy=multi-user.target +EOF + + chmod 644 "$service_file" + log "SUCCESS" "Arquivo de serviço systemd criado em $service_file" + + systemctl daemon-reload + systemctl enable fazai + log "SUCCESS" "Serviço systemd habilitado." + + # Instala serviço do Gemma Worker se binário existir + if [ -x "/opt/fazai/bin/fazai-gemma-worker" ]; then + log "INFO" "Configurando serviço fazai-gemma-worker..." + cat > "/etc/systemd/system/fazai-gemma-worker.service" << EOF +[Unit] +Description=FazAI Gemma Worker v2.0 +After=network.target fazai-qdrant.service +Wants=fazai-qdrant.service +PartOf=fazai.service + +[Service] +Type=simple +User=root +WorkingDirectory=/opt/fazai +EnvironmentFile=-/etc/fazai/env +RuntimeDirectory=fazai +RuntimeDirectoryMode=0777 +UMask=0000 +ExecStartPre=/usr/bin/install -d -m 0777 -o root -g root /run/fazai +ExecStartPre=/bin/rm -f /run/fazai/gemma.sock +ExecStart=/opt/fazai/bin/fazai_gemma_worker.py +ExecStopPost=/bin/rm -f /run/fazai/gemma.sock +Restart=always +RestartSec=5 +StandardOutput=journal +StandardError=journal + +[Install] +WantedBy=multi-user.target +EOF + chmod 644 "/etc/systemd/system/fazai-gemma-worker.service" + systemctl daemon-reload + systemctl enable fazai-gemma-worker || true + log "SUCCESS" "Serviço fazai-gemma-worker preparado." + else + log "WARNING" "Binário fazai-gemma-worker não encontrado; serviço do worker não será criado." + fi + + # Serviço DOCLER Web (portas 3220/3221 para evitar conflito com daemon 3120) + if [ -f "/opt/fazai/web/docler-server.js" ]; then + log "INFO" "Configurando serviço fazai-docler..." + cat > "/etc/systemd/system/fazai-docler.service" << 'EOF' +[Unit] +Description=FazAI DOCLER Web Server +After=network.target +PartOf=fazai.service + +[Service] +Type=simple +User=fazai-web +Group=fazai-web +Environment=DOCLER_PORT=3220 +Environment=DOCLER_ADMIN_PORT=3221 +Environment=DOCLER_HOST=0.0.0.0 +WorkingDirectory=/opt/fazai/web +ExecStart=/usr/bin/node /opt/fazai/web/docler-server.js +Restart=always +RestartSec=5 + +[Install] +WantedBy=multi-user.target +EOF + chmod 644 "/etc/systemd/system/fazai-docler.service" + systemctl daemon-reload + systemctl enable fazai-docler || true + # Tenta iniciar se dependências foram instaladas + systemctl start fazai-docler || true + log "SUCCESS" "Serviço fazai-docler preparado (portas 3220/3221)." + else + log "WARNING" "docler-server.js não encontrado; serviço DOCLER não será criado." + fi + + # Serviço Qdrant Vector Database + log "INFO" "Configurando serviço fazai-qdrant..." + if command -v docker >/dev/null 2>&1 && systemctl is-active docker >/dev/null 2>&1; then + # Usar Docker se disponível + cat > "/etc/systemd/system/fazai-qdrant.service" << 'EOF' +[Unit] +Description=FazAI Qdrant Vector Database (Docker) +After=network.target docker.service +Requires=docker.service +PartOf=fazai.service + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStartPre=/usr/bin/docker pull qdrant/qdrant:latest +ExecStart=/usr/bin/docker run -d \ + --name fazai-qdrant \ + --restart unless-stopped \ + -p 6333:6333 \ + -p 6334:6334 \ + -v /var/lib/qdrant:/qdrant/storage \ + -v /opt/fazai/web/static:/opt/qdrant/web/static \ + -e QDRANT__SERVICE__HTTP_PORT=6333 \ + -e QDRANT__SERVICE__GRPC_PORT=6334 \ + -e QDRANT__SERVICE__HOST=0.0.0.0 \ + -e QDRANT__WEB_UI__ENABLED=true \ + -e QDRANT__SERVICE__ENABLE_CORS=true \ + qdrant/qdrant:latest +ExecStop=/usr/bin/docker stop fazai-qdrant +ExecStopPost=/usr/bin/docker rm fazai-qdrant + +[Install] +WantedBy=multi-user.target +EOF + elif [ -f "/opt/fazai/bin/qdrant" ]; then + # Usar binário nativo se disponível + cat > "/etc/systemd/system/fazai-qdrant.service" << 'EOF' +[Unit] +Description=FazAI Qdrant Vector Database +After=network.target +PartOf=fazai.service + +[Service] +Type=simple +User=fazai +Group=fazai +WorkingDirectory=/var/lib/qdrant +ExecStart=/opt/fazai/bin/qdrant --config-path /etc/fazai/qdrant.yaml +Restart=always +RestartSec=5 +Environment=RUST_LOG=info + +[Install] +WantedBy=multi-user.target +EOF + fi + + chmod 644 "/etc/systemd/system/fazai-qdrant.service" 2>/dev/null || true + systemctl daemon-reload + systemctl enable fazai-qdrant || true + systemctl start fazai-qdrant || true + log "SUCCESS" "Serviço fazai-qdrant preparado (porta 6333)." + + + + # Instalar GPT-Web2Shell se local-extras existe + if [ -d "local-extras/gpt-web2shell" ]; then + log "INFO" "Instalando GPT-Web2Shell..." + mkdir -p /home/${SUDO_USER}/fazai/local-extras/gpt-web2shell + cp -r local-extras/gpt-web2shell/* /home/${SUDO_USER}/fazai/local-extras/gpt-web2shell/ + chown -R ${SUDO_USER}:${SUDO_USER} /home/${SUDO_USER}/fazai/local-extras/ 2>/dev/null || true + chmod +x /home/${SUDO_USER}/fazai/local-extras/gpt-web2shell/bin/gpt-web2shell 2>/dev/null || true + chmod +x /opt/fazai/tools/gpt-web2shell.js 2>/dev/null || true + log "SUCCESS" "GPT-Web2Shell instalado para transcendência CLI." + fi + + # Detecta runtime de contêiner (Docker/Podman) + local CONTAINER="" + if command -v docker >/dev/null 2>&1; then CONTAINER="docker"; fi + if [ -z "$CONTAINER" ] && command -v podman >/dev/null 2>&1; then CONTAINER="podman"; fi + + # Serviço Qdrant (via Docker/Podman) se disponível + if [ -n "$CONTAINER" ]; then + log "INFO" "Configurando serviço Qdrant ($CONTAINER)..." + mkdir -p /var/lib/fazai/qdrant + cat > "/etc/systemd/system/fazai-qdrant.service" << 'EOF' +[Unit] +Description=FazAI Qdrant Vector DB (Docker) +After=network-online.target +PartOf=fazai.service + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStartPre=-/usr/bin/CONTAINER_BIN rm -f fazai-qdrant +ExecStart=/usr/bin/CONTAINER_BIN run -d --name fazai-qdrant -p 6333:6333 -v /var/lib/fazai/qdrant:/qdrant/storage qdrant/qdrant:v1.7.3 +ExecStop=/usr/bin/CONTAINER_BIN stop fazai-qdrant +TimeoutStartSec=120 +TimeoutStopSec=30 + +[Install] +WantedBy=multi-user.target +EOF + # Substitui placeholder pelo runtime + sed -i "s|CONTAINER_BIN|$CONTAINER|g" "/etc/systemd/system/fazai-qdrant.service" + chmod 644 "/etc/systemd/system/fazai-qdrant.service" + systemctl daemon-reload + systemctl enable fazai-qdrant || true + systemctl start fazai-qdrant || true + log "SUCCESS" "Serviço Qdrant preparado (porta 6333)." + + + else + log "WARNING" "Docker/Podman não encontrado; Qdrant não será instalado automaticamente. Instale um runtime de contêiner ou configure Qdrant manualmente." + fi + + # Observabilidade foi movida para repo separado (~/fazaiserverlogs) + if [ -n "$CONTAINER" ]; then + log "INFO" "Monitoring Prometheus/Grafana não é mais instalado neste host. Use o repositório fazaiserverlogs." + fi +} + +# Compila e instala o Gemma Worker (C++) se fontes estiverem presentes +build_gemma_worker() { + if [ -d "worker" ] && [ -f "worker/CMakeLists.txt" ]; then + log "INFO" "Compilando Gemma Worker (C++)..." + mkdir -p worker/build + pushd worker/build >/dev/null + if cmake .. && cmake --build . -j$(nproc) && cmake --install .; then + log "SUCCESS" "Gemma Worker compilado e instalado em /opt/fazai/bin" + else + log "WARNING" "Falha ao compilar o Gemma Worker. O agente local poderá não funcionar." + fi + popd >/dev/null + # Garante diretório de socket + mkdir -p /run/fazai + chmod 755 /run/fazai + else + log "INFO" "Fontes do Gemma Worker não encontradas; pulando compilação." + fi +} + +# Instala Gemma one-shot e pesos padrão (máquinas pequenas) +bootstrap_gemma() { + if [ -x "/opt/fazai/bin/gemma_oneshot" ] && [ -f "/opt/fazai/models/gemma/2.0-2b-it-sfp.sbs" ]; then + log "INFO" "Gemma (oneshot + pesos) já presente." + return 0 + fi + if [ -x "/opt/fazai/tools/gemma_bootstrap.sh" ]; then + log "INFO" "Executando gemma_bootstrap.sh (download/instalação do modelo)." + bash /opt/fazai/tools/gemma_bootstrap.sh || log "WARNING" "Falha no gemma_bootstrap.sh" + else + log "WARNING" "gemma_bootstrap.sh não encontrado." + fi +} + + # Função para instalar dependências do Node.js com retry + install_node_dependencies() { + log "INFO" "Instalando dependências do Node.js..." + + # Cria package.json se não existir + if [ ! -f "package.json" ]; then + log "INFO" "Criando package.json..." + cat > "package.json" << 'EOF' + { + "name": "fazai", + "version": "2.0.0", + "description": "FazAI - Orquestrador Inteligente de Automação", + "main": "main.js", + "dependencies": { + "axios": ">=0.27.2", + "express": ">=4.18.1", + "winston": ">=3.8.1", + + "chalk": ">=4.1.2", + "figlet": ">=1.5.2", + "inquirer": ">=8.2.4" + } + } +EOF + fi + + # Instala no diretório atual primeiro + log "INFO" "Instalando dependências no diretório atual..." + if ! npm install --no-audit --no-progress; then + log "WARNING" "Falha na instalação inicial de dependências. Tentando método alternativo..." + + # Tenta instalar pacotes críticos individualmente + for module in "${DEPENDENCY_MODULES[@]}"; do + log "INFO" "Instalando módulo: $module" + npm install "$module" --no-audit --no-progress || log "WARNING" "Falha ao instalar $module" + done + fi + + # Agora instala em /opt/fazai + log "INFO" "Instalando dependências em /opt/fazai..." + cp package.json /opt/fazai/ + cd /opt/fazai + + if ! npm install --no-audit --no-progress; then + log "WARNING" "Falha ao instalar dependências em /opt/fazai. Tentando método alternativo..." + + # Tenta instalar pacotes críticos individualmente + for module in "${DEPENDENCY_MODULES[@]}"; do + log "INFO" "Instalando módulo em /opt/fazai: $module" + npm install "$module" --no-audit --no-progress || log "WARNING" "Falha ao instalar $module" + done + fi + + cd - > /dev/null + + # Verifica se os módulos essenciais foram instalados + if npm list express winston >> "$LOG_FILE" 2>&1; then + log "SUCCESS" "Módulos express e winston instalados corretamente." + else + log "WARNING" "Módulos express ou winston ausentes. Possível problema de conexão. Execute 'npm install' manualmente." + fi + + log "SUCCESS" "Dependências do Node.js instaladas." + } + + # Função para compilar módulos nativos + compile_native_modules() { + log "INFO" "Verificando módulos nativos..." + + # Cria um módulo nativo básico se não existir + if [ ! -d "/opt/fazai/mods" ]; then + mkdir -p "/opt/fazai/mods" + fi + + cd /opt/fazai/mods + + if [ ! -f "system_mod.c" ]; then + log "INFO" "Criando módulo nativo básico..." + cat > "system_mod.c" << 'EOF' + #include + #include + + // Função básica para teste do módulo nativo + int fazai_test() { + return 42; + } +EOF + fi + + if [ -f "system_mod.c" ]; then + log "DEBUG" "Compilando system_mod.c..." + if gcc -shared -fPIC -o system_mod.so system_mod.c; then + log "SUCCESS" "Módulos nativos compilados com sucesso." + else + log "WARNING" "Falha ao compilar módulos nativos. Continuando sem eles..." + fi + else + log "INFO" "Nenhum módulo nativo para compilar." + fi + + cd - > /dev/null + } + + # Função opcional para instalar o llama.cpp + install_llamacpp() { + if [ "$WITH_LLAMA" != true ]; then + log "INFO" "Instalação do llama.cpp ignorada (--with-llama)" + return 0 + fi + + log "INFO" "Instalando llama.cpp..." + local script_dir="$(cd "$(dirname "$0")" && pwd)" + if bash "$script_dir/bin/tools/install-llamacpp.sh"; then + log "SUCCESS" "llama.cpp instalado" + return 0 + else + log "ERROR" "Falha ao instalar llama.cpp" + return 1 + fi + } + + # Função para instalar interface TUI + + # Função para configurar permissões de segurança + configure_security() { + log "INFO" "Configurando permissões de segurança..." + + # Cria grupo fazai se não existir + if ! getent group fazai > /dev/null 2>&1; then + groupadd -r fazai + log "SUCCESS" "Grupo 'fazai' criado" + fi + + # Cria usuário fazai se não existir + if ! getent passwd fazai > /dev/null 2>&1; then + useradd -r -g fazai -s /bin/false -d /opt/fazai fazai + log "SUCCESS" "Usuário 'fazai' criado" + fi + + # Define permissões dos diretórios + chown -R fazai:fazai /opt/fazai + chown -R fazai:fazai /var/log/fazai + chown -R fazai:fazai /var/lib/fazai + + # Permissões específicas + chmod 750 /opt/fazai + chmod 755 /opt/fazai/bin/fazai + # Conf: dono fazai, grupo root, 640 + chown fazai:root /etc/fazai/fazai.conf 2>/dev/null || true + chmod 640 /etc/fazai/fazai.conf + chmod 755 /opt/fazai/tools/fazai-config.js + + # Configura sudoers para permitir comandos específicos do fazai + if [ ! -f /etc/sudoers.d/fazai ]; then + cat > /etc/sudoers.d/fazai << 'EOF' + # FazAI sudoers configuration + %fazai ALL=(ALL) NOPASSWD: /bin/systemctl start fazai + %fazai ALL=(ALL) NOPASSWD: /bin/systemctl stop fazai + %fazai ALL=(ALL) NOPASSWD: /bin/systemctl restart fazai + %fazai ALL=(ALL) NOPASSWD: /bin/systemctl status fazai + %fazai ALL=(ALL) NOPASSWD: /usr/bin/apt-get update + %fazai ALL=(ALL) NOPASSWD: /usr/bin/apt-get install * + %fazai ALL=(ALL) NOPASSWD: /usr/sbin/service * * +EOF + chmod 440 /etc/sudoers.d/fazai + log "SUCCESS" "Configuração sudoers criada" + fi + + log "SUCCESS" "Permissões de segurança configuradas" + } + + # Função para criar scripts auxiliares + create_helper_scripts() { + log "INFO" "Criando scripts auxiliares..." + + # Script de uninstall + cat > /opt/fazai/bin/uninstall.sh << 'EOF' + #!/bin/bash + # FazAI Uninstall Script + + echo "Desinstalando FazAI..." + + # Para o serviço + systemctl stop fazai 2>/dev/null + systemctl disable fazai 2>/dev/null + + # Remove arquivos de serviço + rm -f /etc/systemd/system/fazai.service + systemctl daemon-reload + + # Remove links simbólicos + rm -f /usr/local/bin/fazai + rm -f /usr/local/bin/fazai-config + + # Remove diretórios (com confirmação) + read -p "Remover todos os dados do FazAI? (logs, configurações, etc.) [s/N]: " -n 1 -r + echo + if [[ $REPLY =~ ^[Ss]$ ]]; then + rm -rf /opt/fazai + rm -rf /etc/fazai + rm -rf /var/log/fazai + rm -rf /var/lib/fazai + echo "Todos os dados removidos." + else + echo "Dados preservados em /etc/fazai, /var/log/fazai e /var/lib/fazai" + fi + + # Remove usuário e grupo + userdel fazai 2>/dev/null + groupdel fazai 2>/dev/null + + # Remove sudoers + rm -f /etc/sudoers.d/fazai + + echo "FazAI desinstalado com sucesso!" +EOF + + chmod +x /opt/fazai/bin/uninstall.sh + ln -sf /opt/fazai/bin/uninstall.sh /usr/local/bin/fazai-uninstall + + # Script de backup + cat > /opt/fazai/bin/backup.sh << 'EOF' + #!/bin/bash + # FazAI Backup Script + + BACKUP_DIR="/tmp/fazai-backup-$(date +%Y%m%d-%H%M%S)" + mkdir -p "$BACKUP_DIR" + + echo "Criando backup em $BACKUP_DIR..." + + # Backup de configurações + cp -r /etc/fazai "$BACKUP_DIR/" + cp -r /var/lib/fazai "$BACKUP_DIR/" + + # Backup de logs (últimos 7 dias) + find /var/log/fazai -name "*.log" -mtime -7 -exec cp {} "$BACKUP_DIR/" \; + + # Compacta o backup + cd /tmp + tar -czf "fazai-backup-$(date +%Y%m%d-%H%M%S).tar.gz" "$(basename $BACKUP_DIR)" + rm -rf "$BACKUP_DIR" + + echo "Backup criado: /tmp/fazai-backup-$(date +%Y%m%d-%H%M%S).tar.gz" +EOF + + chmod +x /opt/fazai/bin/backup.sh + ln -sf /opt/fazai/bin/backup.sh /usr/local/bin/fazai-backup + + log "SUCCESS" "Scripts auxiliares criados" + } + + # Compila o worker Gemma usando o script interno + build_gemma_worker() { + log "INFO" "Compilando FazAI Gemma Worker" + if [ -d "worker" ]; then + pushd worker >/dev/null + ./build.sh || { log "ERROR" "Falha ao compilar worker"; popd >/dev/null; return 1; } + popd >/dev/null + log "SUCCESS" "Worker compilado e instalado em /opt/fazai/bin" + return 0 + else + log "ERROR" "Diretório worker não encontrado" + return 1 + fi + } + + # Função para configurar logrotate + configure_logrotate() { + log "INFO" "Configurando rotação de logs..." + + cat > /etc/logrotate.d/fazai << 'EOF' + /var/log/fazai/*.log { + daily + missingok + rotate 30 + compress + delaycompress + notifempty + create 644 fazai fazai + postrotate + systemctl reload fazai > /dev/null 2>&1 || true + endscript + } +EOF + + log "SUCCESS" "Configuração de logrotate criada" + } + + # Função para validar a instalação + validate_installation() { + log "INFO" "Validando instalação..." + + local validation_errors=0 + + # Verifica arquivos essenciais + local essential_files=( + "/opt/fazai/lib/main.js" + "/opt/fazai/bin/fazai" + "/etc/fazai/fazai.conf" + "/etc/fazai/complex_tasks.conf.default" + "/etc/systemd/system/fazai.service" + "/usr/local/bin/fazai" + "/opt/fazai/tools/fazai_web_frontend.html" + "/opt/fazai/tools/fazai_web.sh" + "/opt/fazai/tools/fazai_html_v1.sh" + "/opt/fazai/tools/auto_tool.js" + "/opt/fazai/tools/net_qos_monitor.js" + "/opt/fazai/tools/agent_supervisor.js" + "/opt/fazai/tools/qdrant_setup.js" + "/opt/fazai/tools/snmp_monitor.js" + "/opt/fazai/tools/modsecurity_setup.js" + "/opt/fazai/tools/suricata_setup.js" + "/opt/fazai/tools/crowdsec_setup.js" + "/opt/fazai/tools/monit_setup.js" + ) + + for file in "${essential_files[@]}"; do + if [ ! -f "$file" ]; then + log "ERROR" "Arquivo essencial não encontrado: $file" + validation_errors=$((validation_errors + 1)) + else + log "DEBUG" "Arquivo validado: $file" + fi + done + + # Verifica diretórios + local essential_dirs=( + "/opt/fazai" + "/etc/fazai" + "/var/log/fazai" + "/var/lib/fazai" + ) + + for dir in "${essential_dirs[@]}"; do + if [ ! -d "$dir" ]; then + log "ERROR" "Diretório essencial não encontrado: $dir" + validation_errors=$((validation_errors + 1)) + else + log "DEBUG" "Diretório validado: $dir" + fi + done + + # Verifica comandos + if ! command -v fazai &> /dev/null; then + log "ERROR" "Comando 'fazai' não está disponível" + validation_errors=$((validation_errors + 1)) + fi + + # Verifica serviço systemd + if ! systemctl is-enabled fazai &> /dev/null; then + log "WARNING" "Serviço fazai não está habilitado" + fi + + # Verifica dependências Node.js críticas + cd /opt/fazai + local critical_modules=("express" "winston") + for module in "${critical_modules[@]}"; do + if ! npm list "$module" &> /dev/null; then + log "WARNING" "Módulo Node.js crítico não encontrado: $module" + fi + done + + if [ $validation_errors -eq 0 ]; then + log "SUCCESS" "Validação da instalação concluída com sucesso!" + return 0 + else + log "ERROR" "Validação falhou com $validation_errors erro(s)" + return 1 + fi + } + + # Função para executar testes pós-instalação + run_post_install_tests() { + log "INFO" "Executando testes pós-instalação..." + + # Teste 1: Verifica se o CLI responde + log "DEBUG" "Testando CLI..." + if fazai --version &> /dev/null; then + log "SUCCESS" "Teste CLI: OK" + else + log "WARNING" "Teste CLI: Falhou" + fi + + # Teste 2: Verifica se o serviço pode ser iniciado + log "DEBUG" "Testando serviço systemd..." + if systemctl start fazai && sleep 2 && systemctl is-active fazai &> /dev/null; then + log "SUCCESS" "Teste serviço: OK" + systemctl stop fazai + else + log "WARNING" "Teste serviço: Falhou" + fi + + # Teste 3: Verifica permissões + log "DEBUG" "Testando permissões..." + if [ -r /etc/fazai/fazai.conf ] && [ -x /opt/fazai/bin/fazai ]; then + log "SUCCESS" "Teste permissões: OK" + else + log "WARNING" "Teste permissões: Falhou" + fi + + log "SUCCESS" "Testes pós-instalação concluídos" + } + + # Função para mostrar informações finais + show_installation_summary() { + log "INFO" "====== Resumo da Instalação ======" + + echo -e "\n${GREEN}✓ FazAI v$VERSION instalado com sucesso!${NC}\n" + + echo -e "${BLUE}Localização dos arquivos:${NC}" + echo " • Binários: /opt/fazai" + echo " • Configuração: /etc/fazai/fazai.conf" + echo " • Configuração de tarefas complexas: /etc/fazai/complex_tasks.conf.default" + echo " • Logs: /var/log/fazai" + echo " • Dados: /var/lib/fazai" + echo "" + + echo -e "${BLUE}Comandos disponíveis:${NC}" + echo " • fazai --help - Ajuda do sistema" + echo " • fazai --version - Versão instalada" + echo " • fazai --status - Status do daemon" + echo " • fazai web - Interface web com gerenciamento de logs" + + echo " • fazai logs [n] - Ver últimas n entradas de log" + echo " • fazai limpar-logs - Limpar logs (com backup)" + + echo " • fazai-backup - Criar backup" + echo " • fazai-uninstall - Desinstalar" + echo "" + + echo -e "${BLUE}Gerenciamento do serviço:${NC}" + echo " • systemctl start fazai - Iniciar" + echo " • systemctl stop fazai - Parar" + echo " • systemctl restart fazai - Reiniciar" + echo " • systemctl status fazai - Ver status" + echo "" + + echo -e "${YELLOW}Próximos passos:${NC}" + echo " 1. Configure suas API keys editando /etc/fazai/fazai.conf" + echo " 2. Inicie o serviço: systemctl start fazai" + echo " 3. Teste o sistema: fazai --status" + echo "" + + echo -e "${PURPLE}Para suporte e documentação:${NC}" + echo " • GitHub: https://github.com/RLuf/FazAI" + echo " • Logs: /var/log/fazai_install.log" + echo "" + + # Salva estado final + save_install_state "installation_complete" "success" + + log "SUCCESS" "====== Instalação Finalizada ======" + } + + # Função principal de instalação + main_install() { + log "INFO" "Iniciando instalação do FazAI v$VERSION" + + # Carrega estado anterior se existir + load_install_state + + # Executa etapas de instalação + local install_steps=( + "setup_logging:Configurando sistema de logs" + "check_root:Verificando permissões" + "check_system:Verificando sistema operacional" + "convert_files_to_unix:Convertendo arquivos para formato Linux" + "install_nodejs:Instalando Node.js" + "install_npm:Verificando npm" + "install_python:Instalando Python 3" + "install_gcc:Instalando ferramentas de compilação" + "ensure_container_runtime:Instalando runtime de contêiner (Docker)" + "create_directories:Criando estrutura de diretórios" + "build_gemma_worker:Compilando Gemma Worker" + "bootstrap_gemma:Instalando Gemma one-shot e pesos padrão" + "copy_files:Copiando arquivos" + "import_env_config:Importando configurações" + "configure_systemd:Configurando serviço systemd" + "install_node_dependencies:Instalando dependências Node.js" + "compile_native_modules:Compilando módulos nativos" + ) + + if [ "$WITH_LLAMA" = true ]; then + install_steps+=("install_llamacpp:Instalando llama.cpp") + fi + + install_steps+=( + + "configure_security:Configurando segurança" + "create_helper_scripts:Criando scripts auxiliares" + "configure_logrotate:Configurando rotação de logs" + "install_bash_completion:Instalando autocompletar" + ) + + local total_steps=${#install_steps[@]} + local current_step=0 + + for step_info in "${install_steps[@]}"; do + local step_function=$(echo "$step_info" | cut -d: -f1) + local step_description=$(echo "$step_info" | cut -d: -f2) + + current_step=$((current_step + 1)) + + # Verifica se já foi executado + if [ "${INSTALL_STATE[$step_function]}" = "completed" ]; then + log "INFO" "[$current_step/$total_steps] $step_description (já concluído)" + continue + fi + + log "INFO" "[$current_step/$total_steps] $step_description" + + # Executa a função + if $step_function; then + save_install_state "$step_function" "completed" + log "SUCCESS" "$step_description - Concluído" + else + log "ERROR" "$step_description - Falhou" + save_install_state "$step_function" "failed" + + if [ "$step_function" = "copy_files" ]; then + log "ERROR" "Falha ao copiar arquivos. Instalação interrompida. Verifique $LOG_FILE para detalhes." + ai_help "Falha ao copiar arquivos durante a instalação do FazAI" + exit 1 + fi + + # Consulta ajuda da IA e pergunta se deve continuar + ai_help "Erro na etapa '$step_description'" + read -p "Erro na etapa '$step_description'. Continuar mesmo assim? (s/N): " -n 1 -r + echo + if [[ ! $REPLY =~ ^[Ss]$ ]]; then + log "ERROR" "Instalação interrompida pelo usuário" + exit 1 + fi + fi + done + + # Validação e testes finais + log "INFO" "Executando validação final..." + if validate_installation; then + run_post_install_tests + show_installation_summary + + # Inicia o serviço se tudo estiver OK + if systemctl start fazai; then + log "SUCCESS" "Serviço FazAI iniciado com sucesso!" + # Health-check com autorreparo + health_check_repair + # Resumo da engine/módulo nativo, se o verificador existir + if [ -x "scripts/verify-engine.sh" ]; then + log "INFO" "Resumo de verificação pós-instalação:" + bash scripts/verify-engine.sh || true + fi + else + log "WARNING" "Falha ao iniciar o serviço. Inicie manualmente: systemctl start fazai" + fi + else + log "ERROR" "Validação da instalação falhou. Verifique os logs em $LOG_FILE" + exit 1 + fi + } + + # Função para limpeza em caso de interrupção + cleanup_on_exit() { + local exit_code=$? + if [ $exit_code -ne 0 ]; then + log "WARNING" "Instalação interrompida (código: $exit_code)" + log "INFO" "Estado salvo em $INSTALL_STATE_FILE" + log "INFO" "Execute novamente o script para continuar de onde parou" + fi + } + + # Captura sinais para limpeza + trap cleanup_on_exit EXIT INT TERM + + + # Verifica argumentos de linha de comando + while [[ $# -gt 0 ]]; do + case "$1" in + --debug) + DEBUG_MODE=true + log "INFO" "Modo debug ativado" + ;; + --clean) + rm -f "$INSTALL_STATE_FILE" + log "INFO" "Estado de instalação limpo" + ;; + --with-llama) + WITH_LLAMA=true + ;; + --help) + echo "FazAI Installer v$VERSION" + echo "Uso: $0 [opções]" + echo "" + echo "Opções:" + echo " --debug Ativa modo debug com logs detalhados" + echo " --clean Remove estado de instalação anterior" + echo " --with-llama Instala o mecanismo local llama.cpp" + echo " --help Mostra esta ajuda" + exit 0 + ;; + esac + shift + done + + # Inicia instalação principal + main_install + + log "SUCCESS" "Instalação do FazAI v2.0 concluída com sucesso!" + echo -e "\n${GREEN}🎉 FazAI v2.0 - Sistema de Fluxo Inteligente está pronto!${NC}" + echo -e "${CYAN}Novos recursos disponíveis:${NC}" + echo -e " 🤖 ${YELLOW}fazai agent${NC} - Agente inteligente cognitivo" + echo -e " 📊 ${YELLOW}fazai relay${NC} - Sistema de relay SMTP inteligente" + echo -e " 🔧 ${YELLOW}Edite /etc/fazai/fazai.conf${NC} - Configurar API keys" + echo -e " 📚 ${YELLOW}fazai manual${NC} - Manual completo" + echo -e "\n${GREEN}Exemplos de uso:${NC}" + echo -e " fazai agent \"configurar servidor de email relay com antispam\"" + echo -e " fazai relay analyze" + echo -e " fazai relay configure" + +exit 0 diff --git a/install.sh.new2 b/install.sh.new2 new file mode 100644 index 0000000..5784b95 --- /dev/null +++ b/install.sh.new2 @@ -0,0 +1,2296 @@ +#!/bin/bash +set -e + +############################################################################### +# FazAI v2.0 Installer +# Sistema de Agente Inteligente Cognitivo e Persistente +############################################################################### + +# Variáveis globais +VERSION="2.0.0" +LOG_FILE="/var/log/fazai/install.log" +INSTALL_STATE_FILE="/var/log/fazai/install_state.txt" +DEBUG_MODE="${DEBUG_MODE:-false}" +WITH_LLAMA="${WITH_LLAMA:-false}" + +# Cores para output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +PURPLE='\033[0;35m' +CYAN='\033[0;36m' +NC='\033[0m' # No Color + +# Array associativo para estado da instalação +declare -A INSTALL_STATE + +# Função de logging +log() { + local level="$1" + local message="$2" + local timestamp=$(date '+%Y-%m-%d %H:%M:%S') + + # Cria diretório de log se não existir + mkdir -p "$(dirname "$LOG_FILE")" + + # Escreve log ao arquivo + echo "[$timestamp] [$level] $message" >> "$LOG_FILE" + + # Mostra no console com cores + case $level in + "INFO") + echo -e "${BLUE}[INFO]${NC} $message" + ;; + "SUCCESS") + echo -e "${GREEN}[SUCESSO]${NC} $message" + ;; + "ERROR") + echo -e "${RED}[ERRO]${NC} $message" + ;; + "WARNING") + echo -e "${YELLOW}[AVISO]${NC} $message" + ;; + "DEBUG") + if [ "$DEBUG_MODE" = true ]; then + echo -e "${PURPLE}[DEBUG]${NC} $message" + fi + ;; + esac +} + +# Verifica root +if [[ $EUID -ne 0 ]]; then + log "ERROR" "Execute como root: sudo ./install.sh" + exit 1 +fi +# Consulta ajuda da IA em caso de erro (simplificada) +ai_help() { + local prompt="$1" + log "INFO" "Erro detectado: $prompt" + log "INFO" "Verifique os logs em $LOG_FILE para mais detalhes" +} + + +# Função para salvar estado da instalação +save_install_state() { + local step=$1 + local status=$2 + INSTALL_STATE["$step"]="$status" + mkdir -p $(dirname "$INSTALL_STATE_FILE") + + # Limpa o arquivo antes de reescrever + > "$INSTALL_STATE_FILE" + for key in "${!INSTALL_STATE[@]}"; do + echo "$key=${INSTALL_STATE[$key]}" >> "$INSTALL_STATE_FILE" + done + log "DEBUG" "Estado salvo: $step = $status" +} + +# Função para carregar estado da instalação +load_install_state() { + if [ -f "$INSTALL_STATE_FILE" ]; then + while IFS='=' read -r key value; do + if [ -n "$key" ] && [ -n "$value" ]; then + INSTALL_STATE["$key"]="$value" + fi + done < "$INSTALL_STATE_FILE" + log "INFO" "Estado da instalação carregado de $INSTALL_STATE_FILE" + fi +} + +# Função para verificar versão de uma dependência +check_dependency_version() { + local cmd=$1 + local min_version=$2 + + if ! command -v "$cmd" &> /dev/null; then + log "DEBUG" "Comando $cmd não encontrado" + return 1 + fi + + local current_version + case $cmd in + "node") + current_version=$(node -v | sed 's/v//') + ;; + "npm") + current_version=$(npm -v) + ;; + "python3") + current_version=$(python3 --version | awk '{print $2}') + ;; + "pip3") + current_version=$(pip3 --version | awk '{print $2}') + ;; + "gcc") + current_version=$(gcc --version | head -n1 | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -n1) + ;; + *) + current_version=$($cmd --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -n1) + ;; + esac + + if [ -z "$current_version" ]; then + log "WARNING" "Não foi possível determinar a versão de $cmd" + return 2 + fi + + # Comparação de versões usando sort -V + if printf '%s\n' "$min_version" "$current_version" | sort -V | head -n1 | grep -q "^$min_version$"; then + log "SUCCESS" "$cmd versão $current_version atende requisito mínimo ($min_version)" + return 0 + else + log "WARNING" "$cmd versão $current_version é menor que a mínima requerida ($min_version)" + return 3 + fi +} + +# Função para converter arquivos para formato Linux (dos2unix) +convert_files_to_unix() { + log "INFO" "Convertendo arquivos para formato Linux..." + + # Instala dos2unix se não estiver disponível + if ! command -v dos2unix &> /dev/null; then + log "INFO" "Instalando dos2unix..." + apt-get update && apt-get install -y dos2unix + + if ! command -v dos2unix &> /dev/null; then + log "WARNING" "dos2unix não pôde ser instalado. Tentando método alternativo..." + # Método alternativo usando sed + convert_with_sed() { + local file="$1" + if [ -f "$file" ]; then + sed -i 's/\r$//' "$file" 2>/dev/null + if [ $? -eq 0 ]; then + log "DEBUG" "Convertido com sed: $file" + else + log "WARNING" "Falha ao converter: $file" + fi + fi + } + + # Converte arquivos críticos usando sed + find . -type f \( -name "*.sh" -o -name "*.bash" -o -name "*.conf" \) -exec bash -c 'convert_with_sed "$0"' {} \; + log "SUCCESS" "Conversão concluída usando método alternativo" + return 0 + fi + fi + + # Executa o script dos2unixAll.sh se existir + if [ -f "etc/fazai/dos2unixAll.sh" ]; then + log "INFO" "Executando script dos2unixAll.sh..." + chmod +x "etc/fazai/dos2unixAll.sh" + cd "$(dirname "$(readlink -f "$0")")" || cd /opt/fazai + bash etc/fazai/dos2unixAll.sh + log "SUCCESS" "Script dos2unixAll.sh executado" + else + log "INFO" "Script dos2unixAll.sh não encontrado. Executando conversão manual..." + + # Encontra e converte todos os arquivos relevantes + find . -type f \ + \( -name "*.sh" \ + -o -name "*.bash" \ + -o -name "*.conf" \ + -o -name "*.yml" \ + -o -name "*.yaml" \ + -o -name "*.json" \ + -o -name "Dockerfile" \) \ + -exec sh -c ' + for file do + echo "🔄 Convertendo: $file" + dos2unix "$file" 2>/dev/null + if [ $? -eq 0 ]; then + echo "✅ Convertido com sucesso: $file" + else + echo "❌ Erro ao converter: $file" + fi + done + ' sh {} + + fi + + log "SUCCESS" "Conversão de arquivos para formato Linux concluída" +} + +# Função para instalar bash completion +install_bash_completion() { + log "INFO" "Instalando bash completion..." + + # Verifica se o bash-completion está instalado + if ! dpkg -l | grep -q bash-completion 2>/dev/null; then + log "INFO" "Instalando pacote bash-completion..." + apt-get update && apt-get install -y bash-completion + fi + + local completion_dir="/etc/bash_completion.d" + mkdir -p "$completion_dir" + + if [ -f "etc/fazai/fazai-completion.sh" ]; then + cp "etc/fazai/fazai-completion.sh" "$completion_dir/fazai" + else + log "WARNING" "etc/fazai/fazai-completion.sh não encontrado, gerando script simples" + cat > "$completion_dir/fazai" <<'EOF' +#!/bin/bash +complete -W "install uninstall status config help version" fazai +EOF + fi + chmod 644 "$completion_dir/fazai" + log "SUCCESS" "Script de completion instalado em $completion_dir/fazai" + + # Adiciona ao .bashrc se não existir + if ! grep -q "source $completion_dir/fazai" /root/.bashrc 2>/dev/null; then + echo "# FazAI bash completion" >> /root/.bashrc + echo "if [ -f /etc/bash_completion ]; then" >> /root/.bashrc + echo " source /etc/bash_completion" >> /root/.bashrc + echo "fi" >> /root/.bashrc + echo "source $completion_dir/fazai" >> /root/.bashrc + log "SUCCESS" "Bash completion configurado no .bashrc" + fi +} + +# Função para verificar e criar diretório de logs +setup_logging() { + mkdir -p $(dirname $LOG_FILE) + touch $LOG_FILE + log "INFO" "Inicializando log de instalação em $LOG_FILE" + log "INFO" "====== Início da instalação do FazAI v$VERSION ======" + log "INFO" "Data e hora: $(date)" + log "INFO" "Sistema: $(uname -a)" +} + +# Função para verificar permissões de root +check_root() { + log "DEBUG" "Verificando permissões de root..." + if [ "$EUID" -ne 0 ]; then + log "ERROR" "Este script precisa ser executado como root (sudo)." + exit 1 + fi + log "SUCCESS" "Verificação de permissões de root concluída." +} + +# Função para verificar o sistema operacional +check_system() { + log "DEBUG" "Verificando sistema operacional..." + if [ -f /etc/os-release ]; then + . /etc/os-release + # Trata derivados como Ubuntu (ex.: Pop!_OS) + if echo "${ID_LIKE:-}" | grep -qi ubuntu; then + ID=ubuntu + fi + case "$ID" in + debian|ubuntu|pop) + log "SUCCESS" "Sistema Debian/Ubuntu detectado: $NAME $VERSION_ID" + ;; + fedora|rhel|centos) + log "SUCCESS" "Sistema Fedora/RedHat/CentOS detectado: $NAME $VERSION_ID" + ;; + *) + log "WARNING" "Este script foi projetado para Debian, Ubuntu ou Fedora. Detectado: $NAME $VERSION_ID." + read -p "Deseja continuar mesmo assim? (s/n): " -n 1 -r + echo + if [[ ! $REPLY =~ ^[Ss]$ ]]; then + log "INFO" "Instalação cancelada pelo usuário." + exit 1 + fi + log "WARNING" "Prosseguindo instalação em sistema não suportado oficialmente." + ;; + esac + else + log "WARNING" "Não foi possível detectar o sistema operacional. Prosseguindo com cautela." + fi +} + +# Garante runtime de contêiner (Docker) para serviços opcionais (Qdrant/Prometheus/Grafana) +ensure_container_runtime() { + if command -v docker >/dev/null 2>&1 || command -v podman >/dev/null 2>&1; then + log "INFO" "Runtime de contêiner já disponível" + return 0 + fi + log "INFO" "Instalando Docker (runtime de contêiner)" + if command -v apt-get >/dev/null 2>&1; then + apt-get update && apt-get install -y docker.io || log "WARNING" "Falha ao instalar Docker (apt)." + systemctl enable --now docker || true + elif command -v dnf >/dev/null 2>&1; then + dnf install -y docker || log "WARNING" "Falha ao instalar Docker (dnf)." + systemctl enable --now docker || true + elif command -v yum >/dev/null 2>&1; then + yum install -y docker || log "WARNING" "Falha ao instalar Docker (yum)." + systemctl enable --now docker || true + elif command -v zypper >/dev/null 2>&1; then + zypper install -y docker || log "WARNING" "Falha ao instalar Docker (zypper)." + systemctl enable --now docker || true + else + log "WARNING" "Gerenciador de pacotes não suportado para instalação automática do Docker." + fi +} + +# Garantir utilitários de rede usados por scripts e testes +ensure_network_utils() { + log "INFO" "Verificando utilitários de rede (curl, jq, netcat)" + local pkgs=(curl jq netcat) + for p in "${pkgs[@]}"; do + if ! command -v "$p" &>/dev/null; then + log "INFO" "Instalando $p" + if command -v apt-get &>/dev/null; then + apt-get update && apt-get install -y $p || { log "WARNING" "Falha ao instalar $p"; } + elif command -v dnf &>/dev/null; then + dnf install -y $p || { log "WARNING" "Falha ao instalar $p"; } + else + log "WARNING" "Gerenciador de pacotes não detectado; instale $p manualmente" + fi + else + log "DEBUG" "$p já presente" + fi + done +} + +# Função para instalar Node.js com retry e múltiplas versões +install_nodejs() { + if command -v node &> /dev/null; then + NODE_VERSION=$(node -v) + log "SUCCESS" "Node.js já instalado: $NODE_VERSION" + + # Verifica versão mínima do Node.js (>=22.0.0) + NODE_VERSION_NUM=$(echo $NODE_VERSION | cut -c 2-) + NODE_MAJOR=$(echo $NODE_VERSION_NUM | cut -d. -f1) + + if [ $NODE_MAJOR -lt 22 ]; then + log "WARNING" "FazAI requer Node.js versão 22.0.0 ou superior. Versão atual: $NODE_VERSION" + log "INFO" "Tentando atualizar o Node.js..." + install_nodejs_from_source + fi + else + log "WARNING" "Node.js não encontrado. Iniciando instalação..." + install_nodejs_from_source + fi +} + +# Função para instalar Node.js a partir de diferentes fontes +install_nodejs_from_source() { + local success=false + # Detecta gerenciador de pacotes + local PKG_MGR="apt-get" + if [ -f /etc/os-release ]; then + . /etc/os-release + case "$ID" in + fedora|rhel|centos) + PKG_MGR="dnf" + ;; + *) + PKG_MGR="apt-get" + ;; + esac + fi + log "INFO" "Atualizando lista de pacotes..." + $PKG_MGR update -y + $PKG_MGR autoremove -y + $PKG_MGR upgrade -y + log "INFO" "Tentando instalar Node.js via $PKG_MGR..." + $PKG_MGR install -y nodejs npm + if command -v node &> /dev/null; then + NODE_VERSION=$(node -v) + NODE_VERSION_NUM=$(echo $NODE_VERSION | cut -c 2-) + NODE_MAJOR=$(echo $NODE_VERSION_NUM | cut -d. -f1) + if [ $NODE_MAJOR -ge 22 ]; then + log "SUCCESS" "Node.js instalado com sucesso via $PKG_MGR: $NODE_VERSION" + success=true + return 0 + else + log "WARNING" "Versão do Node.js instalada via $PKG_MGR é muito antiga: $NODE_VERSION" + fi + else + log "WARNING" "Falha ao instalar Node.js via $PKG_MGR." + fi + # Tenta instalar via NodeSource para diferentes versões (apenas para Debian/Ubuntu) + if [ "$success" = false ] && [ "$PKG_MGR" = "apt-get" ]; then + if ! command -v curl &> /dev/null; then + $PKG_MGR install -y curl + fi + for version in "${NODE_VERSIONS[@]}"; do + log "INFO" "Tentando instalar Node.js v$version via NodeSource..." + for attempt in $(seq 1 $RETRY_COUNT); do + log "DEBUG" "Tentativa $attempt de $RETRY_COUNT para Node.js v$version" + if curl -fsSL "https://deb.nodesource.com/setup_${version}.x" | bash - && $PKG_MGR install -y nodejs; then + if command -v node &> /dev/null; then + NODE_VERSION=$(node -v) + log "SUCCESS" "Node.js instalado com sucesso: $NODE_VERSION" + success=true + break 2 + fi + fi + log "WARNING" "Tentativa $attempt falhou para Node.js v$version" + sleep 2 + done + done + fi + if [ "$success" = false ]; then + log "ERROR" "Todas as tentativas de instalação do Node.js falharam." + log "ERROR" "Por favor, instale o Node.js manualmente e execute este script novamente." + log "ERROR" "Visite: https://nodejs.org/en/download/package-manager/" + exit 1 + fi +} + +# Função para verificar e instalar npm +install_npm() { + local PKG_MGR="apt-get" + if [ -f /etc/os-release ]; then + . /etc/os-release + case "$ID" in + fedora|rhel|centos) + PKG_MGR="dnf" + ;; + *) + PKG_MGR="apt-get" + ;; + esac + fi + if ! command -v npm &> /dev/null; then + log "WARNING" "npm não encontrado. Instalando..." + $PKG_MGR install -y npm + if ! command -v npm &> /dev/null; then + log "ERROR" "Falha ao instalar npm via $PKG_MGR." + exit 1 + else + NPM_VERSION=$(npm -v) + log "SUCCESS" "npm instalado com sucesso: $NPM_VERSION" + fi + else + NPM_VERSION=$(npm -v) + log "SUCCESS" "npm já instalado: $NPM_VERSION" + fi +} + +# Função para verificar e instalar Python 3 +install_python() { + local PKG_MGR="apt-get" + if [ -f /etc/os-release ]; then + . /etc/os-release + case "$ID" in + fedora|rhel|centos) + PKG_MGR="dnf" + ;; + *) + PKG_MGR="apt-get" + ;; + esac + fi + if command -v python3 &> /dev/null; then + PYTHON_VERSION=$(python3 --version | awk '{print $2}') + PYTHON_MAJOR=$(echo "$PYTHON_VERSION" | cut -d. -f1) + PYTHON_MINOR=$(echo "$PYTHON_VERSION" | cut -d. -f2) + if [ "$PYTHON_MAJOR" -lt 3 ] || { [ "$PYTHON_MAJOR" -eq 3 ] && [ "$PYTHON_MINOR" -lt 10 ]; }; then + log "WARNING" "FazAI requer Python 3.10 ou superior. Versão atual: $PYTHON_VERSION" + $PKG_MGR install -y python3 python3-pip + fi + else + log "WARNING" "Python3 não encontrado. Instalando..." + $PKG_MGR install -y python3 python3-pip + fi + if command -v python3 &> /dev/null; then + PYTHON_VERSION=$(python3 --version | awk '{print $2}') + log "SUCCESS" "python3 instalado: $PYTHON_VERSION" + else + log "ERROR" "Falha ao instalar python3." + exit 1 + fi +} + +# Função para verificar e instalar gcc +install_gcc() { + local PKG_MGR="apt-get" + if [ -f /etc/os-release ]; then + . /etc/os-release + case "$ID" in + fedora|rhel|centos) + PKG_MGR="dnf" + ;; + *) + PKG_MGR="apt-get" + ;; + esac + fi + if ! command -v gcc &> /dev/null; then + log "WARNING" "gcc não encontrado. Instalando build-essential..." + $PKG_MGR install -y gcc g++ make cmake + if ! command -v gcc &> /dev/null; then + log "ERROR" "Falha ao instalar gcc. Por favor, instale manualmente." + exit 1 + fi + GCC_VERSION=$(gcc --version | head -n1) + CMAKE_VERSION=$(cmake --version 2>/dev/null | head -n1) + log "SUCCESS" "gcc instalado com sucesso: $GCC_VERSION" + [ -n "$CMAKE_VERSION" ] && log "SUCCESS" "cmake disponível: $CMAKE_VERSION" + else + GCC_VERSION=$(gcc --version | head -n1) + CMAKE_VERSION=$(cmake --version 2>/dev/null | head -n1) + log "SUCCESS" "gcc já instalado: $GCC_VERSION" + [ -n "$CMAKE_VERSION" ] && log "SUCCESS" "cmake disponível: $CMAKE_VERSION" + fi +} + + + +# Função para criar estrutura de diretórios +create_directories() { + log "INFO" "Criando estrutura de diretórios..." + + # Garante a criação do diretório de logs + if [ ! -d "/var/log/fazai" ]; then + mkdir -p "/var/log/fazai" + log "SUCCESS" "Diretório /var/log/fazai criado" + fi + + local directories=( + "/opt/fazai/bin" + "/opt/fazai/lib" + "/opt/fazai/tools" + "/opt/fazai/mods" + " /opt/fazai/models" + "/etc/fazai" + "/var/log/fazai" + "/var/lib/fazai/history" + "/var/lib/fazai/cache" + "/var/lib/fazai/data" + "/var/backups/fazai" + ) + + for dir in "${directories[@]}"; do + if [ ! -d "$dir" ]; then + mkdir -p "$dir" + log "DEBUG" "Diretório criado: $dir" + else + log "DEBUG" "Diretório já existe: $dir" + fi + done + # Diretório de segredos OPNsense (permissões estritas) + mkdir -p /etc/fazai/secrets/opnsense && chmod 700 /etc/fazai/secrets/opnsense || true + + # Garantir diretório de modelos com permissões apropriadas + if [ ! -d "/opt/fazai/models" ]; then + mkdir -p /opt/fazai/models + chown root:root /opt/fazai/models + chmod 755 /opt/fazai/models + log "DEBUG" "Diretório /opt/fazai/models criado" + fi + + log "SUCCESS" "Estrutura de diretórios criada com sucesso." +} + +# Verifica saúde do serviço e tenta autorreparo básico +health_check_repair() { + log "INFO" "Executando health-check do FazAI (/agent/status)" + local API="http://127.0.0.1:3120" + local ok=false + for attempt in 1 2 3; do + if curl -fsS --max-time 3 "$API/agent/status" >/dev/null 2>&1; then + ok=true + break + fi + log "WARNING" "Health-check falhou (tentativa $attempt). Tentando reparo..." + # Reinicia o worker e o serviço mestre + systemctl restart fazai-gemma-worker 2>/dev/null || true + sleep 1 + # Garante diretório do socket + mkdir -p /run/fazai && chmod 755 /run/fazai || true + systemctl restart fazai 2>/dev/null || true + sleep 2 + # Se o binário do worker não existir, tenta compilar/instalar + if [ ! -x "/opt/fazai/bin/fazai-gemma-worker" ] && [ -d "worker" ] && [ -f "worker/CMakeLists.txt" ]; then + log "INFO" "Binário do worker ausente; tentando compilar/instalar..." + (cd worker && ./build.sh && sudo make install) || true + systemctl restart fazai-gemma-worker 2>/dev/null || true + sleep 1 + fi + done + if [ "$ok" = true ]; then + log "SUCCESS" "Health-check OK: /agent/status respondeu" + else + log "ERROR" "Health-check ainda falhou após tentativas de reparo. Verifique logs do serviço." + fi +} + +# Função para copiar arquivos +copy_files() { + log "INFO" "Copiando arquivos para diretórios de instalação..." + + local copy_errors=0 + + # Cria função auxiliar para cópia com verificação de erros + copy_with_verification() { + local source=$1 + local destination=$2 + local description=$3 + + if [ ! -e "$source" ]; then + log "ERROR" "Arquivo de origem ausente para $description: $source" + return 1 + fi + + local output + if output=$(cp -r "$source" "$destination" 2>&1); then + local dest_path="$destination" + if [ -d "$destination" ]; then + dest_path="$destination/$(basename "$source")" + fi + if [ -e "$dest_path" ]; then + log "DEBUG" "$description copiado de $source para $destination" + return 0 + else + log "ERROR" "Arquivo não encontrado após copiar $source para $destination" + return 1 + fi + else + log "ERROR" "Falha ao copiar $description ($source -> $destination): $output" + return 1 + fi + } + + + + # Cria CLI básico se não existir + if [ ! -f "bin/fazai" ]; then + log "INFO" "Criando CLI básico..." + mkdir -p "bin" + cat > "bin/fazai" << 'EOF' +#!/usr/bin/env node + +/** + * FazAI CLI + */ + +const { spawn } = require('child_process'); +const fs = require('fs'); + +const args = process.argv.slice(2); + +if (args.includes('--version')) { + console.log('FazAI v2.0.0'); + process.exit(0); +} + +if (args.includes('--help')) { + console.log('FazAI - Orquestrador Inteligente de Automação'); + console.log(''); + console.log('Uso: fazai [comando] [opções]'); + console.log(''); + console.log('Comandos:'); + console.log(' --version Mostra a versão'); + console.log(' --help Mostra esta ajuda'); + console.log(' --status Status do daemon'); + console.log(' --start Inicia o daemon'); + console.log(' --stop Para o daemon'); + console.log(' --restart Reinicia o daemon'); + process.exit(0); +} + +if (args.includes('--status')) { + const { execSync } = require('child_process'); + try { + const status = execSync('systemctl is-active fazai', { encoding: 'utf8' }).trim(); + console.log(`FazAI daemon: ${status}`); + } catch (error) { + console.log('FazAI daemon: inativo'); + } + process.exit(0); +} + +console.log('FazAI CLI v2.0.0 - Use --help para mais informações'); +EOF + chmod +x "bin/fazai" + fi + + # Garante que o arquivo de configuração exemplo exista + if [ ! -f "etc/fazai/fazai.conf.example" ]; then + log "ERROR" "etc/fazai/fazai.conf.example não encontrado. Verifique o repositório." + exit 1 + fi + + # Agora copia os arquivos + # Copia toda a biblioteca (inclui handlers, core, providers, etc.) + if ! copy_with_verification "opt/fazai/lib" "/opt/fazai/" "Biblioteca FazAI"; then + copy_errors=$((copy_errors+1)) + else + # Garante permissão de execução no entrypoint + chmod 755 /opt/fazai/lib/main.js 2>/dev/null || true + fi + + + + # Copia módulos e integrações adicionais necessários + for f in \ + "opt/fazai/lib/mcp_opnsense.js" \ + "opt/fazai/lib/complex_tasks.js" \ + "opt/fazai/tools/fazai_web_frontend.html" \ + "opt/fazai/tools/web_search.js" \ + "opt/fazai/tools/suricata_setup.js" \ + "opt/fazai/tools/modsecurity_setup.js" \ + "opt/fazai/tools/crowdsec_setup.js" \ + "opt/fazai/tools/spamexperts.js" \ + "opt/fazai/tools/cloudflare.js" \ + ; do + if [ -f "$f" ]; then + if ! copy_with_verification "$f" "/opt/fazai/$(dirname ${f#opt/fazai/})/" "$(basename $f)"; then + copy_errors=$((copy_errors+1)) + fi + fi + done + + # Copia todas as ferramentas para garantir que plugins sejam carregados + if [ -d "opt/fazai/tools" ]; then + if ! copy_with_verification "opt/fazai/tools" "/opt/fazai/" "Ferramentas FazAI"; then + copy_errors=$((copy_errors+1)) + fi + fi + + # Copia interface web (DOCLER) + if [ -d "opt/fazai/web" ]; then + if ! copy_with_verification "opt/fazai/web" "/opt/fazai/" "Interface Web"; then + copy_errors=$((copy_errors+1)) + fi + # Instalar dependências do web server (express, ws) + if [ -f "/opt/fazai/web/package.json" ]; then + log "INFO" "Instalando dependências da interface web (/opt/fazai/web)" + (cd /opt/fazai/web && npm install --omit=dev --no-audit --no-progress || true) + # Tenta instalar autenticação PAM (opcional) + (cd /opt/fazai/web && npm install authenticate-pam --no-audit --no-progress || true) + fi + + # Cria usuário de serviço não-root para o Docler + if ! id -u fazai-web >/dev/null 2>&1; then + log "INFO" "Criando usuário de serviço 'fazai-web' (sem shell de login)" + useradd --system --home /opt/fazai/web --shell /usr/sbin/nologin fazai-web || true + fi + # Corrige permissões para acesso do usuário fazai-web + chmod 755 /opt/fazai || true + chmod 755 /opt/fazai/web || true + chown -R fazai:fazai-web /opt/fazai/web || true + chmod -R g+rx /opt/fazai/web || true + fi + + # Instalar Qdrant Vector Database + log "INFO" "Instalando Qdrant Vector Database..." + if [ ! -f "/opt/fazai/bin/qdrant" ]; then + log "INFO" "Baixando Qdrant binário..." + if curl -L https://github.com/qdrant/qdrant/releases/latest/download/qdrant-x86_64-unknown-linux-gnu.tar.gz -o /tmp/qdrant.tar.gz 2>/dev/null; then + tar -xzf /tmp/qdrant.tar.gz -C /opt/fazai/bin/ 2>/dev/null || log "WARN" "Falha ao extrair Qdrant - usando Docker fallback" + chmod +x /opt/fazai/bin/qdrant 2>/dev/null || true + rm -f /tmp/qdrant.tar.gz + log "INFO" "Qdrant binário instalado" + else + log "WARN" "Falha no download do Qdrant - será usado via Docker" + fi + fi + + # Criar diretórios e configuração do Qdrant + mkdir -p /var/lib/qdrant /opt/fazai/web/static + chown -R fazai:fazai /var/lib/qdrant + + # Configuração Qdrant + cat > /etc/fazai/qdrant.yaml << 'EOF' +log_level: INFO +storage: + storage_path: /var/lib/qdrant/storage + snapshots_path: /var/lib/qdrant/snapshots + on_disk_payload: true + +service: + http_port: 6333 + grpc_port: 6334 + host: 0.0.0.0 + max_request_size_mb: 32 + max_workers: 0 + static_content_dir: /opt/fazai/web/static + enable_cors: true + +web_ui: + enabled: true + +cluster: + enabled: false + +telemetry_disabled: false +EOF + + # Copia binários auxiliares (inclui fazai-gemma-worker e utilitários) + if [ -d "opt/fazai/bin" ]; then + if ! copy_with_verification "opt/fazai/bin" "/opt/fazai/" "Binários FazAI"; then + copy_errors=$((copy_errors+1)) + else + chmod -R 755 /opt/fazai/bin 2>/dev/null || true + fi + fi + + # Copia modelos Gemma se estiverem no repositório (estrutura antiga) + if [ -d "opt/fazai/models/gemma" ]; then + if ! copy_with_verification "opt/fazai/models/gemma" "/opt/fazai/models/" "Modelos Gemma"; then + copy_errors=$((copy_errors+1)) + fi + else + # Nova estrutura: pesos e tokenizer embarcados junto ao fonte + # Preferir em worker/src/gemma.cpp/, fallback para gemma.cpp/ na raiz + SRC_DIR="" + if [ -f "worker/src/gemma.cpp/2.0-2b-it-sfp.sbs" ] || [ -f "worker/src/gemma.cpp/tokenizer.spm" ]; then + SRC_DIR="worker/src/gemma.cpp" + elif [ -f "gemma.cpp/2.0-2b-it-sfp.sbs" ] || [ -f "gemma.cpp/tokenizer.spm" ]; then + SRC_DIR="gemma.cpp" + fi + if [ -n "$SRC_DIR" ]; then + mkdir -p /opt/fazai/models/gemma + if [ -f "$SRC_DIR/2.0-2b-it-sfp.sbs" ]; then + log "INFO" "Copiando pesos Gemma de $SRC_DIR para /opt/fazai/models/gemma/" + cp -f "$SRC_DIR/2.0-2b-it-sfp.sbs" "/opt/fazai/models/gemma/" || copy_errors=$((copy_errors+1)) + fi + if [ -f "$SRC_DIR/tokenizer.spm" ]; then + log "INFO" "Copiando tokenizer Gemma de $SRC_DIR para /opt/fazai/models/gemma/" + cp -f "$SRC_DIR/tokenizer.spm" "/opt/fazai/models/gemma/" || copy_errors=$((copy_errors+1)) + fi + chmod 644 /opt/fazai/models/gemma/* 2>/dev/null || true + + # Atualiza fazai.conf com caminhos detectados + if [ -f "/etc/fazai/fazai.conf" ]; then + WEIGHTS_PATH="/opt/fazai/models/gemma/2.0-2b-it-sfp.sbs" + TOKENIZER_PATH="/opt/fazai/models/gemma/tokenizer.spm" + if [ -f "$WEIGHTS_PATH" ]; then + sed -i "/^\[gemma_cpp\]/,/^\[/ s|^weights\s*=.*|weights = $WEIGHTS_PATH|" /etc/fazai/fazai.conf || true + fi + if [ -f "$TOKENIZER_PATH" ]; then + sed -i "/^\[gemma_cpp\]/,/^\[/ s|^tokenizer\s*=.*|tokenizer = $TOKENIZER_PATH|" /etc/fazai/fazai.conf || true + fi + sed -i "/^\[gemma_cpp\]/,/^\[/ s|^endpoint\s*=.*|endpoint = /opt/fazai/bin/gemma_oneshot|" /etc/fazai/fazai.conf || true + sed -i "/^\[gemma_cpp\]/,/^\[/ s|^default_model\s*=.*|default_model = gemma2-2b-it|" /etc/fazai/fazai.conf || true + fi + else + # Fallback: caminho externo informado pelo usuário + if [ -d "/media/rluft/fedora/root/opt/fazai/models/gemma" ]; then + if ! copy_with_verification "/media/rluft/fedora/root/opt/fazai/models/gemma" "/opt/fazai/models/" "Modelos Gemma (externo)"; then + copy_errors=$((copy_errors+1)) + fi + fi + fi + fi + + # Compila e instala o binário real gemma_oneshot se as fontes estiverem em worker/src/gemma.cpp + if [ -d "worker/src/gemma.cpp" ] && [ -f "worker/src/gemma.cpp/CMakeLists.txt" ]; then + log "INFO" "Compilando gemma.cpp (gemma_oneshot) a partir de worker/src/gemma.cpp..." + ( + cd worker/src/gemma.cpp + mkdir -p build + cd build + cmake .. -DCMAKE_BUILD_TYPE=Release || true + make -j$(nproc) gemma_oneshot || make gemma_oneshot || true + ) + if [ -x "worker/src/gemma.cpp/build/gemma_oneshot" ]; then + install -m 0755 "worker/src/gemma.cpp/build/gemma_oneshot" "/opt/fazai/bin/gemma_oneshot.real" || true + log "SUCCESS" "gemma_oneshot.real instalado em /opt/fazai/bin" + else + log "WARNING" "Falha ao compilar gemma_oneshot. O wrapper tentará outros caminhos se existir um binário no sistema." + fi + fi + + # DeepSeek helper removido (no-op) + + if ! copy_with_verification "etc/fazai/fazai.conf.example" "/etc/fazai/fazai.conf.default" "Configuração padrão"; then + copy_errors=$((copy_errors+1)) + fi + + # Preserva configuracao atual antes de substituir + if [ -f "/etc/fazai/fazai.conf" ]; then + cp /etc/fazai/fazai.conf /etc/fazai/fazai.conf.bak && \ + log "INFO" "Backup criado em fazai.conf.bak" + mv /etc/fazai/fazai.conf /etc/fazai/fazai.conf.old + log "INFO" "Configuração existente renomeada para fazai.conf.old" + fi + + if ! copy_with_verification "etc/fazai/fazai.conf.example" "/etc/fazai/fazai.conf" "Configuração de sistema"; then + copy_errors=$((copy_errors+1)) + else + log "SUCCESS" "Novo arquivo de configuração criado em /etc/fazai/fazai.conf" + + if [ -f "/etc/fazai/fazai.conf.old" ]; then + for prov in openrouter requesty openai; do + key_val=$(awk -v sec="[$prov]" '$0==sec{f=1;next} /^\[/{f=0} f && /api_key/{print $3}' /etc/fazai/fazai.conf.old) + if [ -n "$key_val" ]; then + sed -i "/^\[$prov\]/,/^$/s|api_key =.*|api_key = $key_val|" /etc/fazai/fazai.conf + fi + done + fi + if [ -f "/root/.env" ]; then + /bin/bash /opt/fazai/tools/sync-keys.sh >/dev/null 2>&1 && log "INFO" "Chaves sincronizadas do .env" + fi + fi + + # Copia gemma_bootstrap + if [ -f "opt/fazai/tools/gemma_bootstrap.sh" ]; then + if ! copy_with_verification "opt/fazai/tools/gemma_bootstrap.sh" "/opt/fazai/tools/" "Gemma bootstrap"; then + copy_errors=$((copy_errors+1)) + else + chmod +x /opt/fazai/tools/gemma_bootstrap.sh + log "SUCCESS" "Gemma bootstrap instalado" + fi + fi + + # Copia complex_tasks.conf.example se existir + if [ -f "etc/fazai/complex_tasks.conf.example" ]; then + if ! copy_with_verification "etc/fazai/complex_tasks.conf.example" "/etc/fazai/complex_tasks.conf.default" "Configuração de tarefas complexas"; then + copy_errors=$((copy_errors+1)) + else + log "SUCCESS" "Configuração de tarefas complexas copiada" + fi + fi + + # Copia manual para /opt/fazai/MANUAL_COMPLETO.md (fallback para MANUAL_FERRAMENTAS.md) + if [ -f "MANUAL_COMPLETO.md" ]; then + if ! copy_with_verification "MANUAL_COMPLETO.md" "/opt/fazai/" "Manual completo"; then + copy_errors=$((copy_errors+1)) + fi + elif [ -f "MANUAL_FERRAMENTAS.md" ]; then + if ! copy_with_verification "MANUAL_FERRAMENTAS.md" "/opt/fazai/" "Manual de ferramentas"; then + copy_errors=$((copy_errors+1)) + else + # Mantém o nome esperado pelo CLI + cp -f "/opt/fazai/MANUAL_FERRAMENTAS.md" "/opt/fazai/MANUAL_COMPLETO.md" 2>/dev/null || true + fi + else + log "WARNING" "Manual não encontrado no repositório (MANUAL_COMPLETO.md/MANUAL_FERRAMENTAS.md)" + fi + + if ! copy_with_verification "bin/fazai" "/opt/fazai/bin/" "CLI"; then + copy_errors=$((copy_errors+1)) + fi + chmod 755 /opt/fazai/bin/fazai + ln -sf /opt/fazai/bin/fazai /usr/local/bin/fazai + log "SUCCESS" "CLI instalado em /usr/local/bin/fazai" + + # Instala GPT-Web2Shell (utilitário externo, exclusivo - OPT-IN via FAZAI_ENABLE_GPT_WEB2SHELL=1) + if [ "${FAZAI_ENABLE_GPT_WEB2SHELL}" = "1" ]; then + EXTRA_DIR="${FAZAI_LOCAL_EXTRAS_DIR:-}" + # Preferir extras externos + if [ -n "$EXTRA_DIR" ] && [ -f "$EXTRA_DIR/gpt-web2shell/bin/gpt-web2shell" ]; then + log "INFO" "Instalando GPT-Web2Shell a partir de FAZAI_LOCAL_EXTRAS_DIR=$EXTRA_DIR" + mkdir -p /opt/fazai/bin /opt/fazai/tools + cp -f "$EXTRA_DIR/gpt-web2shell/bin/gpt-web2shell" /opt/fazai/bin/gpt-web2shell + cp -f "$EXTRA_DIR/gpt-web2shell/opt/fazai/tools/gpt-web2shell.js" /opt/fazai/tools/gpt-web2shell.js + chmod 755 /opt/fazai/bin/gpt-web2shell /opt/fazai/tools/gpt-web2shell.js || true + ln -sf /opt/fazai/bin/gpt-web2shell /usr/local/bin/gpt-web2shell + log "SUCCESS" "GPT-Web2Shell instalado em /usr/local/bin/gpt-web2shell (extras externos)" + elif [ -f "bin/gpt-web2shell" ] && [ -f "opt/fazai/tools/gpt-web2shell.js" ]; then + # fallback: se os arquivos estiverem presentes no diretório do repositório + if copy_with_verification "bin/gpt-web2shell" "/opt/fazai/bin/" "GPT-Web2Shell"; then + mkdir -p /opt/fazai/tools + cp -f "opt/fazai/tools/gpt-web2shell.js" "/opt/fazai/tools/gpt-web2shell.js" + chmod 755 /opt/fazai/bin/gpt-web2shell /opt/fazai/tools/gpt-web2shell.js || true + ln -sf /opt/fazai/bin/gpt-web2shell /usr/local/bin/gpt-web2shell + log "SUCCESS" "GPT-Web2Shell instalado em /usr/local/bin/gpt-web2shell" + else + log "WARNING" "Falha ao instalar GPT-Web2Shell (arquivos locais)" + fi + else + log "WARNING" "FAZAI_ENABLE_GPT_WEB2SHELL=1 definido, mas arquivos não encontrados. Use scripts/install-web2shell.sh com FAZAI_LOCAL_EXTRAS_DIR." + fi + else + log "INFO" "GPT-Web2Shell não instalado (exclusivo). Para instalar, exporte FAZAI_ENABLE_GPT_WEB2SHELL=1 e forneça os arquivos via FAZAI_LOCAL_EXTRAS_DIR." + fi + + # Copia ferramentas do bin/tools para /opt/fazai/tools + if [ -d "bin/tools" ]; then + log "INFO" "Copiando ferramentas do bin/tools..." + if ! copy_with_verification "bin/tools/github-setup.sh" "/opt/fazai/tools/" "GitHub Setup Script"; then + copy_errors=$((copy_errors+1)) + fi + if ! copy_with_verification "bin/tools/sync-changes.sh" "/opt/fazai/tools/" "Sync Changes Script"; then + copy_errors=$((copy_errors+1)) + fi + if ! copy_with_verification "bin/tools/sync-keys.sh" "/opt/fazai/tools/" "Sync Keys Script"; then + copy_errors=$((copy_errors+1)) + fi + if ! copy_with_verification "bin/tools/system-check.sh" "/opt/fazai/tools/" "System Check Script"; then + copy_errors=$((copy_errors+1)) + fi + if ! copy_with_verification "bin/tools/test-all-tools.sh" "/opt/fazai/tools/" "Test All Tools Script"; then + copy_errors=$((copy_errors+1)) + fi + if ! copy_with_verification "bin/tools/version-bump.sh" "/opt/fazai/tools/" "Version Bump Script"; then + copy_errors=$((copy_errors+1)) + fi + if ! copy_with_verification "bin/tools/install-llamacpp.sh" "/opt/fazai/tools/" "LLaMA Install Script"; then + copy_errors=$((copy_errors+1)) + fi + + # Torna os scripts executáveis + chmod +x /opt/fazai/tools/*.sh 2>/dev/null + log "SUCCESS" "Ferramentas copiadas e tornadas executáveis" + fi + + # Copia módulos nativos se existirem + if [ -f "opt/fazai/mods/system_mod.so" ]; then + if ! copy_with_verification "opt/fazai/mods/system_mod.so" "/opt/fazai/mods/" "Módulo nativo system_mod"; then + copy_errors=$((copy_errors+1)) + else + log "SUCCESS" "Módulo nativo copiado" + fi + fi + + # Compila módulo system_mod.c se existir + if [ -f "opt/fazai/lib/mods/system_mod.c" ]; then + log "INFO" "Compilando módulo system_mod.c..." + mkdir -p /opt/fazai/lib/mods/ + cp -r opt/fazai/lib/mods/* /opt/fazai/lib/mods/ 2>/dev/null || true + + cd /opt/fazai/lib/mods/ + if [ -f "compile_system_mod.sh" ]; then + chmod +x compile_system_mod.sh + # Verifica dependências primeiro (sem instalar) + ./compile_system_mod.sh --check || log "WARNING" "Pendências detectadas; tentando auto-instalação e compilação." + # Compila (com auto-instalação de pacotes quando necessário) + ./compile_system_mod.sh || log "WARNING" "Falha na compilação do system_mod.c" + # Publica .so + mkdir -p /opt/fazai/mods + cp -f /opt/fazai/lib/mods/*.so /opt/fazai/mods/ 2>/dev/null || true + if ls /opt/fazai/mods/*.so >/dev/null 2>&1; then + log "SUCCESS" "Módulos nativos disponibilizados em /opt/fazai/mods" + else + log "WARNING" "Nenhum módulo .so encontrado após compilação" + fi + else + # Compilação manual se o script não existir + log "WARNING" "Script de compilação não encontrado, tentando compilação manual..." + gcc -shared -fPIC -o system_mod.so system_mod.c -lclamav -lcurl -ljson-c -lpthread 2>/dev/null || log "WARNING" "Falha na compilação do system_mod.c (dependências podem estar faltando)" + mkdir -p /opt/fazai/mods + cp -f /opt/fazai/lib/mods/system_mod.so /opt/fazai/mods/ 2>/dev/null || true + fi + cd - > /dev/null + fi + + + + # Copia novas tools + for t in \ + "opt/fazai/tools/auto_tool.js" \ + "opt/fazai/tools/net_qos_monitor.js" \ + "opt/fazai/tools/agent_supervisor.js" \ + "opt/fazai/tools/qdrant_setup.js" \ + "opt/fazai/tools/snmp_monitor.js" \ + "opt/fazai/tools/modsecurity_setup.js" \ + "opt/fazai/tools/suricata_setup.js" \ + "opt/fazai/tools/crowdsec_setup.js" \ + "opt/fazai/tools/monit_setup.js" \ + "opt/fazai/tools/rag_ingest.js" \ + "opt/fazai/tools/download_gemma2.sh" \ + "opt/fazai/tools/install_python_deps.sh" \ + "opt/fazai/tools/alerts.js" \ + "opt/fazai/tools/blacklist_check.js" \ + "opt/fazai/tools/email_relay.js" \ + "opt/fazai/tools/geoip_lookup.js" \ + "opt/fazai/tools/http_fetch.js" \ + "opt/fazai/tools/ports_monitor.js" \ + "opt/fazai/tools/system_info.js" \ + "opt/fazai/tools/test_complex_tasks.js" \ + "opt/fazai/tools/weather.js" \ + "opt/fazai/tools/crowdsec.js" \ + "opt/fazai/tools/modsecurity.js" \ + "opt/fazai/tools/spamexperts.js" \ + "opt/fazai/tools/web_search.js" \ + "opt/fazai/tools/cloudflare.js"; do + if [ -f "$t" ]; then + if ! copy_with_verification "$t" "/opt/fazai/tools/" "Tool $(basename $t)"; then + copy_errors=$((copy_errors+1)) + else + chmod 755 "/opt/fazai/tools/$(basename $t)" || true + fi + fi + done + + # Instala dependência dialog para alguns scripts + install_dialog + + # Copia interface web front-end + if [ -f "opt/fazai/tools/fazai_web_frontend.html" ]; then + if ! copy_with_verification "opt/fazai/tools/fazai_web_frontend.html" "/opt/fazai/tools/" "Interface web"; then + copy_errors=$((copy_errors+1)) + else + chmod 644 "/opt/fazai/tools/fazai_web_frontend.html" + log "SUCCESS" "Interface web instalada" + fi + else + log "WARNING" "Interface web não encontrado, crio fallback básico..." + cat > "/opt/fazai/tools/fazai_web_frontend.html" << 'EOF' + + + + + + FazAI - Interface Web + + +

FazAI Interface Web

+

Interface básica gerada automaticamente.

+ + +EOF + log "SUCCESS" "Interface web fallback criada" + fi + if [ -f "opt/fazai/tools/fazai-tui.sh" ]; then + if ! copy_with_verification "opt/fazai/tools/fazai-tui.sh" "/opt/fazai/tools/" "Dashboard TUI completo"; then + copy_errors=$((copy_errors+1)) + else + chmod +x /opt/fazai/tools/fazai-tui.sh + ln -sf /opt/fazai/tools/fazai-tui.sh /usr/local/bin/fazai-tui + log "SUCCESS" "Dashboard TUI completo instalado em /usr/local/bin/fazai-tui" + fi + if command -v cargo >/dev/null 2>&1; then + log "INFO" "Compilando TUI em Rust..." + if cargo build --release --manifest-path=tui/Cargo.toml >/tmp/fazai_tui_build.log 2>&1; then + cp tui/target/release/fazai-tui /opt/fazai/tools/fazai-tui-rs + ln -sf /opt/fazai/tools/fazai-tui-rs /usr/local/bin/fazai-tui + log "SUCCESS" "TUI Rust instalado em /usr/local/bin/fazai-tui" + else + log "WARNING" "Falha ao compilar TUI Rust, utilizando script bash" + fi + fi + else + log "WARNING" "Dashboard TUI não encontrado, criando versão básica..." + cat > "/opt/fazai/tools/fazai-tui.sh" << 'EOF' +#!/bin/bash +# FazAI Dashboard TUI - Versão Básica +echo "FazAI Dashboard TUI v2.0.0" +echo "Opções:" +echo " [l] Ver logs | [s] Status | [q] Sair" +while read -r -n1 -p "Selecione: " k; do + echo + case "$k" in + l) curl -fsS http://localhost:3120/logs | jq . || true ;; + s) curl -fsS http://localhost:3120/status | jq . || true ;; + q) echo "Saindo..."; exit 0 ;; + *) echo "Opção inválida" ;; + esac +done +EOF + chmod +x "/opt/fazai/tools/fazai-tui.sh" + ln -sf /opt/fazai/tools/fazai-tui.sh /usr/local/bin/fazai-tui + log "SUCCESS" "Dashboard TUI básico instalado em /usr/local/bin/fazai-tui" + + log "WARNING" "Interface web não encontrada, criando versão básica..." + # Cria uma versão básica se não existir + cat > "/opt/fazai/tools/fazai_web_frontend.html" << 'EOF' + + + + + + FazAI - Interface Web + + + +
+

FazAI - Interface Web

+
+

Gerenciamento de Logs

+ + + +
+
+

Status do Sistema

+ +
+
+
+ + + +EOF + log "SUCCESS" "Interface web básica criada" + fi + + # Copia script de lançamento da interface web + if [ -f "opt/fazai/tools/fazai_web.sh" ]; then + if ! copy_with_verification "opt/fazai/tools/fazai_web.sh" "/opt/fazai/tools/" "Script de lançamento web"; then + copy_errors=$((copy_errors+1)) + else + chmod +x "/opt/fazai/tools/fazai_web.sh" + log "SUCCESS" "Script de lançamento web instalado" + fi + else + log "WARNING" "Script de lançamento web não encontrado, criando versão básica..." + cat > "/opt/fazai/tools/fazai_web.sh" << 'EOF' + #!/bin/bash + # FazAI Web Frontend Launcher + # Caminho: /opt/fazai/tools/fazai_web.sh + + FRONTEND_FILE="/opt/fazai/tools/fazai_web_frontend.html" + + if [ ! -f "$FRONTEND_FILE" ]; then + echo "Erro: Interface web não encontrada: $FRONTEND_FILE" + exit 1 + fi + + echo "Iniciando interface web do FazAI..." + + # Detecta o sistema e abre o navegador + if [[ "$OSTYPE" == "linux-gnu"* ]]; then + if command -v xdg-open > /dev/null; then + xdg-open "$FRONTEND_FILE" + elif command -v firefox > /dev/null; then + firefox "$FRONTEND_FILE" + else + echo "Abra manualmente: $FRONTEND_FILE" + fi + elif [[ "$OSTYPE" == "darwin"* ]]; then + open "$FRONTEND_FILE" + elif [[ "$OSTYPE" == "cygwin" || "$OSTYPE" == "msys" ]]; then + start "$FRONTEND_FILE" + else + echo "Abra manualmente: $FRONTEND_FILE" + fi + + echo "Interface web disponível em: file://$FRONTEND_FILE" +EOF + chmod +x "/opt/fazai/tools/fazai_web.sh" + log "SUCCESS" "Script de lançamento web básico criado" + fi + + # Copia gerador de visualização HTML + if [ -f "opt/fazai/tools/fazai_html_v1.sh" ]; then + if ! copy_with_verification "opt/fazai/tools/fazai_html_v1.sh" "/opt/fazai/tools/" "Gerador HTML"; then + copy_errors=$((copy_errors+1)) + else + chmod +x "/opt/fazai/tools/fazai_html_v1.sh" + ln -sf /opt/fazai/tools/fazai_html_v1.sh /usr/local/bin/fazai-html + log "SUCCESS" "Gerador HTML instalado em /usr/local/bin/fazai-html" + fi + fi + + if [ "$copy_errors" -ne 0 ]; then + log "ERROR" "$copy_errors falha(s) ao copiar arquivos. Veja $LOG_FILE para detalhes." + return 1 + fi + + log "SUCCESS" "Arquivos copiados com sucesso." + } + + # Função para importar configurações de .env + import_env_config() { + log "INFO" "Verificando configurações de ambiente..." + + # Locais possíveis do arquivo .env + local env_locations=( + "/root/.env" + "$HOME/.env" + "./.env" + ".env.example" + ) + + local env_file="" + + # Procura o primeiro arquivo .env disponível + for location in "${env_locations[@]}"; do + if [ -f "$location" ]; then + env_file="$location" + log "INFO" "Arquivo .env encontrado em $env_file" + break + fi + done + + if [ -n "$env_file" ]; then + log "INFO" "Arquivo .env encontrado. Importando configurações..." + + # Extrai chaves de API + local api_keys=( + "OPENAI_API_KEY" + "ANTHROPIC_API_KEY" + "GOOGLE_API_KEY" + "AZURE_API_KEY" + ) + + local fazai_conf="/etc/fazai/fazai.conf" + local changes_made=false + + for key in "${api_keys[@]}"; do + local value=$(grep "^$key=" "$env_file" 2>/dev/null | cut -d'=' -f2 | tr -d '"' | tr -d "'") + if [ -n "$value" ]; then + local config_key=$(echo "$key" | tr '[:upper:]' '[:lower:]') + + # Verifica se a chave já existe no arquivo de configuração + if grep -q "^$config_key" "$fazai_conf"; then + # Substitui o valor existente + sed -i "s|^$config_key.*|$config_key = $value|" "$fazai_conf" + else + # Adiciona nova entrada na seção de APIs + if grep -q "^\[apis\]" "$fazai_conf"; then + sed -i "/^\[apis\]/a $config_key = $value" "$fazai_conf" + else + # Se não houver seção de APIs, adiciona ao final do arquivo + echo -e "\n[apis]\n$config_key = $value" >> "$fazai_conf" + fi + fi + + log "SUCCESS" "Chave $key importada com sucesso." + changes_made=true + fi + done + + if [ "$changes_made" = true ]; then + log "SUCCESS" "Configurações importadas para $fazai_conf" + else + log "WARNING" "Nenhuma configuração relevante encontrada em $env_file" + fi + else + log "INFO" "Nenhum arquivo .env encontrado nas localizações padrão." + fi + } + + # Função para configurar o serviço systemd +configure_systemd() { + log "INFO" "Configurando serviço systemd..." + + local service_file="/etc/systemd/system/fazai.service" + + # Gera um arquivo de serviço melhorado + cat > "$service_file" << EOF + [Unit] + Description=FazAI Service + After=network.target fazai-gemma-worker.service fazai-docler.service fazai-qdrant.service + Wants=fazai-gemma-worker.service fazai-docler.service + Wants=fazai-qdrant.service + StartLimitIntervalSec=0 + + [Service] + Type=simple + Restart=always + RestartSec=1 + User=root + ExecStart=/usr/bin/node /opt/fazai/lib/main.js + WorkingDirectory=/opt/fazai + Environment=NODE_ENV=production + StandardOutput=append:/var/log/fazai/stdout.log + StandardError=append:/var/log/fazai/stderr.log + + # Limites de recursos + LimitNOFILE=65535 + LimitMEMLOCK=512M + + [Install] + WantedBy=multi-user.target +EOF + + chmod 644 "$service_file" + log "SUCCESS" "Arquivo de serviço systemd criado em $service_file" + + systemctl daemon-reload + systemctl enable fazai + log "SUCCESS" "Serviço systemd habilitado." + + # Instala serviço do Gemma Worker se binário existir + if [ -x "/opt/fazai/bin/fazai-gemma-worker" ]; then + log "INFO" "Configurando serviço fazai-gemma-worker..." + cat > "/etc/systemd/system/fazai-gemma-worker.service" << EOF +[Unit] +Description=FazAI Gemma Worker v2.0 +After=network.target fazai-qdrant.service +Wants=fazai-qdrant.service +PartOf=fazai.service + +[Service] +Type=simple +User=root +WorkingDirectory=/opt/fazai +EnvironmentFile=-/etc/fazai/env +RuntimeDirectory=fazai +RuntimeDirectoryMode=0777 +UMask=0000 +ExecStartPre=/usr/bin/install -d -m 0777 -o root -g root /run/fazai +ExecStartPre=/bin/rm -f /run/fazai/gemma.sock +ExecStart=/opt/fazai/bin/fazai_gemma_worker.py +ExecStopPost=/bin/rm -f /run/fazai/gemma.sock +Restart=always +RestartSec=5 +StandardOutput=journal +StandardError=journal + +[Install] +WantedBy=multi-user.target +EOF + chmod 644 "/etc/systemd/system/fazai-gemma-worker.service" + systemctl daemon-reload + systemctl enable fazai-gemma-worker || true + log "SUCCESS" "Serviço fazai-gemma-worker preparado." + else + log "WARNING" "Binário fazai-gemma-worker não encontrado; serviço do worker não será criado." + fi + + # Serviço DOCLER Web (portas 3220/3221 para evitar conflito com daemon 3120) + if [ -f "/opt/fazai/web/docler-server.js" ]; then + log "INFO" "Configurando serviço fazai-docler..." + cat > "/etc/systemd/system/fazai-docler.service" << 'EOF' +[Unit] +Description=FazAI DOCLER Web Server +After=network.target +PartOf=fazai.service + +[Service] +Type=simple +User=fazai-web +Group=fazai-web +Environment=DOCLER_PORT=3220 +Environment=DOCLER_ADMIN_PORT=3221 +Environment=DOCLER_HOST=0.0.0.0 +WorkingDirectory=/opt/fazai/web +ExecStart=/usr/bin/node /opt/fazai/web/docler-server.js +Restart=always +RestartSec=5 + +[Install] +WantedBy=multi-user.target +EOF + chmod 644 "/etc/systemd/system/fazai-docler.service" + systemctl daemon-reload + systemctl enable fazai-docler || true + # Tenta iniciar se dependências foram instaladas + systemctl start fazai-docler || true + log "SUCCESS" "Serviço fazai-docler preparado (portas 3220/3221)." + else + log "WARNING" "docler-server.js não encontrado; serviço DOCLER não será criado." + fi + + # Serviço Qdrant Vector Database + log "INFO" "Configurando serviço fazai-qdrant..." + if command -v docker >/dev/null 2>&1 && systemctl is-active docker >/dev/null 2>&1; then + # Usar Docker se disponível + cat > "/etc/systemd/system/fazai-qdrant.service" << 'EOF' +[Unit] +Description=FazAI Qdrant Vector Database (Docker) +After=network.target docker.service +Requires=docker.service +PartOf=fazai.service + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStartPre=/usr/bin/docker pull qdrant/qdrant:latest +ExecStart=/usr/bin/docker run -d \ + --name fazai-qdrant \ + --restart unless-stopped \ + -p 6333:6333 \ + -p 6334:6334 \ + -v /var/lib/qdrant:/qdrant/storage \ + -v /opt/fazai/web/static:/opt/qdrant/web/static \ + -e QDRANT__SERVICE__HTTP_PORT=6333 \ + -e QDRANT__SERVICE__GRPC_PORT=6334 \ + -e QDRANT__SERVICE__HOST=0.0.0.0 \ + -e QDRANT__WEB_UI__ENABLED=true \ + -e QDRANT__SERVICE__ENABLE_CORS=true \ + qdrant/qdrant:latest +ExecStop=/usr/bin/docker stop fazai-qdrant +ExecStopPost=/usr/bin/docker rm fazai-qdrant + +[Install] +WantedBy=multi-user.target +EOF + elif [ -f "/opt/fazai/bin/qdrant" ]; then + # Usar binário nativo se disponível + cat > "/etc/systemd/system/fazai-qdrant.service" << 'EOF' +[Unit] +Description=FazAI Qdrant Vector Database +After=network.target +PartOf=fazai.service + +[Service] +Type=simple +User=fazai +Group=fazai +WorkingDirectory=/var/lib/qdrant +ExecStart=/opt/fazai/bin/qdrant --config-path /etc/fazai/qdrant.yaml +Restart=always +RestartSec=5 +Environment=RUST_LOG=info + +[Install] +WantedBy=multi-user.target +EOF + fi + + chmod 644 "/etc/systemd/system/fazai-qdrant.service" 2>/dev/null || true + systemctl daemon-reload + systemctl enable fazai-qdrant || true + systemctl start fazai-qdrant || true + log "SUCCESS" "Serviço fazai-qdrant preparado (porta 6333)." + + + + # Instalar GPT-Web2Shell se local-extras existe + if [ -d "local-extras/gpt-web2shell" ]; then + log "INFO" "Instalando GPT-Web2Shell..." + mkdir -p /home/${SUDO_USER}/fazai/local-extras/gpt-web2shell + cp -r local-extras/gpt-web2shell/* /home/${SUDO_USER}/fazai/local-extras/gpt-web2shell/ + chown -R ${SUDO_USER}:${SUDO_USER} /home/${SUDO_USER}/fazai/local-extras/ 2>/dev/null || true + chmod +x /home/${SUDO_USER}/fazai/local-extras/gpt-web2shell/bin/gpt-web2shell 2>/dev/null || true + chmod +x /opt/fazai/tools/gpt-web2shell.js 2>/dev/null || true + log "SUCCESS" "GPT-Web2Shell instalado para transcendência CLI." + fi + + # Detecta runtime de contêiner (Docker/Podman) + local CONTAINER="" + if command -v docker >/dev/null 2>&1; then CONTAINER="docker"; fi + if [ -z "$CONTAINER" ] && command -v podman >/dev/null 2>&1; then CONTAINER="podman"; fi + + # Serviço Qdrant (via Docker/Podman) se disponível + if [ -n "$CONTAINER" ]; then + log "INFO" "Configurando serviço Qdrant ($CONTAINER)..." + mkdir -p /var/lib/fazai/qdrant + cat > "/etc/systemd/system/fazai-qdrant.service" << 'EOF' +[Unit] +Description=FazAI Qdrant Vector DB (Docker) +After=network-online.target +PartOf=fazai.service + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStartPre=-/usr/bin/CONTAINER_BIN rm -f fazai-qdrant +ExecStart=/usr/bin/CONTAINER_BIN run -d --name fazai-qdrant -p 6333:6333 -v /var/lib/fazai/qdrant:/qdrant/storage qdrant/qdrant:v1.7.3 +ExecStop=/usr/bin/CONTAINER_BIN stop fazai-qdrant +TimeoutStartSec=120 +TimeoutStopSec=30 + +[Install] +WantedBy=multi-user.target +EOF + # Substitui placeholder pelo runtime + sed -i "s|CONTAINER_BIN|$CONTAINER|g" "/etc/systemd/system/fazai-qdrant.service" + chmod 644 "/etc/systemd/system/fazai-qdrant.service" + systemctl daemon-reload + systemctl enable fazai-qdrant || true + systemctl start fazai-qdrant || true + log "SUCCESS" "Serviço Qdrant preparado (porta 6333)." + + + else + log "WARNING" "Docker/Podman não encontrado; Qdrant não será instalado automaticamente. Instale um runtime de contêiner ou configure Qdrant manualmente." + fi + + # Observabilidade foi movida para repo separado (~/fazaiserverlogs) + if [ -n "$CONTAINER" ]; then + log "INFO" "Monitoring Prometheus/Grafana não é mais instalado neste host. Use o repositório fazaiserverlogs." + fi +} + +# Compila e instala o Gemma Worker (C++) se fontes estiverem presentes +build_gemma_worker() { + if [ -d "worker" ] && [ -f "worker/CMakeLists.txt" ]; then + log "INFO" "Compilando Gemma Worker (C++)..." + mkdir -p worker/build + pushd worker/build >/dev/null + if cmake .. && cmake --build . -j$(nproc) && cmake --install .; then + log "SUCCESS" "Gemma Worker compilado e instalado em /opt/fazai/bin" + else + log "WARNING" "Falha ao compilar o Gemma Worker. O agente local poderá não funcionar." + fi + popd >/dev/null + # Garante diretório de socket + mkdir -p /run/fazai + chmod 755 /run/fazai + else + log "INFO" "Fontes do Gemma Worker não encontradas; pulando compilação." + fi +} + +# Instala Gemma one-shot e pesos padrão (máquinas pequenas) +bootstrap_gemma() { + if [ -x "/opt/fazai/bin/gemma_oneshot" ] && [ -f "/opt/fazai/models/gemma/2.0-2b-it-sfp.sbs" ]; then + log "INFO" "Gemma (oneshot + pesos) já presente." + return 0 + fi + if [ -x "/opt/fazai/tools/gemma_bootstrap.sh" ]; then + log "INFO" "Executando gemma_bootstrap.sh (download/instalação do modelo)." + bash /opt/fazai/tools/gemma_bootstrap.sh || log "WARNING" "Falha no gemma_bootstrap.sh" + else + log "WARNING" "gemma_bootstrap.sh não encontrado." + fi +} + + # Função para instalar dependências do Node.js com retry + install_node_dependencies() { + log "INFO" "Instalando dependências do Node.js..." + + # Cria package.json se não existir + if [ ! -f "package.json" ]; then + log "INFO" "Criando package.json..." + cat > "package.json" << 'EOF' + { + "name": "fazai", + "version": "2.0.0", + "description": "FazAI - Orquestrador Inteligente de Automação", + "main": "main.js", + "dependencies": { + "axios": ">=0.27.2", + "express": ">=4.18.1", + "winston": ">=3.8.1", + + "chalk": ">=4.1.2", + "figlet": ">=1.5.2", + "inquirer": ">=8.2.4" + } + } +EOF + fi + + # Instala no diretório atual primeiro + log "INFO" "Instalando dependências no diretório atual..." + if ! npm install --no-audit --no-progress; then + log "WARNING" "Falha na instalação inicial de dependências. Tentando método alternativo..." + + # Tenta instalar pacotes críticos individualmente + for module in "${DEPENDENCY_MODULES[@]}"; do + log "INFO" "Instalando módulo: $module" + npm install "$module" --no-audit --no-progress || log "WARNING" "Falha ao instalar $module" + done + fi + + # Agora instala em /opt/fazai + log "INFO" "Instalando dependências em /opt/fazai..." + cp package.json /opt/fazai/ + cd /opt/fazai + + if ! npm install --no-audit --no-progress; then + log "WARNING" "Falha ao instalar dependências em /opt/fazai. Tentando método alternativo..." + + # Tenta instalar pacotes críticos individualmente + for module in "${DEPENDENCY_MODULES[@]}"; do + log "INFO" "Instalando módulo em /opt/fazai: $module" + npm install "$module" --no-audit --no-progress || log "WARNING" "Falha ao instalar $module" + done + fi + + cd - > /dev/null + + # Verifica se os módulos essenciais foram instalados + if npm list express winston >> "$LOG_FILE" 2>&1; then + log "SUCCESS" "Módulos express e winston instalados corretamente." + else + log "WARNING" "Módulos express ou winston ausentes. Possível problema de conexão. Execute 'npm install' manualmente." + fi + + log "SUCCESS" "Dependências do Node.js instaladas." + } + + # Função para compilar módulos nativos + compile_native_modules() { + log "INFO" "Verificando módulos nativos..." + + # Cria um módulo nativo básico se não existir + if [ ! -d "/opt/fazai/mods" ]; then + mkdir -p "/opt/fazai/mods" + fi + + cd /opt/fazai/mods + + if [ ! -f "system_mod.c" ]; then + log "INFO" "Criando módulo nativo básico..." + cat > "system_mod.c" << 'EOF' + #include + #include + + // Função básica para teste do módulo nativo + int fazai_test() { + return 42; + } +EOF + fi + + if [ -f "system_mod.c" ]; then + log "DEBUG" "Compilando system_mod.c..." + if gcc -shared -fPIC -o system_mod.so system_mod.c; then + log "SUCCESS" "Módulos nativos compilados com sucesso." + else + log "WARNING" "Falha ao compilar módulos nativos. Continuando sem eles..." + fi + else + log "INFO" "Nenhum módulo nativo para compilar." + fi + + cd - > /dev/null + } + + # Função opcional para instalar o llama.cpp + install_llamacpp() { + if [ "$WITH_LLAMA" != true ]; then + log "INFO" "Instalação do llama.cpp ignorada (--with-llama)" + return 0 + fi + + log "INFO" "Instalando llama.cpp..." + local script_dir="$(cd "$(dirname "$0")" && pwd)" + if bash "$script_dir/bin/tools/install-llamacpp.sh"; then + log "SUCCESS" "llama.cpp instalado" + return 0 + else + log "ERROR" "Falha ao instalar llama.cpp" + return 1 + fi + } + + # Função para instalar interface TUI + + # Função para configurar permissões de segurança + configure_security() { + log "INFO" "Configurando permissões de segurança..." + + # Cria grupo fazai se não existir + if ! getent group fazai > /dev/null 2>&1; then + groupadd -r fazai + log "SUCCESS" "Grupo 'fazai' criado" + fi + + # Cria usuário fazai se não existir + if ! getent passwd fazai > /dev/null 2>&1; then + useradd -r -g fazai -s /bin/false -d /opt/fazai fazai + log "SUCCESS" "Usuário 'fazai' criado" + fi + + # Define permissões dos diretórios + chown -R fazai:fazai /opt/fazai + chown -R fazai:fazai /var/log/fazai + chown -R fazai:fazai /var/lib/fazai + + # Permissões específicas + chmod 750 /opt/fazai + chmod 755 /opt/fazai/bin/fazai + # Conf: dono fazai, grupo root, 640 + chown fazai:root /etc/fazai/fazai.conf 2>/dev/null || true + chmod 640 /etc/fazai/fazai.conf + chmod 755 /opt/fazai/tools/fazai-config.js + + # Configura sudoers para permitir comandos específicos do fazai + if [ ! -f /etc/sudoers.d/fazai ]; then + cat > /etc/sudoers.d/fazai << 'EOF' + # FazAI sudoers configuration + %fazai ALL=(ALL) NOPASSWD: /bin/systemctl start fazai + %fazai ALL=(ALL) NOPASSWD: /bin/systemctl stop fazai + %fazai ALL=(ALL) NOPASSWD: /bin/systemctl restart fazai + %fazai ALL=(ALL) NOPASSWD: /bin/systemctl status fazai + %fazai ALL=(ALL) NOPASSWD: /usr/bin/apt-get update + %fazai ALL=(ALL) NOPASSWD: /usr/bin/apt-get install * + %fazai ALL=(ALL) NOPASSWD: /usr/sbin/service * * +EOF + chmod 440 /etc/sudoers.d/fazai + log "SUCCESS" "Configuração sudoers criada" + fi + + log "SUCCESS" "Permissões de segurança configuradas" + } + + # Função para criar scripts auxiliares + create_helper_scripts() { + log "INFO" "Criando scripts auxiliares..." + + # Script de uninstall + cat > /opt/fazai/bin/uninstall.sh << 'EOF' + #!/bin/bash + # FazAI Uninstall Script + + echo "Desinstalando FazAI..." + + # Para o serviço + systemctl stop fazai 2>/dev/null + systemctl disable fazai 2>/dev/null + + # Remove arquivos de serviço + rm -f /etc/systemd/system/fazai.service + systemctl daemon-reload + + # Remove links simbólicos + rm -f /usr/local/bin/fazai + rm -f /usr/local/bin/fazai-config + + # Remove diretórios (com confirmação) + read -p "Remover todos os dados do FazAI? (logs, configurações, etc.) [s/N]: " -n 1 -r + echo + if [[ $REPLY =~ ^[Ss]$ ]]; then + rm -rf /opt/fazai + rm -rf /etc/fazai + rm -rf /var/log/fazai + rm -rf /var/lib/fazai + echo "Todos os dados removidos." + else + echo "Dados preservados em /etc/fazai, /var/log/fazai e /var/lib/fazai" + fi + + # Remove usuário e grupo + userdel fazai 2>/dev/null + groupdel fazai 2>/dev/null + + # Remove sudoers + rm -f /etc/sudoers.d/fazai + + echo "FazAI desinstalado com sucesso!" +EOF + + chmod +x /opt/fazai/bin/uninstall.sh + ln -sf /opt/fazai/bin/uninstall.sh /usr/local/bin/fazai-uninstall + + # Script de backup + cat > /opt/fazai/bin/backup.sh << 'EOF' + #!/bin/bash + # FazAI Backup Script + + BACKUP_DIR="/tmp/fazai-backup-$(date +%Y%m%d-%H%M%S)" + mkdir -p "$BACKUP_DIR" + + echo "Criando backup em $BACKUP_DIR..." + + # Backup de configurações + cp -r /etc/fazai "$BACKUP_DIR/" + cp -r /var/lib/fazai "$BACKUP_DIR/" + + # Backup de logs (últimos 7 dias) + find /var/log/fazai -name "*.log" -mtime -7 -exec cp {} "$BACKUP_DIR/" \; + + # Compacta o backup + cd /tmp + tar -czf "fazai-backup-$(date +%Y%m%d-%H%M%S).tar.gz" "$(basename $BACKUP_DIR)" + rm -rf "$BACKUP_DIR" + + echo "Backup criado: /tmp/fazai-backup-$(date +%Y%m%d-%H%M%S).tar.gz" +EOF + + chmod +x /opt/fazai/bin/backup.sh + ln -sf /opt/fazai/bin/backup.sh /usr/local/bin/fazai-backup + + log "SUCCESS" "Scripts auxiliares criados" + } + + # Compila o worker Gemma usando o script interno + build_gemma_worker() { + log "INFO" "Compilando FazAI Gemma Worker" + if [ -d "worker" ]; then + pushd worker >/dev/null + ./build.sh || { log "ERROR" "Falha ao compilar worker"; popd >/dev/null; return 1; } + popd >/dev/null + log "SUCCESS" "Worker compilado e instalado em /opt/fazai/bin" + return 0 + else + log "ERROR" "Diretório worker não encontrado" + return 1 + fi + } + + # Função para configurar logrotate + configure_logrotate() { + log "INFO" "Configurando rotação de logs..." + + cat > /etc/logrotate.d/fazai << 'EOF' + /var/log/fazai/*.log { + daily + missingok + rotate 30 + compress + delaycompress + notifempty + create 644 fazai fazai + postrotate + systemctl reload fazai > /dev/null 2>&1 || true + endscript + } +EOF + + log "SUCCESS" "Configuração de logrotate criada" + } + + # Função para validar a instalação + validate_installation() { + log "INFO" "Validando instalação..." + + local validation_errors=0 + + # Verifica arquivos essenciais + local essential_files=( + "/opt/fazai/lib/main.js" + "/opt/fazai/bin/fazai" + "/etc/fazai/fazai.conf" + "/etc/fazai/complex_tasks.conf.default" + "/etc/systemd/system/fazai.service" + "/usr/local/bin/fazai" + "/opt/fazai/tools/fazai_web_frontend.html" + "/opt/fazai/tools/fazai_web.sh" + "/opt/fazai/tools/fazai_html_v1.sh" + "/opt/fazai/tools/auto_tool.js" + "/opt/fazai/tools/net_qos_monitor.js" + "/opt/fazai/tools/agent_supervisor.js" + "/opt/fazai/tools/qdrant_setup.js" + "/opt/fazai/tools/snmp_monitor.js" + "/opt/fazai/tools/modsecurity_setup.js" + "/opt/fazai/tools/suricata_setup.js" + "/opt/fazai/tools/crowdsec_setup.js" + "/opt/fazai/tools/monit_setup.js" + ) + + for file in "${essential_files[@]}"; do + if [ ! -f "$file" ]; then + log "ERROR" "Arquivo essencial não encontrado: $file" + validation_errors=$((validation_errors + 1)) + else + log "DEBUG" "Arquivo validado: $file" + fi + done + + # Verifica diretórios + local essential_dirs=( + "/opt/fazai" + "/etc/fazai" + "/var/log/fazai" + "/var/lib/fazai" + ) + + for dir in "${essential_dirs[@]}"; do + if [ ! -d "$dir" ]; then + log "ERROR" "Diretório essencial não encontrado: $dir" + validation_errors=$((validation_errors + 1)) + else + log "DEBUG" "Diretório validado: $dir" + fi + done + + # Verifica comandos + if ! command -v fazai &> /dev/null; then + log "ERROR" "Comando 'fazai' não está disponível" + validation_errors=$((validation_errors + 1)) + fi + + # Verifica serviço systemd + if ! systemctl is-enabled fazai &> /dev/null; then + log "WARNING" "Serviço fazai não está habilitado" + fi + + # Verifica dependências Node.js críticas + cd /opt/fazai + local critical_modules=("express" "winston") + for module in "${critical_modules[@]}"; do + if ! npm list "$module" &> /dev/null; then + log "WARNING" "Módulo Node.js crítico não encontrado: $module" + fi + done + + if [ $validation_errors -eq 0 ]; then + log "SUCCESS" "Validação da instalação concluída com sucesso!" + return 0 + else + log "ERROR" "Validação falhou com $validation_errors erro(s)" + return 1 + fi + } + + # Função para executar testes pós-instalação + run_post_install_tests() { + log "INFO" "Executando testes pós-instalação..." + + # Teste 1: Verifica se o CLI responde + log "DEBUG" "Testando CLI..." + if fazai --version &> /dev/null; then + log "SUCCESS" "Teste CLI: OK" + else + log "WARNING" "Teste CLI: Falhou" + fi + + # Teste 2: Verifica se o serviço pode ser iniciado + log "DEBUG" "Testando serviço systemd..." + if systemctl start fazai && sleep 2 && systemctl is-active fazai &> /dev/null; then + log "SUCCESS" "Teste serviço: OK" + systemctl stop fazai + else + log "WARNING" "Teste serviço: Falhou" + fi + + # Teste 3: Verifica permissões + log "DEBUG" "Testando permissões..." + if [ -r /etc/fazai/fazai.conf ] && [ -x /opt/fazai/bin/fazai ]; then + log "SUCCESS" "Teste permissões: OK" + else + log "WARNING" "Teste permissões: Falhou" + fi + + log "SUCCESS" "Testes pós-instalação concluídos" + } + + # Função para mostrar informações finais + show_installation_summary() { + log "INFO" "====== Resumo da Instalação ======" + + echo -e "\n${GREEN}✓ FazAI v$VERSION instalado com sucesso!${NC}\n" + + echo -e "${BLUE}Localização dos arquivos:${NC}" + echo " • Binários: /opt/fazai" + echo " • Configuração: /etc/fazai/fazai.conf" + echo " • Configuração de tarefas complexas: /etc/fazai/complex_tasks.conf.default" + echo " • Logs: /var/log/fazai" + echo " • Dados: /var/lib/fazai" + echo "" + + echo -e "${BLUE}Comandos disponíveis:${NC}" + echo " • fazai --help - Ajuda do sistema" + echo " • fazai --version - Versão instalada" + echo " • fazai --status - Status do daemon" + echo " • fazai web - Interface web com gerenciamento de logs" + + echo " • fazai logs [n] - Ver últimas n entradas de log" + echo " • fazai limpar-logs - Limpar logs (com backup)" + + echo " • fazai-backup - Criar backup" + echo " • fazai-uninstall - Desinstalar" + echo "" + + echo -e "${BLUE}Gerenciamento do serviço:${NC}" + echo " • systemctl start fazai - Iniciar" + echo " • systemctl stop fazai - Parar" + echo " • systemctl restart fazai - Reiniciar" + echo " • systemctl status fazai - Ver status" + echo "" + + echo -e "${YELLOW}Próximos passos:${NC}" + echo " 1. Configure suas API keys editando /etc/fazai/fazai.conf" + echo " 2. Inicie o serviço: systemctl start fazai" + echo " 3. Teste o sistema: fazai --status" + echo "" + + echo -e "${PURPLE}Para suporte e documentação:${NC}" + echo " • GitHub: https://github.com/RLuf/FazAI" + echo " • Logs: /var/log/fazai_install.log" + echo "" + + # Salva estado final + save_install_state "installation_complete" "success" + + log "SUCCESS" "====== Instalação Finalizada ======" + } + + # Função principal de instalação + main_install() { + log "INFO" "Iniciando instalação do FazAI v$VERSION" + + # Carrega estado anterior se existir + load_install_state + + # Executa etapas de instalação + local install_steps=( + "setup_logging:Configurando sistema de logs" + "check_root:Verificando permissões" + "check_system:Verificando sistema operacional" + "convert_files_to_unix:Convertendo arquivos para formato Linux" + "install_nodejs:Instalando Node.js" + "install_npm:Verificando npm" + "install_python:Instalando Python 3" + "install_gcc:Instalando ferramentas de compilação" + "ensure_container_runtime:Instalando runtime de contêiner (Docker)" + "create_directories:Criando estrutura de diretórios" + "build_gemma_worker:Compilando Gemma Worker" + "bootstrap_gemma:Instalando Gemma one-shot e pesos padrão" + "copy_files:Copiando arquivos" + "import_env_config:Importando configurações" + "configure_systemd:Configurando serviço systemd" + "install_node_dependencies:Instalando dependências Node.js" + "compile_native_modules:Compilando módulos nativos" + ) + + if [ "$WITH_LLAMA" = true ]; then + install_steps+=("install_llamacpp:Instalando llama.cpp") + fi + + install_steps+=( + + "configure_security:Configurando segurança" + "create_helper_scripts:Criando scripts auxiliares" + "configure_logrotate:Configurando rotação de logs" + "install_bash_completion:Instalando autocompletar" + ) + + local total_steps=${#install_steps[@]} + local current_step=0 + + for step_info in "${install_steps[@]}"; do + local step_function=$(echo "$step_info" | cut -d: -f1) + local step_description=$(echo "$step_info" | cut -d: -f2) + + current_step=$((current_step + 1)) + + # Verifica se já foi executado + if [ "${INSTALL_STATE[$step_function]}" = "completed" ]; then + log "INFO" "[$current_step/$total_steps] $step_description (já concluído)" + continue + fi + + log "INFO" "[$current_step/$total_steps] $step_description" + + # Executa a função + if $step_function; then + save_install_state "$step_function" "completed" + log "SUCCESS" "$step_description - Concluído" + else + log "ERROR" "$step_description - Falhou" + save_install_state "$step_function" "failed" + + if [ "$step_function" = "copy_files" ]; then + log "ERROR" "Falha ao copiar arquivos. Instalação interrompida. Verifique $LOG_FILE para detalhes." + ai_help "Falha ao copiar arquivos durante a instalação do FazAI" + exit 1 + fi + + # Consulta ajuda da IA e pergunta se deve continuar + ai_help "Erro na etapa '$step_description'" + read -p "Erro na etapa '$step_description'. Continuar mesmo assim? (s/N): " -n 1 -r + echo + if [[ ! $REPLY =~ ^[Ss]$ ]]; then + log "ERROR" "Instalação interrompida pelo usuário" + exit 1 + fi + fi + done + + # Validação e testes finais + log "INFO" "Executando validação final..." + if validate_installation; then + run_post_install_tests + show_installation_summary + + # Inicia o serviço se tudo estiver OK + if systemctl start fazai; then + log "SUCCESS" "Serviço FazAI iniciado com sucesso!" + # Health-check com autorreparo + health_check_repair + # Resumo da engine/módulo nativo, se o verificador existir + if [ -x "scripts/verify-engine.sh" ]; then + log "INFO" "Resumo de verificação pós-instalação:" + bash scripts/verify-engine.sh || true + fi + else + log "WARNING" "Falha ao iniciar o serviço. Inicie manualmente: systemctl start fazai" + fi + else + log "ERROR" "Validação da instalação falhou. Verifique os logs em $LOG_FILE" + exit 1 + fi + } + + # Função para limpeza em caso de interrupção + cleanup_on_exit() { + local exit_code=$? + if [ $exit_code -ne 0 ]; then + log "WARNING" "Instalação interrompida (código: $exit_code)" + log "INFO" "Estado salvo em $INSTALL_STATE_FILE" + log "INFO" "Execute novamente o script para continuar de onde parou" + fi + } + + # Captura sinais para limpeza + trap cleanup_on_exit EXIT INT TERM + + + # Verifica argumentos de linha de comando + while [[ $# -gt 0 ]]; do + case "$1" in + --debug) + DEBUG_MODE=true + log "INFO" "Modo debug ativado" + ;; + --clean) + rm -f "$INSTALL_STATE_FILE" + log "INFO" "Estado de instalação limpo" + ;; + --with-llama) + WITH_LLAMA=true + ;; + --help) + echo "FazAI Installer v$VERSION" + echo "Uso: $0 [opções]" + echo "" + echo "Opções:" + echo " --debug Ativa modo debug com logs detalhados" + echo " --clean Remove estado de instalação anterior" + echo " --with-llama Instala o mecanismo local llama.cpp" + echo " --help Mostra esta ajuda" + exit 0 + ;; + esac + shift + done + + # Inicia instalação principal + main_install + + log "SUCCESS" "Instalação do FazAI v2.0 concluída com sucesso!" + echo -e "\n${GREEN}🎉 FazAI v2.0 - Sistema de Fluxo Inteligente está pronto!${NC}" + echo -e "${CYAN}Novos recursos disponíveis:${NC}" + echo -e " 🤖 ${YELLOW}fazai agent${NC} - Agente inteligente cognitivo" + echo -e " 📊 ${YELLOW}fazai relay${NC} - Sistema de relay SMTP inteligente" + echo -e " 🔧 ${YELLOW}Edite /etc/fazai/fazai.conf${NC} - Configurar API keys" + echo -e " 📚 ${YELLOW}fazai manual${NC} - Manual completo" + echo -e "\n${GREEN}Exemplos de uso:${NC}" + echo -e " fazai agent \"configurar servidor de email relay com antispam\"" + echo -e " fazai relay analyze" + echo -e " fazai relay configure" + +exit 0 From beb7dd205530ecfc2cc8d110d6344c3080834cc5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 11 Oct 2025 22:54:26 +0000 Subject: [PATCH 3/4] Clean up temporary files from install.sh fixes Co-authored-by: RLuf <74881309+RLuf@users.noreply.github.com> --- install.sh.new | 2339 ----------------------------------------------- install.sh.new2 | 2296 ---------------------------------------------- 2 files changed, 4635 deletions(-) delete mode 100644 install.sh.new delete mode 100644 install.sh.new2 diff --git a/install.sh.new b/install.sh.new deleted file mode 100644 index 4a43c95..0000000 --- a/install.sh.new +++ /dev/null @@ -1,2339 +0,0 @@ -#!/bin/bash -set -e - -############################################################################### -# FazAI v2.0 Installer -# Sistema de Agente Inteligente Cognitivo e Persistente -############################################################################### - -# Variáveis globais -VERSION="2.0.0" -LOG_FILE="/var/log/fazai/install.log" -INSTALL_STATE_FILE="/var/log/fazai/install_state.txt" -DEBUG_MODE="${DEBUG_MODE:-false}" -WITH_LLAMA="${WITH_LLAMA:-false}" - -# Cores para output -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -PURPLE='\033[0;35m' -CYAN='\033[0;36m' -NC='\033[0m' # No Color - -# Array associativo para estado da instalação -declare -A INSTALL_STATE - -# Função de logging -log() { - local level="$1" - local message="$2" - local timestamp=$(date '+%Y-%m-%d %H:%M:%S') - - # Cria diretório de log se não existir - mkdir -p "$(dirname "$LOG_FILE")" - - # Escreve log ao arquivo - echo "[$timestamp] [$level] $message" >> "$LOG_FILE" - - # Mostra no console com cores - case $level in - "INFO") - echo -e "${BLUE}[INFO]${NC} $message" - ;; - "SUCCESS") - echo -e "${GREEN}[SUCESSO]${NC} $message" - ;; - "ERROR") - echo -e "${RED}[ERRO]${NC} $message" - ;; - "WARNING") - echo -e "${YELLOW}[AVISO]${NC} $message" - ;; - "DEBUG") - if [ "$DEBUG_MODE" = true ]; then - echo -e "${PURPLE}[DEBUG]${NC} $message" - fi - ;; - esac -} - -# Verifica root -if [[ $EUID -ne 0 ]]; then - log "ERROR" "Execute como root: sudo ./install.sh" - exit 1 -fi -RestartSec=5 -StandardOutput=journal -StandardError=journal - -[Install] -WantedBy=multi-user.target -EOF - -# Habilita e inicia serviço -systemctl daemon-reload -systemctl enable fazai-gemma-worker -systemctl start fazai-gemma-worker - -echo "✅ FazAI v2.0 instalado com sucesso!" -echo "📍 Teste: fazai ask 'olá mundo'" -echo "📍 Status: systemctl status fazai-gemma-worker" -echo "📍 Logs: journalctl -u fazai-gemma-worker -f" - mkdir -p $(dirname $LOG_FILE) - - # Escreve log ao arquivo - echo "[$timestamp] [$level] $message" >> $LOG_FILE - - # Mostra no console com cores - case $level in - "INFO") - echo -e "${BLUE}[INFO]${NC} $message" - ;; - "SUCCESS") - echo -e "${GREEN}[SUCESSO]${NC} $message" - ;; - "ERROR") - echo -e "${RED}[ERRO]${NC} $message" - ;; - "WARNING") - echo -e "${YELLOW}[AVISO]${NC} $message" - ;; - "DEBUG") - if [ "$DEBUG_MODE" = true ]; then - echo -e "${PURPLE}[DEBUG]${NC} $message" - fi - ;; - esac -} -# Consulta ajuda da IA em caso de erro (simplificada) -ai_help() { - local prompt="$1" - log "INFO" "Erro detectado: $prompt" - log "INFO" "Verifique os logs em $LOG_FILE para mais detalhes" -} - - -# Função para salvar estado da instalação -save_install_state() { - local step=$1 - local status=$2 - INSTALL_STATE["$step"]="$status" - mkdir -p $(dirname "$INSTALL_STATE_FILE") - - # Limpa o arquivo antes de reescrever - > "$INSTALL_STATE_FILE" - for key in "${!INSTALL_STATE[@]}"; do - echo "$key=${INSTALL_STATE[$key]}" >> "$INSTALL_STATE_FILE" - done - log "DEBUG" "Estado salvo: $step = $status" -} - -# Função para carregar estado da instalação -load_install_state() { - if [ -f "$INSTALL_STATE_FILE" ]; then - while IFS='=' read -r key value; do - if [ -n "$key" ] && [ -n "$value" ]; then - INSTALL_STATE["$key"]="$value" - fi - done < "$INSTALL_STATE_FILE" - log "INFO" "Estado da instalação carregado de $INSTALL_STATE_FILE" - fi -} - -# Função para verificar versão de uma dependência -check_dependency_version() { - local cmd=$1 - local min_version=$2 - - if ! command -v "$cmd" &> /dev/null; then - log "DEBUG" "Comando $cmd não encontrado" - return 1 - fi - - local current_version - case $cmd in - "node") - current_version=$(node -v | sed 's/v//') - ;; - "npm") - current_version=$(npm -v) - ;; - "python3") - current_version=$(python3 --version | awk '{print $2}') - ;; - "pip3") - current_version=$(pip3 --version | awk '{print $2}') - ;; - "gcc") - current_version=$(gcc --version | head -n1 | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -n1) - ;; - *) - current_version=$($cmd --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -n1) - ;; - esac - - if [ -z "$current_version" ]; then - log "WARNING" "Não foi possível determinar a versão de $cmd" - return 2 - fi - - # Comparação de versões usando sort -V - if printf '%s\n' "$min_version" "$current_version" | sort -V | head -n1 | grep -q "^$min_version$"; then - log "SUCCESS" "$cmd versão $current_version atende requisito mínimo ($min_version)" - return 0 - else - log "WARNING" "$cmd versão $current_version é menor que a mínima requerida ($min_version)" - return 3 - fi -} - -# Função para converter arquivos para formato Linux (dos2unix) -convert_files_to_unix() { - log "INFO" "Convertendo arquivos para formato Linux..." - - # Instala dos2unix se não estiver disponível - if ! command -v dos2unix &> /dev/null; then - log "INFO" "Instalando dos2unix..." - apt-get update && apt-get install -y dos2unix - - if ! command -v dos2unix &> /dev/null; then - log "WARNING" "dos2unix não pôde ser instalado. Tentando método alternativo..." - # Método alternativo usando sed - convert_with_sed() { - local file="$1" - if [ -f "$file" ]; then - sed -i 's/\r$//' "$file" 2>/dev/null - if [ $? -eq 0 ]; then - log "DEBUG" "Convertido com sed: $file" - else - log "WARNING" "Falha ao converter: $file" - fi - fi - } - - # Converte arquivos críticos usando sed - find . -type f \( -name "*.sh" -o -name "*.bash" -o -name "*.conf" \) -exec bash -c 'convert_with_sed "$0"' {} \; - log "SUCCESS" "Conversão concluída usando método alternativo" - return 0 - fi - fi - - # Executa o script dos2unixAll.sh se existir - if [ -f "etc/fazai/dos2unixAll.sh" ]; then - log "INFO" "Executando script dos2unixAll.sh..." - chmod +x "etc/fazai/dos2unixAll.sh" - cd "$(dirname "$(readlink -f "$0")")" || cd /opt/fazai - bash etc/fazai/dos2unixAll.sh - log "SUCCESS" "Script dos2unixAll.sh executado" - else - log "INFO" "Script dos2unixAll.sh não encontrado. Executando conversão manual..." - - # Encontra e converte todos os arquivos relevantes - find . -type f \ - \( -name "*.sh" \ - -o -name "*.bash" \ - -o -name "*.conf" \ - -o -name "*.yml" \ - -o -name "*.yaml" \ - -o -name "*.json" \ - -o -name "Dockerfile" \) \ - -exec sh -c ' - for file do - echo "🔄 Convertendo: $file" - dos2unix "$file" 2>/dev/null - if [ $? -eq 0 ]; then - echo "✅ Convertido com sucesso: $file" - else - echo "❌ Erro ao converter: $file" - fi - done - ' sh {} + - fi - - log "SUCCESS" "Conversão de arquivos para formato Linux concluída" -} - -# Função para instalar bash completion -install_bash_completion() { - log "INFO" "Instalando bash completion..." - - # Verifica se o bash-completion está instalado - if ! dpkg -l | grep -q bash-completion 2>/dev/null; then - log "INFO" "Instalando pacote bash-completion..." - apt-get update && apt-get install -y bash-completion - fi - - local completion_dir="/etc/bash_completion.d" - mkdir -p "$completion_dir" - - if [ -f "etc/fazai/fazai-completion.sh" ]; then - cp "etc/fazai/fazai-completion.sh" "$completion_dir/fazai" - else - log "WARNING" "etc/fazai/fazai-completion.sh não encontrado, gerando script simples" - cat > "$completion_dir/fazai" <<'EOF' -#!/bin/bash -complete -W "install uninstall status config help version" fazai -EOF - fi - chmod 644 "$completion_dir/fazai" - log "SUCCESS" "Script de completion instalado em $completion_dir/fazai" - - # Adiciona ao .bashrc se não existir - if ! grep -q "source $completion_dir/fazai" /root/.bashrc 2>/dev/null; then - echo "# FazAI bash completion" >> /root/.bashrc - echo "if [ -f /etc/bash_completion ]; then" >> /root/.bashrc - echo " source /etc/bash_completion" >> /root/.bashrc - echo "fi" >> /root/.bashrc - echo "source $completion_dir/fazai" >> /root/.bashrc - log "SUCCESS" "Bash completion configurado no .bashrc" - fi -} - -# Função para verificar e criar diretório de logs -setup_logging() { - mkdir -p $(dirname $LOG_FILE) - touch $LOG_FILE - log "INFO" "Inicializando log de instalação em $LOG_FILE" - log "INFO" "====== Início da instalação do FazAI v$VERSION ======" - log "INFO" "Data e hora: $(date)" - log "INFO" "Sistema: $(uname -a)" -} - -# Função para verificar permissões de root -check_root() { - log "DEBUG" "Verificando permissões de root..." - if [ "$EUID" -ne 0 ]; then - log "ERROR" "Este script precisa ser executado como root (sudo)." - exit 1 - fi - log "SUCCESS" "Verificação de permissões de root concluída." -} - -# Função para verificar o sistema operacional -check_system() { - log "DEBUG" "Verificando sistema operacional..." - if [ -f /etc/os-release ]; then - . /etc/os-release - # Trata derivados como Ubuntu (ex.: Pop!_OS) - if echo "${ID_LIKE:-}" | grep -qi ubuntu; then - ID=ubuntu - fi - case "$ID" in - debian|ubuntu|pop) - log "SUCCESS" "Sistema Debian/Ubuntu detectado: $NAME $VERSION_ID" - ;; - fedora|rhel|centos) - log "SUCCESS" "Sistema Fedora/RedHat/CentOS detectado: $NAME $VERSION_ID" - ;; - *) - log "WARNING" "Este script foi projetado para Debian, Ubuntu ou Fedora. Detectado: $NAME $VERSION_ID." - read -p "Deseja continuar mesmo assim? (s/n): " -n 1 -r - echo - if [[ ! $REPLY =~ ^[Ss]$ ]]; then - log "INFO" "Instalação cancelada pelo usuário." - exit 1 - fi - log "WARNING" "Prosseguindo instalação em sistema não suportado oficialmente." - ;; - esac - else - log "WARNING" "Não foi possível detectar o sistema operacional. Prosseguindo com cautela." - fi -} - -# Garante runtime de contêiner (Docker) para serviços opcionais (Qdrant/Prometheus/Grafana) -ensure_container_runtime() { - if command -v docker >/dev/null 2>&1 || command -v podman >/dev/null 2>&1; then - log "INFO" "Runtime de contêiner já disponível" - return 0 - fi - log "INFO" "Instalando Docker (runtime de contêiner)" - if command -v apt-get >/dev/null 2>&1; then - apt-get update && apt-get install -y docker.io || log "WARNING" "Falha ao instalar Docker (apt)." - systemctl enable --now docker || true - elif command -v dnf >/dev/null 2>&1; then - dnf install -y docker || log "WARNING" "Falha ao instalar Docker (dnf)." - systemctl enable --now docker || true - elif command -v yum >/dev/null 2>&1; then - yum install -y docker || log "WARNING" "Falha ao instalar Docker (yum)." - systemctl enable --now docker || true - elif command -v zypper >/dev/null 2>&1; then - zypper install -y docker || log "WARNING" "Falha ao instalar Docker (zypper)." - systemctl enable --now docker || true - else - log "WARNING" "Gerenciador de pacotes não suportado para instalação automática do Docker." - fi -} - -# Garantir utilitários de rede usados por scripts e testes -ensure_network_utils() { - log "INFO" "Verificando utilitários de rede (curl, jq, netcat)" - local pkgs=(curl jq netcat) - for p in "${pkgs[@]}"; do - if ! command -v "$p" &>/dev/null; then - log "INFO" "Instalando $p" - if command -v apt-get &>/dev/null; then - apt-get update && apt-get install -y $p || { log "WARNING" "Falha ao instalar $p"; } - elif command -v dnf &>/dev/null; then - dnf install -y $p || { log "WARNING" "Falha ao instalar $p"; } - else - log "WARNING" "Gerenciador de pacotes não detectado; instale $p manualmente" - fi - else - log "DEBUG" "$p já presente" - fi - done -} - -# Função para instalar Node.js com retry e múltiplas versões -install_nodejs() { - if command -v node &> /dev/null; then - NODE_VERSION=$(node -v) - log "SUCCESS" "Node.js já instalado: $NODE_VERSION" - - # Verifica versão mínima do Node.js (>=22.0.0) - NODE_VERSION_NUM=$(echo $NODE_VERSION | cut -c 2-) - NODE_MAJOR=$(echo $NODE_VERSION_NUM | cut -d. -f1) - - if [ $NODE_MAJOR -lt 22 ]; then - log "WARNING" "FazAI requer Node.js versão 22.0.0 ou superior. Versão atual: $NODE_VERSION" - log "INFO" "Tentando atualizar o Node.js..." - install_nodejs_from_source - fi - else - log "WARNING" "Node.js não encontrado. Iniciando instalação..." - install_nodejs_from_source - fi -} - -# Função para instalar Node.js a partir de diferentes fontes -install_nodejs_from_source() { - local success=false - # Detecta gerenciador de pacotes - local PKG_MGR="apt-get" - if [ -f /etc/os-release ]; then - . /etc/os-release - case "$ID" in - fedora|rhel|centos) - PKG_MGR="dnf" - ;; - *) - PKG_MGR="apt-get" - ;; - esac - fi - log "INFO" "Atualizando lista de pacotes..." - $PKG_MGR update -y - $PKG_MGR autoremove -y - $PKG_MGR upgrade -y - log "INFO" "Tentando instalar Node.js via $PKG_MGR..." - $PKG_MGR install -y nodejs npm - if command -v node &> /dev/null; then - NODE_VERSION=$(node -v) - NODE_VERSION_NUM=$(echo $NODE_VERSION | cut -c 2-) - NODE_MAJOR=$(echo $NODE_VERSION_NUM | cut -d. -f1) - if [ $NODE_MAJOR -ge 22 ]; then - log "SUCCESS" "Node.js instalado com sucesso via $PKG_MGR: $NODE_VERSION" - success=true - return 0 - else - log "WARNING" "Versão do Node.js instalada via $PKG_MGR é muito antiga: $NODE_VERSION" - fi - else - log "WARNING" "Falha ao instalar Node.js via $PKG_MGR." - fi - # Tenta instalar via NodeSource para diferentes versões (apenas para Debian/Ubuntu) - if [ "$success" = false ] && [ "$PKG_MGR" = "apt-get" ]; then - if ! command -v curl &> /dev/null; then - $PKG_MGR install -y curl - fi - for version in "${NODE_VERSIONS[@]}"; do - log "INFO" "Tentando instalar Node.js v$version via NodeSource..." - for attempt in $(seq 1 $RETRY_COUNT); do - log "DEBUG" "Tentativa $attempt de $RETRY_COUNT para Node.js v$version" - if curl -fsSL "https://deb.nodesource.com/setup_${version}.x" | bash - && $PKG_MGR install -y nodejs; then - if command -v node &> /dev/null; then - NODE_VERSION=$(node -v) - log "SUCCESS" "Node.js instalado com sucesso: $NODE_VERSION" - success=true - break 2 - fi - fi - log "WARNING" "Tentativa $attempt falhou para Node.js v$version" - sleep 2 - done - done - fi - if [ "$success" = false ]; then - log "ERROR" "Todas as tentativas de instalação do Node.js falharam." - log "ERROR" "Por favor, instale o Node.js manualmente e execute este script novamente." - log "ERROR" "Visite: https://nodejs.org/en/download/package-manager/" - exit 1 - fi -} - -# Função para verificar e instalar npm -install_npm() { - local PKG_MGR="apt-get" - if [ -f /etc/os-release ]; then - . /etc/os-release - case "$ID" in - fedora|rhel|centos) - PKG_MGR="dnf" - ;; - *) - PKG_MGR="apt-get" - ;; - esac - fi - if ! command -v npm &> /dev/null; then - log "WARNING" "npm não encontrado. Instalando..." - $PKG_MGR install -y npm - if ! command -v npm &> /dev/null; then - log "ERROR" "Falha ao instalar npm via $PKG_MGR." - exit 1 - else - NPM_VERSION=$(npm -v) - log "SUCCESS" "npm instalado com sucesso: $NPM_VERSION" - fi - else - NPM_VERSION=$(npm -v) - log "SUCCESS" "npm já instalado: $NPM_VERSION" - fi -} - -# Função para verificar e instalar Python 3 -install_python() { - local PKG_MGR="apt-get" - if [ -f /etc/os-release ]; then - . /etc/os-release - case "$ID" in - fedora|rhel|centos) - PKG_MGR="dnf" - ;; - *) - PKG_MGR="apt-get" - ;; - esac - fi - if command -v python3 &> /dev/null; then - PYTHON_VERSION=$(python3 --version | awk '{print $2}') - PYTHON_MAJOR=$(echo "$PYTHON_VERSION" | cut -d. -f1) - PYTHON_MINOR=$(echo "$PYTHON_VERSION" | cut -d. -f2) - if [ "$PYTHON_MAJOR" -lt 3 ] || { [ "$PYTHON_MAJOR" -eq 3 ] && [ "$PYTHON_MINOR" -lt 10 ]; }; then - log "WARNING" "FazAI requer Python 3.10 ou superior. Versão atual: $PYTHON_VERSION" - $PKG_MGR install -y python3 python3-pip - fi - else - log "WARNING" "Python3 não encontrado. Instalando..." - $PKG_MGR install -y python3 python3-pip - fi - if command -v python3 &> /dev/null; then - PYTHON_VERSION=$(python3 --version | awk '{print $2}') - log "SUCCESS" "python3 instalado: $PYTHON_VERSION" - else - log "ERROR" "Falha ao instalar python3." - exit 1 - fi -} - -# Função para verificar e instalar gcc -install_gcc() { - local PKG_MGR="apt-get" - if [ -f /etc/os-release ]; then - . /etc/os-release - case "$ID" in - fedora|rhel|centos) - PKG_MGR="dnf" - ;; - *) - PKG_MGR="apt-get" - ;; - esac - fi - if ! command -v gcc &> /dev/null; then - log "WARNING" "gcc não encontrado. Instalando build-essential..." - $PKG_MGR install -y gcc g++ make cmake - if ! command -v gcc &> /dev/null; then - log "ERROR" "Falha ao instalar gcc. Por favor, instale manualmente." - exit 1 - fi - GCC_VERSION=$(gcc --version | head -n1) - CMAKE_VERSION=$(cmake --version 2>/dev/null | head -n1) - log "SUCCESS" "gcc instalado com sucesso: $GCC_VERSION" - [ -n "$CMAKE_VERSION" ] && log "SUCCESS" "cmake disponível: $CMAKE_VERSION" - else - GCC_VERSION=$(gcc --version | head -n1) - CMAKE_VERSION=$(cmake --version 2>/dev/null | head -n1) - log "SUCCESS" "gcc já instalado: $GCC_VERSION" - [ -n "$CMAKE_VERSION" ] && log "SUCCESS" "cmake disponível: $CMAKE_VERSION" - fi -} - - - -# Função para criar estrutura de diretórios -create_directories() { - log "INFO" "Criando estrutura de diretórios..." - - # Garante a criação do diretório de logs - if [ ! -d "/var/log/fazai" ]; then - mkdir -p "/var/log/fazai" - log "SUCCESS" "Diretório /var/log/fazai criado" - fi - - local directories=( - "/opt/fazai/bin" - "/opt/fazai/lib" - "/opt/fazai/tools" - "/opt/fazai/mods" - " /opt/fazai/models" - "/etc/fazai" - "/var/log/fazai" - "/var/lib/fazai/history" - "/var/lib/fazai/cache" - "/var/lib/fazai/data" - "/var/backups/fazai" - ) - - for dir in "${directories[@]}"; do - if [ ! -d "$dir" ]; then - mkdir -p "$dir" - log "DEBUG" "Diretório criado: $dir" - else - log "DEBUG" "Diretório já existe: $dir" - fi - done - # Diretório de segredos OPNsense (permissões estritas) - mkdir -p /etc/fazai/secrets/opnsense && chmod 700 /etc/fazai/secrets/opnsense || true - - # Garantir diretório de modelos com permissões apropriadas - if [ ! -d "/opt/fazai/models" ]; then - mkdir -p /opt/fazai/models - chown root:root /opt/fazai/models - chmod 755 /opt/fazai/models - log "DEBUG" "Diretório /opt/fazai/models criado" - fi - - log "SUCCESS" "Estrutura de diretórios criada com sucesso." -} - -# Verifica saúde do serviço e tenta autorreparo básico -health_check_repair() { - log "INFO" "Executando health-check do FazAI (/agent/status)" - local API="http://127.0.0.1:3120" - local ok=false - for attempt in 1 2 3; do - if curl -fsS --max-time 3 "$API/agent/status" >/dev/null 2>&1; then - ok=true - break - fi - log "WARNING" "Health-check falhou (tentativa $attempt). Tentando reparo..." - # Reinicia o worker e o serviço mestre - systemctl restart fazai-gemma-worker 2>/dev/null || true - sleep 1 - # Garante diretório do socket - mkdir -p /run/fazai && chmod 755 /run/fazai || true - systemctl restart fazai 2>/dev/null || true - sleep 2 - # Se o binário do worker não existir, tenta compilar/instalar - if [ ! -x "/opt/fazai/bin/fazai-gemma-worker" ] && [ -d "worker" ] && [ -f "worker/CMakeLists.txt" ]; then - log "INFO" "Binário do worker ausente; tentando compilar/instalar..." - (cd worker && ./build.sh && sudo make install) || true - systemctl restart fazai-gemma-worker 2>/dev/null || true - sleep 1 - fi - done - if [ "$ok" = true ]; then - log "SUCCESS" "Health-check OK: /agent/status respondeu" - else - log "ERROR" "Health-check ainda falhou após tentativas de reparo. Verifique logs do serviço." - fi -} - -# Função para copiar arquivos -copy_files() { - log "INFO" "Copiando arquivos para diretórios de instalação..." - - local copy_errors=0 - - # Cria função auxiliar para cópia com verificação de erros - copy_with_verification() { - local source=$1 - local destination=$2 - local description=$3 - - if [ ! -e "$source" ]; then - log "ERROR" "Arquivo de origem ausente para $description: $source" - return 1 - fi - - local output - if output=$(cp -r "$source" "$destination" 2>&1); then - local dest_path="$destination" - if [ -d "$destination" ]; then - dest_path="$destination/$(basename "$source")" - fi - if [ -e "$dest_path" ]; then - log "DEBUG" "$description copiado de $source para $destination" - return 0 - else - log "ERROR" "Arquivo não encontrado após copiar $source para $destination" - return 1 - fi - else - log "ERROR" "Falha ao copiar $description ($source -> $destination): $output" - return 1 - fi - } - - - - # Cria CLI básico se não existir - if [ ! -f "bin/fazai" ]; then - log "INFO" "Criando CLI básico..." - mkdir -p "bin" - cat > "bin/fazai" << 'EOF' -#!/usr/bin/env node - -/** - * FazAI CLI - */ - -const { spawn } = require('child_process'); -const fs = require('fs'); - -const args = process.argv.slice(2); - -if (args.includes('--version')) { - console.log('FazAI v2.0.0'); - process.exit(0); -} - -if (args.includes('--help')) { - console.log('FazAI - Orquestrador Inteligente de Automação'); - console.log(''); - console.log('Uso: fazai [comando] [opções]'); - console.log(''); - console.log('Comandos:'); - console.log(' --version Mostra a versão'); - console.log(' --help Mostra esta ajuda'); - console.log(' --status Status do daemon'); - console.log(' --start Inicia o daemon'); - console.log(' --stop Para o daemon'); - console.log(' --restart Reinicia o daemon'); - process.exit(0); -} - -if (args.includes('--status')) { - const { execSync } = require('child_process'); - try { - const status = execSync('systemctl is-active fazai', { encoding: 'utf8' }).trim(); - console.log(`FazAI daemon: ${status}`); - } catch (error) { - console.log('FazAI daemon: inativo'); - } - process.exit(0); -} - -console.log('FazAI CLI v2.0.0 - Use --help para mais informações'); -EOF - chmod +x "bin/fazai" - fi - - # Garante que o arquivo de configuração exemplo exista - if [ ! -f "etc/fazai/fazai.conf.example" ]; then - log "ERROR" "etc/fazai/fazai.conf.example não encontrado. Verifique o repositório." - exit 1 - fi - - # Agora copia os arquivos - # Copia toda a biblioteca (inclui handlers, core, providers, etc.) - if ! copy_with_verification "opt/fazai/lib" "/opt/fazai/" "Biblioteca FazAI"; then - copy_errors=$((copy_errors+1)) - else - # Garante permissão de execução no entrypoint - chmod 755 /opt/fazai/lib/main.js 2>/dev/null || true - fi - - - - # Copia módulos e integrações adicionais necessários - for f in \ - "opt/fazai/lib/mcp_opnsense.js" \ - "opt/fazai/lib/complex_tasks.js" \ - "opt/fazai/tools/fazai_web_frontend.html" \ - "opt/fazai/tools/web_search.js" \ - "opt/fazai/tools/suricata_setup.js" \ - "opt/fazai/tools/modsecurity_setup.js" \ - "opt/fazai/tools/crowdsec_setup.js" \ - "opt/fazai/tools/spamexperts.js" \ - "opt/fazai/tools/cloudflare.js" \ - ; do - if [ -f "$f" ]; then - if ! copy_with_verification "$f" "/opt/fazai/$(dirname ${f#opt/fazai/})/" "$(basename $f)"; then - copy_errors=$((copy_errors+1)) - fi - fi - done - - # Copia todas as ferramentas para garantir que plugins sejam carregados - if [ -d "opt/fazai/tools" ]; then - if ! copy_with_verification "opt/fazai/tools" "/opt/fazai/" "Ferramentas FazAI"; then - copy_errors=$((copy_errors+1)) - fi - fi - - # Copia interface web (DOCLER) - if [ -d "opt/fazai/web" ]; then - if ! copy_with_verification "opt/fazai/web" "/opt/fazai/" "Interface Web"; then - copy_errors=$((copy_errors+1)) - fi - # Instalar dependências do web server (express, ws) - if [ -f "/opt/fazai/web/package.json" ]; then - log "INFO" "Instalando dependências da interface web (/opt/fazai/web)" - (cd /opt/fazai/web && npm install --omit=dev --no-audit --no-progress || true) - # Tenta instalar autenticação PAM (opcional) - (cd /opt/fazai/web && npm install authenticate-pam --no-audit --no-progress || true) - fi - - # Cria usuário de serviço não-root para o Docler - if ! id -u fazai-web >/dev/null 2>&1; then - log "INFO" "Criando usuário de serviço 'fazai-web' (sem shell de login)" - useradd --system --home /opt/fazai/web --shell /usr/sbin/nologin fazai-web || true - fi - # Corrige permissões para acesso do usuário fazai-web - chmod 755 /opt/fazai || true - chmod 755 /opt/fazai/web || true - chown -R fazai:fazai-web /opt/fazai/web || true - chmod -R g+rx /opt/fazai/web || true - fi - - # Instalar Qdrant Vector Database - log "INFO" "Instalando Qdrant Vector Database..." - if [ ! -f "/opt/fazai/bin/qdrant" ]; then - log "INFO" "Baixando Qdrant binário..." - if curl -L https://github.com/qdrant/qdrant/releases/latest/download/qdrant-x86_64-unknown-linux-gnu.tar.gz -o /tmp/qdrant.tar.gz 2>/dev/null; then - tar -xzf /tmp/qdrant.tar.gz -C /opt/fazai/bin/ 2>/dev/null || log "WARN" "Falha ao extrair Qdrant - usando Docker fallback" - chmod +x /opt/fazai/bin/qdrant 2>/dev/null || true - rm -f /tmp/qdrant.tar.gz - log "INFO" "Qdrant binário instalado" - else - log "WARN" "Falha no download do Qdrant - será usado via Docker" - fi - fi - - # Criar diretórios e configuração do Qdrant - mkdir -p /var/lib/qdrant /opt/fazai/web/static - chown -R fazai:fazai /var/lib/qdrant - - # Configuração Qdrant - cat > /etc/fazai/qdrant.yaml << 'EOF' -log_level: INFO -storage: - storage_path: /var/lib/qdrant/storage - snapshots_path: /var/lib/qdrant/snapshots - on_disk_payload: true - -service: - http_port: 6333 - grpc_port: 6334 - host: 0.0.0.0 - max_request_size_mb: 32 - max_workers: 0 - static_content_dir: /opt/fazai/web/static - enable_cors: true - -web_ui: - enabled: true - -cluster: - enabled: false - -telemetry_disabled: false -EOF - - # Copia binários auxiliares (inclui fazai-gemma-worker e utilitários) - if [ -d "opt/fazai/bin" ]; then - if ! copy_with_verification "opt/fazai/bin" "/opt/fazai/" "Binários FazAI"; then - copy_errors=$((copy_errors+1)) - else - chmod -R 755 /opt/fazai/bin 2>/dev/null || true - fi - fi - - # Copia modelos Gemma se estiverem no repositório (estrutura antiga) - if [ -d "opt/fazai/models/gemma" ]; then - if ! copy_with_verification "opt/fazai/models/gemma" "/opt/fazai/models/" "Modelos Gemma"; then - copy_errors=$((copy_errors+1)) - fi - else - # Nova estrutura: pesos e tokenizer embarcados junto ao fonte - # Preferir em worker/src/gemma.cpp/, fallback para gemma.cpp/ na raiz - SRC_DIR="" - if [ -f "worker/src/gemma.cpp/2.0-2b-it-sfp.sbs" ] || [ -f "worker/src/gemma.cpp/tokenizer.spm" ]; then - SRC_DIR="worker/src/gemma.cpp" - elif [ -f "gemma.cpp/2.0-2b-it-sfp.sbs" ] || [ -f "gemma.cpp/tokenizer.spm" ]; then - SRC_DIR="gemma.cpp" - fi - if [ -n "$SRC_DIR" ]; then - mkdir -p /opt/fazai/models/gemma - if [ -f "$SRC_DIR/2.0-2b-it-sfp.sbs" ]; then - log "INFO" "Copiando pesos Gemma de $SRC_DIR para /opt/fazai/models/gemma/" - cp -f "$SRC_DIR/2.0-2b-it-sfp.sbs" "/opt/fazai/models/gemma/" || copy_errors=$((copy_errors+1)) - fi - if [ -f "$SRC_DIR/tokenizer.spm" ]; then - log "INFO" "Copiando tokenizer Gemma de $SRC_DIR para /opt/fazai/models/gemma/" - cp -f "$SRC_DIR/tokenizer.spm" "/opt/fazai/models/gemma/" || copy_errors=$((copy_errors+1)) - fi - chmod 644 /opt/fazai/models/gemma/* 2>/dev/null || true - - # Atualiza fazai.conf com caminhos detectados - if [ -f "/etc/fazai/fazai.conf" ]; then - WEIGHTS_PATH="/opt/fazai/models/gemma/2.0-2b-it-sfp.sbs" - TOKENIZER_PATH="/opt/fazai/models/gemma/tokenizer.spm" - if [ -f "$WEIGHTS_PATH" ]; then - sed -i "/^\[gemma_cpp\]/,/^\[/ s|^weights\s*=.*|weights = $WEIGHTS_PATH|" /etc/fazai/fazai.conf || true - fi - if [ -f "$TOKENIZER_PATH" ]; then - sed -i "/^\[gemma_cpp\]/,/^\[/ s|^tokenizer\s*=.*|tokenizer = $TOKENIZER_PATH|" /etc/fazai/fazai.conf || true - fi - sed -i "/^\[gemma_cpp\]/,/^\[/ s|^endpoint\s*=.*|endpoint = /opt/fazai/bin/gemma_oneshot|" /etc/fazai/fazai.conf || true - sed -i "/^\[gemma_cpp\]/,/^\[/ s|^default_model\s*=.*|default_model = gemma2-2b-it|" /etc/fazai/fazai.conf || true - fi - else - # Fallback: caminho externo informado pelo usuário - if [ -d "/media/rluft/fedora/root/opt/fazai/models/gemma" ]; then - if ! copy_with_verification "/media/rluft/fedora/root/opt/fazai/models/gemma" "/opt/fazai/models/" "Modelos Gemma (externo)"; then - copy_errors=$((copy_errors+1)) - fi - fi - fi - fi - - # Compila e instala o binário real gemma_oneshot se as fontes estiverem em worker/src/gemma.cpp - if [ -d "worker/src/gemma.cpp" ] && [ -f "worker/src/gemma.cpp/CMakeLists.txt" ]; then - log "INFO" "Compilando gemma.cpp (gemma_oneshot) a partir de worker/src/gemma.cpp..." - ( - cd worker/src/gemma.cpp - mkdir -p build - cd build - cmake .. -DCMAKE_BUILD_TYPE=Release || true - make -j$(nproc) gemma_oneshot || make gemma_oneshot || true - ) - if [ -x "worker/src/gemma.cpp/build/gemma_oneshot" ]; then - install -m 0755 "worker/src/gemma.cpp/build/gemma_oneshot" "/opt/fazai/bin/gemma_oneshot.real" || true - log "SUCCESS" "gemma_oneshot.real instalado em /opt/fazai/bin" - else - log "WARNING" "Falha ao compilar gemma_oneshot. O wrapper tentará outros caminhos se existir um binário no sistema." - fi - fi - - # DeepSeek helper removido (no-op) - - if ! copy_with_verification "etc/fazai/fazai.conf.example" "/etc/fazai/fazai.conf.default" "Configuração padrão"; then - copy_errors=$((copy_errors+1)) - fi - - # Preserva configuracao atual antes de substituir - if [ -f "/etc/fazai/fazai.conf" ]; then - cp /etc/fazai/fazai.conf /etc/fazai/fazai.conf.bak && \ - log "INFO" "Backup criado em fazai.conf.bak" - mv /etc/fazai/fazai.conf /etc/fazai/fazai.conf.old - log "INFO" "Configuração existente renomeada para fazai.conf.old" - fi - - if ! copy_with_verification "etc/fazai/fazai.conf.example" "/etc/fazai/fazai.conf" "Configuração de sistema"; then - copy_errors=$((copy_errors+1)) - else - log "SUCCESS" "Novo arquivo de configuração criado em /etc/fazai/fazai.conf" - - if [ -f "/etc/fazai/fazai.conf.old" ]; then - for prov in openrouter requesty openai; do - key_val=$(awk -v sec="[$prov]" '$0==sec{f=1;next} /^\[/{f=0} f && /api_key/{print $3}' /etc/fazai/fazai.conf.old) - if [ -n "$key_val" ]; then - sed -i "/^\[$prov\]/,/^$/s|api_key =.*|api_key = $key_val|" /etc/fazai/fazai.conf - fi - done - fi - if [ -f "/root/.env" ]; then - /bin/bash /opt/fazai/tools/sync-keys.sh >/dev/null 2>&1 && log "INFO" "Chaves sincronizadas do .env" - fi - fi - - # Copia gemma_bootstrap - if [ -f "opt/fazai/tools/gemma_bootstrap.sh" ]; then - if ! copy_with_verification "opt/fazai/tools/gemma_bootstrap.sh" "/opt/fazai/tools/" "Gemma bootstrap"; then - copy_errors=$((copy_errors+1)) - else - chmod +x /opt/fazai/tools/gemma_bootstrap.sh - log "SUCCESS" "Gemma bootstrap instalado" - fi - fi - - # Copia complex_tasks.conf.example se existir - if [ -f "etc/fazai/complex_tasks.conf.example" ]; then - if ! copy_with_verification "etc/fazai/complex_tasks.conf.example" "/etc/fazai/complex_tasks.conf.default" "Configuração de tarefas complexas"; then - copy_errors=$((copy_errors+1)) - else - log "SUCCESS" "Configuração de tarefas complexas copiada" - fi - fi - - # Copia manual para /opt/fazai/MANUAL_COMPLETO.md (fallback para MANUAL_FERRAMENTAS.md) - if [ -f "MANUAL_COMPLETO.md" ]; then - if ! copy_with_verification "MANUAL_COMPLETO.md" "/opt/fazai/" "Manual completo"; then - copy_errors=$((copy_errors+1)) - fi - elif [ -f "MANUAL_FERRAMENTAS.md" ]; then - if ! copy_with_verification "MANUAL_FERRAMENTAS.md" "/opt/fazai/" "Manual de ferramentas"; then - copy_errors=$((copy_errors+1)) - else - # Mantém o nome esperado pelo CLI - cp -f "/opt/fazai/MANUAL_FERRAMENTAS.md" "/opt/fazai/MANUAL_COMPLETO.md" 2>/dev/null || true - fi - else - log "WARNING" "Manual não encontrado no repositório (MANUAL_COMPLETO.md/MANUAL_FERRAMENTAS.md)" - fi - - if ! copy_with_verification "bin/fazai" "/opt/fazai/bin/" "CLI"; then - copy_errors=$((copy_errors+1)) - fi - chmod 755 /opt/fazai/bin/fazai - ln -sf /opt/fazai/bin/fazai /usr/local/bin/fazai - log "SUCCESS" "CLI instalado em /usr/local/bin/fazai" - - # Instala GPT-Web2Shell (utilitário externo, exclusivo - OPT-IN via FAZAI_ENABLE_GPT_WEB2SHELL=1) - if [ "${FAZAI_ENABLE_GPT_WEB2SHELL}" = "1" ]; then - EXTRA_DIR="${FAZAI_LOCAL_EXTRAS_DIR:-}" - # Preferir extras externos - if [ -n "$EXTRA_DIR" ] && [ -f "$EXTRA_DIR/gpt-web2shell/bin/gpt-web2shell" ]; then - log "INFO" "Instalando GPT-Web2Shell a partir de FAZAI_LOCAL_EXTRAS_DIR=$EXTRA_DIR" - mkdir -p /opt/fazai/bin /opt/fazai/tools - cp -f "$EXTRA_DIR/gpt-web2shell/bin/gpt-web2shell" /opt/fazai/bin/gpt-web2shell - cp -f "$EXTRA_DIR/gpt-web2shell/opt/fazai/tools/gpt-web2shell.js" /opt/fazai/tools/gpt-web2shell.js - chmod 755 /opt/fazai/bin/gpt-web2shell /opt/fazai/tools/gpt-web2shell.js || true - ln -sf /opt/fazai/bin/gpt-web2shell /usr/local/bin/gpt-web2shell - log "SUCCESS" "GPT-Web2Shell instalado em /usr/local/bin/gpt-web2shell (extras externos)" - elif [ -f "bin/gpt-web2shell" ] && [ -f "opt/fazai/tools/gpt-web2shell.js" ]; then - # fallback: se os arquivos estiverem presentes no diretório do repositório - if copy_with_verification "bin/gpt-web2shell" "/opt/fazai/bin/" "GPT-Web2Shell"; then - mkdir -p /opt/fazai/tools - cp -f "opt/fazai/tools/gpt-web2shell.js" "/opt/fazai/tools/gpt-web2shell.js" - chmod 755 /opt/fazai/bin/gpt-web2shell /opt/fazai/tools/gpt-web2shell.js || true - ln -sf /opt/fazai/bin/gpt-web2shell /usr/local/bin/gpt-web2shell - log "SUCCESS" "GPT-Web2Shell instalado em /usr/local/bin/gpt-web2shell" - else - log "WARNING" "Falha ao instalar GPT-Web2Shell (arquivos locais)" - fi - else - log "WARNING" "FAZAI_ENABLE_GPT_WEB2SHELL=1 definido, mas arquivos não encontrados. Use scripts/install-web2shell.sh com FAZAI_LOCAL_EXTRAS_DIR." - fi - else - log "INFO" "GPT-Web2Shell não instalado (exclusivo). Para instalar, exporte FAZAI_ENABLE_GPT_WEB2SHELL=1 e forneça os arquivos via FAZAI_LOCAL_EXTRAS_DIR." - fi - - # Copia ferramentas do bin/tools para /opt/fazai/tools - if [ -d "bin/tools" ]; then - log "INFO" "Copiando ferramentas do bin/tools..." - if ! copy_with_verification "bin/tools/github-setup.sh" "/opt/fazai/tools/" "GitHub Setup Script"; then - copy_errors=$((copy_errors+1)) - fi - if ! copy_with_verification "bin/tools/sync-changes.sh" "/opt/fazai/tools/" "Sync Changes Script"; then - copy_errors=$((copy_errors+1)) - fi - if ! copy_with_verification "bin/tools/sync-keys.sh" "/opt/fazai/tools/" "Sync Keys Script"; then - copy_errors=$((copy_errors+1)) - fi - if ! copy_with_verification "bin/tools/system-check.sh" "/opt/fazai/tools/" "System Check Script"; then - copy_errors=$((copy_errors+1)) - fi - if ! copy_with_verification "bin/tools/test-all-tools.sh" "/opt/fazai/tools/" "Test All Tools Script"; then - copy_errors=$((copy_errors+1)) - fi - if ! copy_with_verification "bin/tools/version-bump.sh" "/opt/fazai/tools/" "Version Bump Script"; then - copy_errors=$((copy_errors+1)) - fi - if ! copy_with_verification "bin/tools/install-llamacpp.sh" "/opt/fazai/tools/" "LLaMA Install Script"; then - copy_errors=$((copy_errors+1)) - fi - - # Torna os scripts executáveis - chmod +x /opt/fazai/tools/*.sh 2>/dev/null - log "SUCCESS" "Ferramentas copiadas e tornadas executáveis" - fi - - # Copia módulos nativos se existirem - if [ -f "opt/fazai/mods/system_mod.so" ]; then - if ! copy_with_verification "opt/fazai/mods/system_mod.so" "/opt/fazai/mods/" "Módulo nativo system_mod"; then - copy_errors=$((copy_errors+1)) - else - log "SUCCESS" "Módulo nativo copiado" - fi - fi - - # Compila módulo system_mod.c se existir - if [ -f "opt/fazai/lib/mods/system_mod.c" ]; then - log "INFO" "Compilando módulo system_mod.c..." - mkdir -p /opt/fazai/lib/mods/ - cp -r opt/fazai/lib/mods/* /opt/fazai/lib/mods/ 2>/dev/null || true - - cd /opt/fazai/lib/mods/ - if [ -f "compile_system_mod.sh" ]; then - chmod +x compile_system_mod.sh - # Verifica dependências primeiro (sem instalar) - ./compile_system_mod.sh --check || log "WARNING" "Pendências detectadas; tentando auto-instalação e compilação." - # Compila (com auto-instalação de pacotes quando necessário) - ./compile_system_mod.sh || log "WARNING" "Falha na compilação do system_mod.c" - # Publica .so - mkdir -p /opt/fazai/mods - cp -f /opt/fazai/lib/mods/*.so /opt/fazai/mods/ 2>/dev/null || true - if ls /opt/fazai/mods/*.so >/dev/null 2>&1; then - log "SUCCESS" "Módulos nativos disponibilizados em /opt/fazai/mods" - else - log "WARNING" "Nenhum módulo .so encontrado após compilação" - fi - else - # Compilação manual se o script não existir - log "WARNING" "Script de compilação não encontrado, tentando compilação manual..." - gcc -shared -fPIC -o system_mod.so system_mod.c -lclamav -lcurl -ljson-c -lpthread 2>/dev/null || log "WARNING" "Falha na compilação do system_mod.c (dependências podem estar faltando)" - mkdir -p /opt/fazai/mods - cp -f /opt/fazai/lib/mods/system_mod.so /opt/fazai/mods/ 2>/dev/null || true - fi - cd - > /dev/null - fi - - - - # Copia novas tools - for t in \ - "opt/fazai/tools/auto_tool.js" \ - "opt/fazai/tools/net_qos_monitor.js" \ - "opt/fazai/tools/agent_supervisor.js" \ - "opt/fazai/tools/qdrant_setup.js" \ - "opt/fazai/tools/snmp_monitor.js" \ - "opt/fazai/tools/modsecurity_setup.js" \ - "opt/fazai/tools/suricata_setup.js" \ - "opt/fazai/tools/crowdsec_setup.js" \ - "opt/fazai/tools/monit_setup.js" \ - "opt/fazai/tools/rag_ingest.js" \ - "opt/fazai/tools/download_gemma2.sh" \ - "opt/fazai/tools/install_python_deps.sh" \ - "opt/fazai/tools/alerts.js" \ - "opt/fazai/tools/blacklist_check.js" \ - "opt/fazai/tools/email_relay.js" \ - "opt/fazai/tools/geoip_lookup.js" \ - "opt/fazai/tools/http_fetch.js" \ - "opt/fazai/tools/ports_monitor.js" \ - "opt/fazai/tools/system_info.js" \ - "opt/fazai/tools/test_complex_tasks.js" \ - "opt/fazai/tools/weather.js" \ - "opt/fazai/tools/crowdsec.js" \ - "opt/fazai/tools/modsecurity.js" \ - "opt/fazai/tools/spamexperts.js" \ - "opt/fazai/tools/web_search.js" \ - "opt/fazai/tools/cloudflare.js"; do - if [ -f "$t" ]; then - if ! copy_with_verification "$t" "/opt/fazai/tools/" "Tool $(basename $t)"; then - copy_errors=$((copy_errors+1)) - else - chmod 755 "/opt/fazai/tools/$(basename $t)" || true - fi - fi - done - - # Instala dependência dialog para alguns scripts - install_dialog - - # Copia interface web front-end - if [ -f "opt/fazai/tools/fazai_web_frontend.html" ]; then - if ! copy_with_verification "opt/fazai/tools/fazai_web_frontend.html" "/opt/fazai/tools/" "Interface web"; then - copy_errors=$((copy_errors+1)) - else - chmod 644 "/opt/fazai/tools/fazai_web_frontend.html" - log "SUCCESS" "Interface web instalada" - fi - else - log "WARNING" "Interface web não encontrado, crio fallback básico..." - cat > "/opt/fazai/tools/fazai_web_frontend.html" << 'EOF' - - - - - - FazAI - Interface Web - - -

FazAI Interface Web

-

Interface básica gerada automaticamente.

- - -EOF - log "SUCCESS" "Interface web fallback criada" - fi - if [ -f "opt/fazai/tools/fazai-tui.sh" ]; then - if ! copy_with_verification "opt/fazai/tools/fazai-tui.sh" "/opt/fazai/tools/" "Dashboard TUI completo"; then - copy_errors=$((copy_errors+1)) - else - chmod +x /opt/fazai/tools/fazai-tui.sh - ln -sf /opt/fazai/tools/fazai-tui.sh /usr/local/bin/fazai-tui - log "SUCCESS" "Dashboard TUI completo instalado em /usr/local/bin/fazai-tui" - fi - if command -v cargo >/dev/null 2>&1; then - log "INFO" "Compilando TUI em Rust..." - if cargo build --release --manifest-path=tui/Cargo.toml >/tmp/fazai_tui_build.log 2>&1; then - cp tui/target/release/fazai-tui /opt/fazai/tools/fazai-tui-rs - ln -sf /opt/fazai/tools/fazai-tui-rs /usr/local/bin/fazai-tui - log "SUCCESS" "TUI Rust instalado em /usr/local/bin/fazai-tui" - else - log "WARNING" "Falha ao compilar TUI Rust, utilizando script bash" - fi - fi - else - log "WARNING" "Dashboard TUI não encontrado, criando versão básica..." - cat > "/opt/fazai/tools/fazai-tui.sh" << 'EOF' -#!/bin/bash -# FazAI Dashboard TUI - Versão Básica -echo "FazAI Dashboard TUI v2.0.0" -echo "Opções:" -echo " [l] Ver logs | [s] Status | [q] Sair" -while read -r -n1 -p "Selecione: " k; do - echo - case "$k" in - l) curl -fsS http://localhost:3120/logs | jq . || true ;; - s) curl -fsS http://localhost:3120/status | jq . || true ;; - q) echo "Saindo..."; exit 0 ;; - *) echo "Opção inválida" ;; - esac -done -EOF - chmod +x "/opt/fazai/tools/fazai-tui.sh" - ln -sf /opt/fazai/tools/fazai-tui.sh /usr/local/bin/fazai-tui - log "SUCCESS" "Dashboard TUI básico instalado em /usr/local/bin/fazai-tui" - - log "WARNING" "Interface web não encontrada, criando versão básica..." - # Cria uma versão básica se não existir - cat > "/opt/fazai/tools/fazai_web_frontend.html" << 'EOF' - - - - - - FazAI - Interface Web - - - -
-

FazAI - Interface Web

-
-

Gerenciamento de Logs

- - - -
-
-

Status do Sistema

- -
-
-
- - - -EOF - log "SUCCESS" "Interface web básica criada" - fi - - # Copia script de lançamento da interface web - if [ -f "opt/fazai/tools/fazai_web.sh" ]; then - if ! copy_with_verification "opt/fazai/tools/fazai_web.sh" "/opt/fazai/tools/" "Script de lançamento web"; then - copy_errors=$((copy_errors+1)) - else - chmod +x "/opt/fazai/tools/fazai_web.sh" - log "SUCCESS" "Script de lançamento web instalado" - fi - else - log "WARNING" "Script de lançamento web não encontrado, criando versão básica..." - cat > "/opt/fazai/tools/fazai_web.sh" << 'EOF' - #!/bin/bash - # FazAI Web Frontend Launcher - # Caminho: /opt/fazai/tools/fazai_web.sh - - FRONTEND_FILE="/opt/fazai/tools/fazai_web_frontend.html" - - if [ ! -f "$FRONTEND_FILE" ]; then - echo "Erro: Interface web não encontrada: $FRONTEND_FILE" - exit 1 - fi - - echo "Iniciando interface web do FazAI..." - - # Detecta o sistema e abre o navegador - if [[ "$OSTYPE" == "linux-gnu"* ]]; then - if command -v xdg-open > /dev/null; then - xdg-open "$FRONTEND_FILE" - elif command -v firefox > /dev/null; then - firefox "$FRONTEND_FILE" - else - echo "Abra manualmente: $FRONTEND_FILE" - fi - elif [[ "$OSTYPE" == "darwin"* ]]; then - open "$FRONTEND_FILE" - elif [[ "$OSTYPE" == "cygwin" || "$OSTYPE" == "msys" ]]; then - start "$FRONTEND_FILE" - else - echo "Abra manualmente: $FRONTEND_FILE" - fi - - echo "Interface web disponível em: file://$FRONTEND_FILE" -EOF - chmod +x "/opt/fazai/tools/fazai_web.sh" - log "SUCCESS" "Script de lançamento web básico criado" - fi - - # Copia gerador de visualização HTML - if [ -f "opt/fazai/tools/fazai_html_v1.sh" ]; then - if ! copy_with_verification "opt/fazai/tools/fazai_html_v1.sh" "/opt/fazai/tools/" "Gerador HTML"; then - copy_errors=$((copy_errors+1)) - else - chmod +x "/opt/fazai/tools/fazai_html_v1.sh" - ln -sf /opt/fazai/tools/fazai_html_v1.sh /usr/local/bin/fazai-html - log "SUCCESS" "Gerador HTML instalado em /usr/local/bin/fazai-html" - fi - fi - - if [ "$copy_errors" -ne 0 ]; then - log "ERROR" "$copy_errors falha(s) ao copiar arquivos. Veja $LOG_FILE para detalhes." - return 1 - fi - - log "SUCCESS" "Arquivos copiados com sucesso." - } - - # Função para importar configurações de .env - import_env_config() { - log "INFO" "Verificando configurações de ambiente..." - - # Locais possíveis do arquivo .env - local env_locations=( - "/root/.env" - "$HOME/.env" - "./.env" - ".env.example" - ) - - local env_file="" - - # Procura o primeiro arquivo .env disponível - for location in "${env_locations[@]}"; do - if [ -f "$location" ]; then - env_file="$location" - log "INFO" "Arquivo .env encontrado em $env_file" - break - fi - done - - if [ -n "$env_file" ]; then - log "INFO" "Arquivo .env encontrado. Importando configurações..." - - # Extrai chaves de API - local api_keys=( - "OPENAI_API_KEY" - "ANTHROPIC_API_KEY" - "GOOGLE_API_KEY" - "AZURE_API_KEY" - ) - - local fazai_conf="/etc/fazai/fazai.conf" - local changes_made=false - - for key in "${api_keys[@]}"; do - local value=$(grep "^$key=" "$env_file" 2>/dev/null | cut -d'=' -f2 | tr -d '"' | tr -d "'") - if [ -n "$value" ]; then - local config_key=$(echo "$key" | tr '[:upper:]' '[:lower:]') - - # Verifica se a chave já existe no arquivo de configuração - if grep -q "^$config_key" "$fazai_conf"; then - # Substitui o valor existente - sed -i "s|^$config_key.*|$config_key = $value|" "$fazai_conf" - else - # Adiciona nova entrada na seção de APIs - if grep -q "^\[apis\]" "$fazai_conf"; then - sed -i "/^\[apis\]/a $config_key = $value" "$fazai_conf" - else - # Se não houver seção de APIs, adiciona ao final do arquivo - echo -e "\n[apis]\n$config_key = $value" >> "$fazai_conf" - fi - fi - - log "SUCCESS" "Chave $key importada com sucesso." - changes_made=true - fi - done - - if [ "$changes_made" = true ]; then - log "SUCCESS" "Configurações importadas para $fazai_conf" - else - log "WARNING" "Nenhuma configuração relevante encontrada em $env_file" - fi - else - log "INFO" "Nenhum arquivo .env encontrado nas localizações padrão." - fi - } - - # Função para configurar o serviço systemd -configure_systemd() { - log "INFO" "Configurando serviço systemd..." - - local service_file="/etc/systemd/system/fazai.service" - - # Gera um arquivo de serviço melhorado - cat > "$service_file" << EOF - [Unit] - Description=FazAI Service - After=network.target fazai-gemma-worker.service fazai-docler.service fazai-qdrant.service - Wants=fazai-gemma-worker.service fazai-docler.service - Wants=fazai-qdrant.service - StartLimitIntervalSec=0 - - [Service] - Type=simple - Restart=always - RestartSec=1 - User=root - ExecStart=/usr/bin/node /opt/fazai/lib/main.js - WorkingDirectory=/opt/fazai - Environment=NODE_ENV=production - StandardOutput=append:/var/log/fazai/stdout.log - StandardError=append:/var/log/fazai/stderr.log - - # Limites de recursos - LimitNOFILE=65535 - LimitMEMLOCK=512M - - [Install] - WantedBy=multi-user.target -EOF - - chmod 644 "$service_file" - log "SUCCESS" "Arquivo de serviço systemd criado em $service_file" - - systemctl daemon-reload - systemctl enable fazai - log "SUCCESS" "Serviço systemd habilitado." - - # Instala serviço do Gemma Worker se binário existir - if [ -x "/opt/fazai/bin/fazai-gemma-worker" ]; then - log "INFO" "Configurando serviço fazai-gemma-worker..." - cat > "/etc/systemd/system/fazai-gemma-worker.service" << EOF -[Unit] -Description=FazAI Gemma Worker v2.0 -After=network.target fazai-qdrant.service -Wants=fazai-qdrant.service -PartOf=fazai.service - -[Service] -Type=simple -User=root -WorkingDirectory=/opt/fazai -EnvironmentFile=-/etc/fazai/env -RuntimeDirectory=fazai -RuntimeDirectoryMode=0777 -UMask=0000 -ExecStartPre=/usr/bin/install -d -m 0777 -o root -g root /run/fazai -ExecStartPre=/bin/rm -f /run/fazai/gemma.sock -ExecStart=/opt/fazai/bin/fazai_gemma_worker.py -ExecStopPost=/bin/rm -f /run/fazai/gemma.sock -Restart=always -RestartSec=5 -StandardOutput=journal -StandardError=journal - -[Install] -WantedBy=multi-user.target -EOF - chmod 644 "/etc/systemd/system/fazai-gemma-worker.service" - systemctl daemon-reload - systemctl enable fazai-gemma-worker || true - log "SUCCESS" "Serviço fazai-gemma-worker preparado." - else - log "WARNING" "Binário fazai-gemma-worker não encontrado; serviço do worker não será criado." - fi - - # Serviço DOCLER Web (portas 3220/3221 para evitar conflito com daemon 3120) - if [ -f "/opt/fazai/web/docler-server.js" ]; then - log "INFO" "Configurando serviço fazai-docler..." - cat > "/etc/systemd/system/fazai-docler.service" << 'EOF' -[Unit] -Description=FazAI DOCLER Web Server -After=network.target -PartOf=fazai.service - -[Service] -Type=simple -User=fazai-web -Group=fazai-web -Environment=DOCLER_PORT=3220 -Environment=DOCLER_ADMIN_PORT=3221 -Environment=DOCLER_HOST=0.0.0.0 -WorkingDirectory=/opt/fazai/web -ExecStart=/usr/bin/node /opt/fazai/web/docler-server.js -Restart=always -RestartSec=5 - -[Install] -WantedBy=multi-user.target -EOF - chmod 644 "/etc/systemd/system/fazai-docler.service" - systemctl daemon-reload - systemctl enable fazai-docler || true - # Tenta iniciar se dependências foram instaladas - systemctl start fazai-docler || true - log "SUCCESS" "Serviço fazai-docler preparado (portas 3220/3221)." - else - log "WARNING" "docler-server.js não encontrado; serviço DOCLER não será criado." - fi - - # Serviço Qdrant Vector Database - log "INFO" "Configurando serviço fazai-qdrant..." - if command -v docker >/dev/null 2>&1 && systemctl is-active docker >/dev/null 2>&1; then - # Usar Docker se disponível - cat > "/etc/systemd/system/fazai-qdrant.service" << 'EOF' -[Unit] -Description=FazAI Qdrant Vector Database (Docker) -After=network.target docker.service -Requires=docker.service -PartOf=fazai.service - -[Service] -Type=oneshot -RemainAfterExit=yes -ExecStartPre=/usr/bin/docker pull qdrant/qdrant:latest -ExecStart=/usr/bin/docker run -d \ - --name fazai-qdrant \ - --restart unless-stopped \ - -p 6333:6333 \ - -p 6334:6334 \ - -v /var/lib/qdrant:/qdrant/storage \ - -v /opt/fazai/web/static:/opt/qdrant/web/static \ - -e QDRANT__SERVICE__HTTP_PORT=6333 \ - -e QDRANT__SERVICE__GRPC_PORT=6334 \ - -e QDRANT__SERVICE__HOST=0.0.0.0 \ - -e QDRANT__WEB_UI__ENABLED=true \ - -e QDRANT__SERVICE__ENABLE_CORS=true \ - qdrant/qdrant:latest -ExecStop=/usr/bin/docker stop fazai-qdrant -ExecStopPost=/usr/bin/docker rm fazai-qdrant - -[Install] -WantedBy=multi-user.target -EOF - elif [ -f "/opt/fazai/bin/qdrant" ]; then - # Usar binário nativo se disponível - cat > "/etc/systemd/system/fazai-qdrant.service" << 'EOF' -[Unit] -Description=FazAI Qdrant Vector Database -After=network.target -PartOf=fazai.service - -[Service] -Type=simple -User=fazai -Group=fazai -WorkingDirectory=/var/lib/qdrant -ExecStart=/opt/fazai/bin/qdrant --config-path /etc/fazai/qdrant.yaml -Restart=always -RestartSec=5 -Environment=RUST_LOG=info - -[Install] -WantedBy=multi-user.target -EOF - fi - - chmod 644 "/etc/systemd/system/fazai-qdrant.service" 2>/dev/null || true - systemctl daemon-reload - systemctl enable fazai-qdrant || true - systemctl start fazai-qdrant || true - log "SUCCESS" "Serviço fazai-qdrant preparado (porta 6333)." - - - - # Instalar GPT-Web2Shell se local-extras existe - if [ -d "local-extras/gpt-web2shell" ]; then - log "INFO" "Instalando GPT-Web2Shell..." - mkdir -p /home/${SUDO_USER}/fazai/local-extras/gpt-web2shell - cp -r local-extras/gpt-web2shell/* /home/${SUDO_USER}/fazai/local-extras/gpt-web2shell/ - chown -R ${SUDO_USER}:${SUDO_USER} /home/${SUDO_USER}/fazai/local-extras/ 2>/dev/null || true - chmod +x /home/${SUDO_USER}/fazai/local-extras/gpt-web2shell/bin/gpt-web2shell 2>/dev/null || true - chmod +x /opt/fazai/tools/gpt-web2shell.js 2>/dev/null || true - log "SUCCESS" "GPT-Web2Shell instalado para transcendência CLI." - fi - - # Detecta runtime de contêiner (Docker/Podman) - local CONTAINER="" - if command -v docker >/dev/null 2>&1; then CONTAINER="docker"; fi - if [ -z "$CONTAINER" ] && command -v podman >/dev/null 2>&1; then CONTAINER="podman"; fi - - # Serviço Qdrant (via Docker/Podman) se disponível - if [ -n "$CONTAINER" ]; then - log "INFO" "Configurando serviço Qdrant ($CONTAINER)..." - mkdir -p /var/lib/fazai/qdrant - cat > "/etc/systemd/system/fazai-qdrant.service" << 'EOF' -[Unit] -Description=FazAI Qdrant Vector DB (Docker) -After=network-online.target -PartOf=fazai.service - -[Service] -Type=oneshot -RemainAfterExit=yes -ExecStartPre=-/usr/bin/CONTAINER_BIN rm -f fazai-qdrant -ExecStart=/usr/bin/CONTAINER_BIN run -d --name fazai-qdrant -p 6333:6333 -v /var/lib/fazai/qdrant:/qdrant/storage qdrant/qdrant:v1.7.3 -ExecStop=/usr/bin/CONTAINER_BIN stop fazai-qdrant -TimeoutStartSec=120 -TimeoutStopSec=30 - -[Install] -WantedBy=multi-user.target -EOF - # Substitui placeholder pelo runtime - sed -i "s|CONTAINER_BIN|$CONTAINER|g" "/etc/systemd/system/fazai-qdrant.service" - chmod 644 "/etc/systemd/system/fazai-qdrant.service" - systemctl daemon-reload - systemctl enable fazai-qdrant || true - systemctl start fazai-qdrant || true - log "SUCCESS" "Serviço Qdrant preparado (porta 6333)." - - - else - log "WARNING" "Docker/Podman não encontrado; Qdrant não será instalado automaticamente. Instale um runtime de contêiner ou configure Qdrant manualmente." - fi - - # Observabilidade foi movida para repo separado (~/fazaiserverlogs) - if [ -n "$CONTAINER" ]; then - log "INFO" "Monitoring Prometheus/Grafana não é mais instalado neste host. Use o repositório fazaiserverlogs." - fi -} - -# Compila e instala o Gemma Worker (C++) se fontes estiverem presentes -build_gemma_worker() { - if [ -d "worker" ] && [ -f "worker/CMakeLists.txt" ]; then - log "INFO" "Compilando Gemma Worker (C++)..." - mkdir -p worker/build - pushd worker/build >/dev/null - if cmake .. && cmake --build . -j$(nproc) && cmake --install .; then - log "SUCCESS" "Gemma Worker compilado e instalado em /opt/fazai/bin" - else - log "WARNING" "Falha ao compilar o Gemma Worker. O agente local poderá não funcionar." - fi - popd >/dev/null - # Garante diretório de socket - mkdir -p /run/fazai - chmod 755 /run/fazai - else - log "INFO" "Fontes do Gemma Worker não encontradas; pulando compilação." - fi -} - -# Instala Gemma one-shot e pesos padrão (máquinas pequenas) -bootstrap_gemma() { - if [ -x "/opt/fazai/bin/gemma_oneshot" ] && [ -f "/opt/fazai/models/gemma/2.0-2b-it-sfp.sbs" ]; then - log "INFO" "Gemma (oneshot + pesos) já presente." - return 0 - fi - if [ -x "/opt/fazai/tools/gemma_bootstrap.sh" ]; then - log "INFO" "Executando gemma_bootstrap.sh (download/instalação do modelo)." - bash /opt/fazai/tools/gemma_bootstrap.sh || log "WARNING" "Falha no gemma_bootstrap.sh" - else - log "WARNING" "gemma_bootstrap.sh não encontrado." - fi -} - - # Função para instalar dependências do Node.js com retry - install_node_dependencies() { - log "INFO" "Instalando dependências do Node.js..." - - # Cria package.json se não existir - if [ ! -f "package.json" ]; then - log "INFO" "Criando package.json..." - cat > "package.json" << 'EOF' - { - "name": "fazai", - "version": "2.0.0", - "description": "FazAI - Orquestrador Inteligente de Automação", - "main": "main.js", - "dependencies": { - "axios": ">=0.27.2", - "express": ">=4.18.1", - "winston": ">=3.8.1", - - "chalk": ">=4.1.2", - "figlet": ">=1.5.2", - "inquirer": ">=8.2.4" - } - } -EOF - fi - - # Instala no diretório atual primeiro - log "INFO" "Instalando dependências no diretório atual..." - if ! npm install --no-audit --no-progress; then - log "WARNING" "Falha na instalação inicial de dependências. Tentando método alternativo..." - - # Tenta instalar pacotes críticos individualmente - for module in "${DEPENDENCY_MODULES[@]}"; do - log "INFO" "Instalando módulo: $module" - npm install "$module" --no-audit --no-progress || log "WARNING" "Falha ao instalar $module" - done - fi - - # Agora instala em /opt/fazai - log "INFO" "Instalando dependências em /opt/fazai..." - cp package.json /opt/fazai/ - cd /opt/fazai - - if ! npm install --no-audit --no-progress; then - log "WARNING" "Falha ao instalar dependências em /opt/fazai. Tentando método alternativo..." - - # Tenta instalar pacotes críticos individualmente - for module in "${DEPENDENCY_MODULES[@]}"; do - log "INFO" "Instalando módulo em /opt/fazai: $module" - npm install "$module" --no-audit --no-progress || log "WARNING" "Falha ao instalar $module" - done - fi - - cd - > /dev/null - - # Verifica se os módulos essenciais foram instalados - if npm list express winston >> "$LOG_FILE" 2>&1; then - log "SUCCESS" "Módulos express e winston instalados corretamente." - else - log "WARNING" "Módulos express ou winston ausentes. Possível problema de conexão. Execute 'npm install' manualmente." - fi - - log "SUCCESS" "Dependências do Node.js instaladas." - } - - # Função para compilar módulos nativos - compile_native_modules() { - log "INFO" "Verificando módulos nativos..." - - # Cria um módulo nativo básico se não existir - if [ ! -d "/opt/fazai/mods" ]; then - mkdir -p "/opt/fazai/mods" - fi - - cd /opt/fazai/mods - - if [ ! -f "system_mod.c" ]; then - log "INFO" "Criando módulo nativo básico..." - cat > "system_mod.c" << 'EOF' - #include - #include - - // Função básica para teste do módulo nativo - int fazai_test() { - return 42; - } -EOF - fi - - if [ -f "system_mod.c" ]; then - log "DEBUG" "Compilando system_mod.c..." - if gcc -shared -fPIC -o system_mod.so system_mod.c; then - log "SUCCESS" "Módulos nativos compilados com sucesso." - else - log "WARNING" "Falha ao compilar módulos nativos. Continuando sem eles..." - fi - else - log "INFO" "Nenhum módulo nativo para compilar." - fi - - cd - > /dev/null - } - - # Função opcional para instalar o llama.cpp - install_llamacpp() { - if [ "$WITH_LLAMA" != true ]; then - log "INFO" "Instalação do llama.cpp ignorada (--with-llama)" - return 0 - fi - - log "INFO" "Instalando llama.cpp..." - local script_dir="$(cd "$(dirname "$0")" && pwd)" - if bash "$script_dir/bin/tools/install-llamacpp.sh"; then - log "SUCCESS" "llama.cpp instalado" - return 0 - else - log "ERROR" "Falha ao instalar llama.cpp" - return 1 - fi - } - - # Função para instalar interface TUI - - # Função para configurar permissões de segurança - configure_security() { - log "INFO" "Configurando permissões de segurança..." - - # Cria grupo fazai se não existir - if ! getent group fazai > /dev/null 2>&1; then - groupadd -r fazai - log "SUCCESS" "Grupo 'fazai' criado" - fi - - # Cria usuário fazai se não existir - if ! getent passwd fazai > /dev/null 2>&1; then - useradd -r -g fazai -s /bin/false -d /opt/fazai fazai - log "SUCCESS" "Usuário 'fazai' criado" - fi - - # Define permissões dos diretórios - chown -R fazai:fazai /opt/fazai - chown -R fazai:fazai /var/log/fazai - chown -R fazai:fazai /var/lib/fazai - - # Permissões específicas - chmod 750 /opt/fazai - chmod 755 /opt/fazai/bin/fazai - # Conf: dono fazai, grupo root, 640 - chown fazai:root /etc/fazai/fazai.conf 2>/dev/null || true - chmod 640 /etc/fazai/fazai.conf - chmod 755 /opt/fazai/tools/fazai-config.js - - # Configura sudoers para permitir comandos específicos do fazai - if [ ! -f /etc/sudoers.d/fazai ]; then - cat > /etc/sudoers.d/fazai << 'EOF' - # FazAI sudoers configuration - %fazai ALL=(ALL) NOPASSWD: /bin/systemctl start fazai - %fazai ALL=(ALL) NOPASSWD: /bin/systemctl stop fazai - %fazai ALL=(ALL) NOPASSWD: /bin/systemctl restart fazai - %fazai ALL=(ALL) NOPASSWD: /bin/systemctl status fazai - %fazai ALL=(ALL) NOPASSWD: /usr/bin/apt-get update - %fazai ALL=(ALL) NOPASSWD: /usr/bin/apt-get install * - %fazai ALL=(ALL) NOPASSWD: /usr/sbin/service * * -EOF - chmod 440 /etc/sudoers.d/fazai - log "SUCCESS" "Configuração sudoers criada" - fi - - log "SUCCESS" "Permissões de segurança configuradas" - } - - # Função para criar scripts auxiliares - create_helper_scripts() { - log "INFO" "Criando scripts auxiliares..." - - # Script de uninstall - cat > /opt/fazai/bin/uninstall.sh << 'EOF' - #!/bin/bash - # FazAI Uninstall Script - - echo "Desinstalando FazAI..." - - # Para o serviço - systemctl stop fazai 2>/dev/null - systemctl disable fazai 2>/dev/null - - # Remove arquivos de serviço - rm -f /etc/systemd/system/fazai.service - systemctl daemon-reload - - # Remove links simbólicos - rm -f /usr/local/bin/fazai - rm -f /usr/local/bin/fazai-config - - # Remove diretórios (com confirmação) - read -p "Remover todos os dados do FazAI? (logs, configurações, etc.) [s/N]: " -n 1 -r - echo - if [[ $REPLY =~ ^[Ss]$ ]]; then - rm -rf /opt/fazai - rm -rf /etc/fazai - rm -rf /var/log/fazai - rm -rf /var/lib/fazai - echo "Todos os dados removidos." - else - echo "Dados preservados em /etc/fazai, /var/log/fazai e /var/lib/fazai" - fi - - # Remove usuário e grupo - userdel fazai 2>/dev/null - groupdel fazai 2>/dev/null - - # Remove sudoers - rm -f /etc/sudoers.d/fazai - - echo "FazAI desinstalado com sucesso!" -EOF - - chmod +x /opt/fazai/bin/uninstall.sh - ln -sf /opt/fazai/bin/uninstall.sh /usr/local/bin/fazai-uninstall - - # Script de backup - cat > /opt/fazai/bin/backup.sh << 'EOF' - #!/bin/bash - # FazAI Backup Script - - BACKUP_DIR="/tmp/fazai-backup-$(date +%Y%m%d-%H%M%S)" - mkdir -p "$BACKUP_DIR" - - echo "Criando backup em $BACKUP_DIR..." - - # Backup de configurações - cp -r /etc/fazai "$BACKUP_DIR/" - cp -r /var/lib/fazai "$BACKUP_DIR/" - - # Backup de logs (últimos 7 dias) - find /var/log/fazai -name "*.log" -mtime -7 -exec cp {} "$BACKUP_DIR/" \; - - # Compacta o backup - cd /tmp - tar -czf "fazai-backup-$(date +%Y%m%d-%H%M%S).tar.gz" "$(basename $BACKUP_DIR)" - rm -rf "$BACKUP_DIR" - - echo "Backup criado: /tmp/fazai-backup-$(date +%Y%m%d-%H%M%S).tar.gz" -EOF - - chmod +x /opt/fazai/bin/backup.sh - ln -sf /opt/fazai/bin/backup.sh /usr/local/bin/fazai-backup - - log "SUCCESS" "Scripts auxiliares criados" - } - - # Compila o worker Gemma usando o script interno - build_gemma_worker() { - log "INFO" "Compilando FazAI Gemma Worker" - if [ -d "worker" ]; then - pushd worker >/dev/null - ./build.sh || { log "ERROR" "Falha ao compilar worker"; popd >/dev/null; return 1; } - popd >/dev/null - log "SUCCESS" "Worker compilado e instalado em /opt/fazai/bin" - return 0 - else - log "ERROR" "Diretório worker não encontrado" - return 1 - fi - } - - # Função para configurar logrotate - configure_logrotate() { - log "INFO" "Configurando rotação de logs..." - - cat > /etc/logrotate.d/fazai << 'EOF' - /var/log/fazai/*.log { - daily - missingok - rotate 30 - compress - delaycompress - notifempty - create 644 fazai fazai - postrotate - systemctl reload fazai > /dev/null 2>&1 || true - endscript - } -EOF - - log "SUCCESS" "Configuração de logrotate criada" - } - - # Função para validar a instalação - validate_installation() { - log "INFO" "Validando instalação..." - - local validation_errors=0 - - # Verifica arquivos essenciais - local essential_files=( - "/opt/fazai/lib/main.js" - "/opt/fazai/bin/fazai" - "/etc/fazai/fazai.conf" - "/etc/fazai/complex_tasks.conf.default" - "/etc/systemd/system/fazai.service" - "/usr/local/bin/fazai" - "/opt/fazai/tools/fazai_web_frontend.html" - "/opt/fazai/tools/fazai_web.sh" - "/opt/fazai/tools/fazai_html_v1.sh" - "/opt/fazai/tools/auto_tool.js" - "/opt/fazai/tools/net_qos_monitor.js" - "/opt/fazai/tools/agent_supervisor.js" - "/opt/fazai/tools/qdrant_setup.js" - "/opt/fazai/tools/snmp_monitor.js" - "/opt/fazai/tools/modsecurity_setup.js" - "/opt/fazai/tools/suricata_setup.js" - "/opt/fazai/tools/crowdsec_setup.js" - "/opt/fazai/tools/monit_setup.js" - ) - - for file in "${essential_files[@]}"; do - if [ ! -f "$file" ]; then - log "ERROR" "Arquivo essencial não encontrado: $file" - validation_errors=$((validation_errors + 1)) - else - log "DEBUG" "Arquivo validado: $file" - fi - done - - # Verifica diretórios - local essential_dirs=( - "/opt/fazai" - "/etc/fazai" - "/var/log/fazai" - "/var/lib/fazai" - ) - - for dir in "${essential_dirs[@]}"; do - if [ ! -d "$dir" ]; then - log "ERROR" "Diretório essencial não encontrado: $dir" - validation_errors=$((validation_errors + 1)) - else - log "DEBUG" "Diretório validado: $dir" - fi - done - - # Verifica comandos - if ! command -v fazai &> /dev/null; then - log "ERROR" "Comando 'fazai' não está disponível" - validation_errors=$((validation_errors + 1)) - fi - - # Verifica serviço systemd - if ! systemctl is-enabled fazai &> /dev/null; then - log "WARNING" "Serviço fazai não está habilitado" - fi - - # Verifica dependências Node.js críticas - cd /opt/fazai - local critical_modules=("express" "winston") - for module in "${critical_modules[@]}"; do - if ! npm list "$module" &> /dev/null; then - log "WARNING" "Módulo Node.js crítico não encontrado: $module" - fi - done - - if [ $validation_errors -eq 0 ]; then - log "SUCCESS" "Validação da instalação concluída com sucesso!" - return 0 - else - log "ERROR" "Validação falhou com $validation_errors erro(s)" - return 1 - fi - } - - # Função para executar testes pós-instalação - run_post_install_tests() { - log "INFO" "Executando testes pós-instalação..." - - # Teste 1: Verifica se o CLI responde - log "DEBUG" "Testando CLI..." - if fazai --version &> /dev/null; then - log "SUCCESS" "Teste CLI: OK" - else - log "WARNING" "Teste CLI: Falhou" - fi - - # Teste 2: Verifica se o serviço pode ser iniciado - log "DEBUG" "Testando serviço systemd..." - if systemctl start fazai && sleep 2 && systemctl is-active fazai &> /dev/null; then - log "SUCCESS" "Teste serviço: OK" - systemctl stop fazai - else - log "WARNING" "Teste serviço: Falhou" - fi - - # Teste 3: Verifica permissões - log "DEBUG" "Testando permissões..." - if [ -r /etc/fazai/fazai.conf ] && [ -x /opt/fazai/bin/fazai ]; then - log "SUCCESS" "Teste permissões: OK" - else - log "WARNING" "Teste permissões: Falhou" - fi - - log "SUCCESS" "Testes pós-instalação concluídos" - } - - # Função para mostrar informações finais - show_installation_summary() { - log "INFO" "====== Resumo da Instalação ======" - - echo -e "\n${GREEN}✓ FazAI v$VERSION instalado com sucesso!${NC}\n" - - echo -e "${BLUE}Localização dos arquivos:${NC}" - echo " • Binários: /opt/fazai" - echo " • Configuração: /etc/fazai/fazai.conf" - echo " • Configuração de tarefas complexas: /etc/fazai/complex_tasks.conf.default" - echo " • Logs: /var/log/fazai" - echo " • Dados: /var/lib/fazai" - echo "" - - echo -e "${BLUE}Comandos disponíveis:${NC}" - echo " • fazai --help - Ajuda do sistema" - echo " • fazai --version - Versão instalada" - echo " • fazai --status - Status do daemon" - echo " • fazai web - Interface web com gerenciamento de logs" - - echo " • fazai logs [n] - Ver últimas n entradas de log" - echo " • fazai limpar-logs - Limpar logs (com backup)" - - echo " • fazai-backup - Criar backup" - echo " • fazai-uninstall - Desinstalar" - echo "" - - echo -e "${BLUE}Gerenciamento do serviço:${NC}" - echo " • systemctl start fazai - Iniciar" - echo " • systemctl stop fazai - Parar" - echo " • systemctl restart fazai - Reiniciar" - echo " • systemctl status fazai - Ver status" - echo "" - - echo -e "${YELLOW}Próximos passos:${NC}" - echo " 1. Configure suas API keys editando /etc/fazai/fazai.conf" - echo " 2. Inicie o serviço: systemctl start fazai" - echo " 3. Teste o sistema: fazai --status" - echo "" - - echo -e "${PURPLE}Para suporte e documentação:${NC}" - echo " • GitHub: https://github.com/RLuf/FazAI" - echo " • Logs: /var/log/fazai_install.log" - echo "" - - # Salva estado final - save_install_state "installation_complete" "success" - - log "SUCCESS" "====== Instalação Finalizada ======" - } - - # Função principal de instalação - main_install() { - log "INFO" "Iniciando instalação do FazAI v$VERSION" - - # Carrega estado anterior se existir - load_install_state - - # Executa etapas de instalação - local install_steps=( - "setup_logging:Configurando sistema de logs" - "check_root:Verificando permissões" - "check_system:Verificando sistema operacional" - "convert_files_to_unix:Convertendo arquivos para formato Linux" - "install_nodejs:Instalando Node.js" - "install_npm:Verificando npm" - "install_python:Instalando Python 3" - "install_gcc:Instalando ferramentas de compilação" - "ensure_container_runtime:Instalando runtime de contêiner (Docker)" - "create_directories:Criando estrutura de diretórios" - "build_gemma_worker:Compilando Gemma Worker" - "bootstrap_gemma:Instalando Gemma one-shot e pesos padrão" - "copy_files:Copiando arquivos" - "import_env_config:Importando configurações" - "configure_systemd:Configurando serviço systemd" - "install_node_dependencies:Instalando dependências Node.js" - "compile_native_modules:Compilando módulos nativos" - ) - - if [ "$WITH_LLAMA" = true ]; then - install_steps+=("install_llamacpp:Instalando llama.cpp") - fi - - install_steps+=( - - "configure_security:Configurando segurança" - "create_helper_scripts:Criando scripts auxiliares" - "configure_logrotate:Configurando rotação de logs" - "install_bash_completion:Instalando autocompletar" - ) - - local total_steps=${#install_steps[@]} - local current_step=0 - - for step_info in "${install_steps[@]}"; do - local step_function=$(echo "$step_info" | cut -d: -f1) - local step_description=$(echo "$step_info" | cut -d: -f2) - - current_step=$((current_step + 1)) - - # Verifica se já foi executado - if [ "${INSTALL_STATE[$step_function]}" = "completed" ]; then - log "INFO" "[$current_step/$total_steps] $step_description (já concluído)" - continue - fi - - log "INFO" "[$current_step/$total_steps] $step_description" - - # Executa a função - if $step_function; then - save_install_state "$step_function" "completed" - log "SUCCESS" "$step_description - Concluído" - else - log "ERROR" "$step_description - Falhou" - save_install_state "$step_function" "failed" - - if [ "$step_function" = "copy_files" ]; then - log "ERROR" "Falha ao copiar arquivos. Instalação interrompida. Verifique $LOG_FILE para detalhes." - ai_help "Falha ao copiar arquivos durante a instalação do FazAI" - exit 1 - fi - - # Consulta ajuda da IA e pergunta se deve continuar - ai_help "Erro na etapa '$step_description'" - read -p "Erro na etapa '$step_description'. Continuar mesmo assim? (s/N): " -n 1 -r - echo - if [[ ! $REPLY =~ ^[Ss]$ ]]; then - log "ERROR" "Instalação interrompida pelo usuário" - exit 1 - fi - fi - done - - # Validação e testes finais - log "INFO" "Executando validação final..." - if validate_installation; then - run_post_install_tests - show_installation_summary - - # Inicia o serviço se tudo estiver OK - if systemctl start fazai; then - log "SUCCESS" "Serviço FazAI iniciado com sucesso!" - # Health-check com autorreparo - health_check_repair - # Resumo da engine/módulo nativo, se o verificador existir - if [ -x "scripts/verify-engine.sh" ]; then - log "INFO" "Resumo de verificação pós-instalação:" - bash scripts/verify-engine.sh || true - fi - else - log "WARNING" "Falha ao iniciar o serviço. Inicie manualmente: systemctl start fazai" - fi - else - log "ERROR" "Validação da instalação falhou. Verifique os logs em $LOG_FILE" - exit 1 - fi - } - - # Função para limpeza em caso de interrupção - cleanup_on_exit() { - local exit_code=$? - if [ $exit_code -ne 0 ]; then - log "WARNING" "Instalação interrompida (código: $exit_code)" - log "INFO" "Estado salvo em $INSTALL_STATE_FILE" - log "INFO" "Execute novamente o script para continuar de onde parou" - fi - } - - # Captura sinais para limpeza - trap cleanup_on_exit EXIT INT TERM - - - # Verifica argumentos de linha de comando - while [[ $# -gt 0 ]]; do - case "$1" in - --debug) - DEBUG_MODE=true - log "INFO" "Modo debug ativado" - ;; - --clean) - rm -f "$INSTALL_STATE_FILE" - log "INFO" "Estado de instalação limpo" - ;; - --with-llama) - WITH_LLAMA=true - ;; - --help) - echo "FazAI Installer v$VERSION" - echo "Uso: $0 [opções]" - echo "" - echo "Opções:" - echo " --debug Ativa modo debug com logs detalhados" - echo " --clean Remove estado de instalação anterior" - echo " --with-llama Instala o mecanismo local llama.cpp" - echo " --help Mostra esta ajuda" - exit 0 - ;; - esac - shift - done - - # Inicia instalação principal - main_install - - log "SUCCESS" "Instalação do FazAI v2.0 concluída com sucesso!" - echo -e "\n${GREEN}🎉 FazAI v2.0 - Sistema de Fluxo Inteligente está pronto!${NC}" - echo -e "${CYAN}Novos recursos disponíveis:${NC}" - echo -e " 🤖 ${YELLOW}fazai agent${NC} - Agente inteligente cognitivo" - echo -e " 📊 ${YELLOW}fazai relay${NC} - Sistema de relay SMTP inteligente" - echo -e " 🔧 ${YELLOW}Edite /etc/fazai/fazai.conf${NC} - Configurar API keys" - echo -e " 📚 ${YELLOW}fazai manual${NC} - Manual completo" - echo -e "\n${GREEN}Exemplos de uso:${NC}" - echo -e " fazai agent \"configurar servidor de email relay com antispam\"" - echo -e " fazai relay analyze" - echo -e " fazai relay configure" - -exit 0 diff --git a/install.sh.new2 b/install.sh.new2 deleted file mode 100644 index 5784b95..0000000 --- a/install.sh.new2 +++ /dev/null @@ -1,2296 +0,0 @@ -#!/bin/bash -set -e - -############################################################################### -# FazAI v2.0 Installer -# Sistema de Agente Inteligente Cognitivo e Persistente -############################################################################### - -# Variáveis globais -VERSION="2.0.0" -LOG_FILE="/var/log/fazai/install.log" -INSTALL_STATE_FILE="/var/log/fazai/install_state.txt" -DEBUG_MODE="${DEBUG_MODE:-false}" -WITH_LLAMA="${WITH_LLAMA:-false}" - -# Cores para output -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -PURPLE='\033[0;35m' -CYAN='\033[0;36m' -NC='\033[0m' # No Color - -# Array associativo para estado da instalação -declare -A INSTALL_STATE - -# Função de logging -log() { - local level="$1" - local message="$2" - local timestamp=$(date '+%Y-%m-%d %H:%M:%S') - - # Cria diretório de log se não existir - mkdir -p "$(dirname "$LOG_FILE")" - - # Escreve log ao arquivo - echo "[$timestamp] [$level] $message" >> "$LOG_FILE" - - # Mostra no console com cores - case $level in - "INFO") - echo -e "${BLUE}[INFO]${NC} $message" - ;; - "SUCCESS") - echo -e "${GREEN}[SUCESSO]${NC} $message" - ;; - "ERROR") - echo -e "${RED}[ERRO]${NC} $message" - ;; - "WARNING") - echo -e "${YELLOW}[AVISO]${NC} $message" - ;; - "DEBUG") - if [ "$DEBUG_MODE" = true ]; then - echo -e "${PURPLE}[DEBUG]${NC} $message" - fi - ;; - esac -} - -# Verifica root -if [[ $EUID -ne 0 ]]; then - log "ERROR" "Execute como root: sudo ./install.sh" - exit 1 -fi -# Consulta ajuda da IA em caso de erro (simplificada) -ai_help() { - local prompt="$1" - log "INFO" "Erro detectado: $prompt" - log "INFO" "Verifique os logs em $LOG_FILE para mais detalhes" -} - - -# Função para salvar estado da instalação -save_install_state() { - local step=$1 - local status=$2 - INSTALL_STATE["$step"]="$status" - mkdir -p $(dirname "$INSTALL_STATE_FILE") - - # Limpa o arquivo antes de reescrever - > "$INSTALL_STATE_FILE" - for key in "${!INSTALL_STATE[@]}"; do - echo "$key=${INSTALL_STATE[$key]}" >> "$INSTALL_STATE_FILE" - done - log "DEBUG" "Estado salvo: $step = $status" -} - -# Função para carregar estado da instalação -load_install_state() { - if [ -f "$INSTALL_STATE_FILE" ]; then - while IFS='=' read -r key value; do - if [ -n "$key" ] && [ -n "$value" ]; then - INSTALL_STATE["$key"]="$value" - fi - done < "$INSTALL_STATE_FILE" - log "INFO" "Estado da instalação carregado de $INSTALL_STATE_FILE" - fi -} - -# Função para verificar versão de uma dependência -check_dependency_version() { - local cmd=$1 - local min_version=$2 - - if ! command -v "$cmd" &> /dev/null; then - log "DEBUG" "Comando $cmd não encontrado" - return 1 - fi - - local current_version - case $cmd in - "node") - current_version=$(node -v | sed 's/v//') - ;; - "npm") - current_version=$(npm -v) - ;; - "python3") - current_version=$(python3 --version | awk '{print $2}') - ;; - "pip3") - current_version=$(pip3 --version | awk '{print $2}') - ;; - "gcc") - current_version=$(gcc --version | head -n1 | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -n1) - ;; - *) - current_version=$($cmd --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -n1) - ;; - esac - - if [ -z "$current_version" ]; then - log "WARNING" "Não foi possível determinar a versão de $cmd" - return 2 - fi - - # Comparação de versões usando sort -V - if printf '%s\n' "$min_version" "$current_version" | sort -V | head -n1 | grep -q "^$min_version$"; then - log "SUCCESS" "$cmd versão $current_version atende requisito mínimo ($min_version)" - return 0 - else - log "WARNING" "$cmd versão $current_version é menor que a mínima requerida ($min_version)" - return 3 - fi -} - -# Função para converter arquivos para formato Linux (dos2unix) -convert_files_to_unix() { - log "INFO" "Convertendo arquivos para formato Linux..." - - # Instala dos2unix se não estiver disponível - if ! command -v dos2unix &> /dev/null; then - log "INFO" "Instalando dos2unix..." - apt-get update && apt-get install -y dos2unix - - if ! command -v dos2unix &> /dev/null; then - log "WARNING" "dos2unix não pôde ser instalado. Tentando método alternativo..." - # Método alternativo usando sed - convert_with_sed() { - local file="$1" - if [ -f "$file" ]; then - sed -i 's/\r$//' "$file" 2>/dev/null - if [ $? -eq 0 ]; then - log "DEBUG" "Convertido com sed: $file" - else - log "WARNING" "Falha ao converter: $file" - fi - fi - } - - # Converte arquivos críticos usando sed - find . -type f \( -name "*.sh" -o -name "*.bash" -o -name "*.conf" \) -exec bash -c 'convert_with_sed "$0"' {} \; - log "SUCCESS" "Conversão concluída usando método alternativo" - return 0 - fi - fi - - # Executa o script dos2unixAll.sh se existir - if [ -f "etc/fazai/dos2unixAll.sh" ]; then - log "INFO" "Executando script dos2unixAll.sh..." - chmod +x "etc/fazai/dos2unixAll.sh" - cd "$(dirname "$(readlink -f "$0")")" || cd /opt/fazai - bash etc/fazai/dos2unixAll.sh - log "SUCCESS" "Script dos2unixAll.sh executado" - else - log "INFO" "Script dos2unixAll.sh não encontrado. Executando conversão manual..." - - # Encontra e converte todos os arquivos relevantes - find . -type f \ - \( -name "*.sh" \ - -o -name "*.bash" \ - -o -name "*.conf" \ - -o -name "*.yml" \ - -o -name "*.yaml" \ - -o -name "*.json" \ - -o -name "Dockerfile" \) \ - -exec sh -c ' - for file do - echo "🔄 Convertendo: $file" - dos2unix "$file" 2>/dev/null - if [ $? -eq 0 ]; then - echo "✅ Convertido com sucesso: $file" - else - echo "❌ Erro ao converter: $file" - fi - done - ' sh {} + - fi - - log "SUCCESS" "Conversão de arquivos para formato Linux concluída" -} - -# Função para instalar bash completion -install_bash_completion() { - log "INFO" "Instalando bash completion..." - - # Verifica se o bash-completion está instalado - if ! dpkg -l | grep -q bash-completion 2>/dev/null; then - log "INFO" "Instalando pacote bash-completion..." - apt-get update && apt-get install -y bash-completion - fi - - local completion_dir="/etc/bash_completion.d" - mkdir -p "$completion_dir" - - if [ -f "etc/fazai/fazai-completion.sh" ]; then - cp "etc/fazai/fazai-completion.sh" "$completion_dir/fazai" - else - log "WARNING" "etc/fazai/fazai-completion.sh não encontrado, gerando script simples" - cat > "$completion_dir/fazai" <<'EOF' -#!/bin/bash -complete -W "install uninstall status config help version" fazai -EOF - fi - chmod 644 "$completion_dir/fazai" - log "SUCCESS" "Script de completion instalado em $completion_dir/fazai" - - # Adiciona ao .bashrc se não existir - if ! grep -q "source $completion_dir/fazai" /root/.bashrc 2>/dev/null; then - echo "# FazAI bash completion" >> /root/.bashrc - echo "if [ -f /etc/bash_completion ]; then" >> /root/.bashrc - echo " source /etc/bash_completion" >> /root/.bashrc - echo "fi" >> /root/.bashrc - echo "source $completion_dir/fazai" >> /root/.bashrc - log "SUCCESS" "Bash completion configurado no .bashrc" - fi -} - -# Função para verificar e criar diretório de logs -setup_logging() { - mkdir -p $(dirname $LOG_FILE) - touch $LOG_FILE - log "INFO" "Inicializando log de instalação em $LOG_FILE" - log "INFO" "====== Início da instalação do FazAI v$VERSION ======" - log "INFO" "Data e hora: $(date)" - log "INFO" "Sistema: $(uname -a)" -} - -# Função para verificar permissões de root -check_root() { - log "DEBUG" "Verificando permissões de root..." - if [ "$EUID" -ne 0 ]; then - log "ERROR" "Este script precisa ser executado como root (sudo)." - exit 1 - fi - log "SUCCESS" "Verificação de permissões de root concluída." -} - -# Função para verificar o sistema operacional -check_system() { - log "DEBUG" "Verificando sistema operacional..." - if [ -f /etc/os-release ]; then - . /etc/os-release - # Trata derivados como Ubuntu (ex.: Pop!_OS) - if echo "${ID_LIKE:-}" | grep -qi ubuntu; then - ID=ubuntu - fi - case "$ID" in - debian|ubuntu|pop) - log "SUCCESS" "Sistema Debian/Ubuntu detectado: $NAME $VERSION_ID" - ;; - fedora|rhel|centos) - log "SUCCESS" "Sistema Fedora/RedHat/CentOS detectado: $NAME $VERSION_ID" - ;; - *) - log "WARNING" "Este script foi projetado para Debian, Ubuntu ou Fedora. Detectado: $NAME $VERSION_ID." - read -p "Deseja continuar mesmo assim? (s/n): " -n 1 -r - echo - if [[ ! $REPLY =~ ^[Ss]$ ]]; then - log "INFO" "Instalação cancelada pelo usuário." - exit 1 - fi - log "WARNING" "Prosseguindo instalação em sistema não suportado oficialmente." - ;; - esac - else - log "WARNING" "Não foi possível detectar o sistema operacional. Prosseguindo com cautela." - fi -} - -# Garante runtime de contêiner (Docker) para serviços opcionais (Qdrant/Prometheus/Grafana) -ensure_container_runtime() { - if command -v docker >/dev/null 2>&1 || command -v podman >/dev/null 2>&1; then - log "INFO" "Runtime de contêiner já disponível" - return 0 - fi - log "INFO" "Instalando Docker (runtime de contêiner)" - if command -v apt-get >/dev/null 2>&1; then - apt-get update && apt-get install -y docker.io || log "WARNING" "Falha ao instalar Docker (apt)." - systemctl enable --now docker || true - elif command -v dnf >/dev/null 2>&1; then - dnf install -y docker || log "WARNING" "Falha ao instalar Docker (dnf)." - systemctl enable --now docker || true - elif command -v yum >/dev/null 2>&1; then - yum install -y docker || log "WARNING" "Falha ao instalar Docker (yum)." - systemctl enable --now docker || true - elif command -v zypper >/dev/null 2>&1; then - zypper install -y docker || log "WARNING" "Falha ao instalar Docker (zypper)." - systemctl enable --now docker || true - else - log "WARNING" "Gerenciador de pacotes não suportado para instalação automática do Docker." - fi -} - -# Garantir utilitários de rede usados por scripts e testes -ensure_network_utils() { - log "INFO" "Verificando utilitários de rede (curl, jq, netcat)" - local pkgs=(curl jq netcat) - for p in "${pkgs[@]}"; do - if ! command -v "$p" &>/dev/null; then - log "INFO" "Instalando $p" - if command -v apt-get &>/dev/null; then - apt-get update && apt-get install -y $p || { log "WARNING" "Falha ao instalar $p"; } - elif command -v dnf &>/dev/null; then - dnf install -y $p || { log "WARNING" "Falha ao instalar $p"; } - else - log "WARNING" "Gerenciador de pacotes não detectado; instale $p manualmente" - fi - else - log "DEBUG" "$p já presente" - fi - done -} - -# Função para instalar Node.js com retry e múltiplas versões -install_nodejs() { - if command -v node &> /dev/null; then - NODE_VERSION=$(node -v) - log "SUCCESS" "Node.js já instalado: $NODE_VERSION" - - # Verifica versão mínima do Node.js (>=22.0.0) - NODE_VERSION_NUM=$(echo $NODE_VERSION | cut -c 2-) - NODE_MAJOR=$(echo $NODE_VERSION_NUM | cut -d. -f1) - - if [ $NODE_MAJOR -lt 22 ]; then - log "WARNING" "FazAI requer Node.js versão 22.0.0 ou superior. Versão atual: $NODE_VERSION" - log "INFO" "Tentando atualizar o Node.js..." - install_nodejs_from_source - fi - else - log "WARNING" "Node.js não encontrado. Iniciando instalação..." - install_nodejs_from_source - fi -} - -# Função para instalar Node.js a partir de diferentes fontes -install_nodejs_from_source() { - local success=false - # Detecta gerenciador de pacotes - local PKG_MGR="apt-get" - if [ -f /etc/os-release ]; then - . /etc/os-release - case "$ID" in - fedora|rhel|centos) - PKG_MGR="dnf" - ;; - *) - PKG_MGR="apt-get" - ;; - esac - fi - log "INFO" "Atualizando lista de pacotes..." - $PKG_MGR update -y - $PKG_MGR autoremove -y - $PKG_MGR upgrade -y - log "INFO" "Tentando instalar Node.js via $PKG_MGR..." - $PKG_MGR install -y nodejs npm - if command -v node &> /dev/null; then - NODE_VERSION=$(node -v) - NODE_VERSION_NUM=$(echo $NODE_VERSION | cut -c 2-) - NODE_MAJOR=$(echo $NODE_VERSION_NUM | cut -d. -f1) - if [ $NODE_MAJOR -ge 22 ]; then - log "SUCCESS" "Node.js instalado com sucesso via $PKG_MGR: $NODE_VERSION" - success=true - return 0 - else - log "WARNING" "Versão do Node.js instalada via $PKG_MGR é muito antiga: $NODE_VERSION" - fi - else - log "WARNING" "Falha ao instalar Node.js via $PKG_MGR." - fi - # Tenta instalar via NodeSource para diferentes versões (apenas para Debian/Ubuntu) - if [ "$success" = false ] && [ "$PKG_MGR" = "apt-get" ]; then - if ! command -v curl &> /dev/null; then - $PKG_MGR install -y curl - fi - for version in "${NODE_VERSIONS[@]}"; do - log "INFO" "Tentando instalar Node.js v$version via NodeSource..." - for attempt in $(seq 1 $RETRY_COUNT); do - log "DEBUG" "Tentativa $attempt de $RETRY_COUNT para Node.js v$version" - if curl -fsSL "https://deb.nodesource.com/setup_${version}.x" | bash - && $PKG_MGR install -y nodejs; then - if command -v node &> /dev/null; then - NODE_VERSION=$(node -v) - log "SUCCESS" "Node.js instalado com sucesso: $NODE_VERSION" - success=true - break 2 - fi - fi - log "WARNING" "Tentativa $attempt falhou para Node.js v$version" - sleep 2 - done - done - fi - if [ "$success" = false ]; then - log "ERROR" "Todas as tentativas de instalação do Node.js falharam." - log "ERROR" "Por favor, instale o Node.js manualmente e execute este script novamente." - log "ERROR" "Visite: https://nodejs.org/en/download/package-manager/" - exit 1 - fi -} - -# Função para verificar e instalar npm -install_npm() { - local PKG_MGR="apt-get" - if [ -f /etc/os-release ]; then - . /etc/os-release - case "$ID" in - fedora|rhel|centos) - PKG_MGR="dnf" - ;; - *) - PKG_MGR="apt-get" - ;; - esac - fi - if ! command -v npm &> /dev/null; then - log "WARNING" "npm não encontrado. Instalando..." - $PKG_MGR install -y npm - if ! command -v npm &> /dev/null; then - log "ERROR" "Falha ao instalar npm via $PKG_MGR." - exit 1 - else - NPM_VERSION=$(npm -v) - log "SUCCESS" "npm instalado com sucesso: $NPM_VERSION" - fi - else - NPM_VERSION=$(npm -v) - log "SUCCESS" "npm já instalado: $NPM_VERSION" - fi -} - -# Função para verificar e instalar Python 3 -install_python() { - local PKG_MGR="apt-get" - if [ -f /etc/os-release ]; then - . /etc/os-release - case "$ID" in - fedora|rhel|centos) - PKG_MGR="dnf" - ;; - *) - PKG_MGR="apt-get" - ;; - esac - fi - if command -v python3 &> /dev/null; then - PYTHON_VERSION=$(python3 --version | awk '{print $2}') - PYTHON_MAJOR=$(echo "$PYTHON_VERSION" | cut -d. -f1) - PYTHON_MINOR=$(echo "$PYTHON_VERSION" | cut -d. -f2) - if [ "$PYTHON_MAJOR" -lt 3 ] || { [ "$PYTHON_MAJOR" -eq 3 ] && [ "$PYTHON_MINOR" -lt 10 ]; }; then - log "WARNING" "FazAI requer Python 3.10 ou superior. Versão atual: $PYTHON_VERSION" - $PKG_MGR install -y python3 python3-pip - fi - else - log "WARNING" "Python3 não encontrado. Instalando..." - $PKG_MGR install -y python3 python3-pip - fi - if command -v python3 &> /dev/null; then - PYTHON_VERSION=$(python3 --version | awk '{print $2}') - log "SUCCESS" "python3 instalado: $PYTHON_VERSION" - else - log "ERROR" "Falha ao instalar python3." - exit 1 - fi -} - -# Função para verificar e instalar gcc -install_gcc() { - local PKG_MGR="apt-get" - if [ -f /etc/os-release ]; then - . /etc/os-release - case "$ID" in - fedora|rhel|centos) - PKG_MGR="dnf" - ;; - *) - PKG_MGR="apt-get" - ;; - esac - fi - if ! command -v gcc &> /dev/null; then - log "WARNING" "gcc não encontrado. Instalando build-essential..." - $PKG_MGR install -y gcc g++ make cmake - if ! command -v gcc &> /dev/null; then - log "ERROR" "Falha ao instalar gcc. Por favor, instale manualmente." - exit 1 - fi - GCC_VERSION=$(gcc --version | head -n1) - CMAKE_VERSION=$(cmake --version 2>/dev/null | head -n1) - log "SUCCESS" "gcc instalado com sucesso: $GCC_VERSION" - [ -n "$CMAKE_VERSION" ] && log "SUCCESS" "cmake disponível: $CMAKE_VERSION" - else - GCC_VERSION=$(gcc --version | head -n1) - CMAKE_VERSION=$(cmake --version 2>/dev/null | head -n1) - log "SUCCESS" "gcc já instalado: $GCC_VERSION" - [ -n "$CMAKE_VERSION" ] && log "SUCCESS" "cmake disponível: $CMAKE_VERSION" - fi -} - - - -# Função para criar estrutura de diretórios -create_directories() { - log "INFO" "Criando estrutura de diretórios..." - - # Garante a criação do diretório de logs - if [ ! -d "/var/log/fazai" ]; then - mkdir -p "/var/log/fazai" - log "SUCCESS" "Diretório /var/log/fazai criado" - fi - - local directories=( - "/opt/fazai/bin" - "/opt/fazai/lib" - "/opt/fazai/tools" - "/opt/fazai/mods" - " /opt/fazai/models" - "/etc/fazai" - "/var/log/fazai" - "/var/lib/fazai/history" - "/var/lib/fazai/cache" - "/var/lib/fazai/data" - "/var/backups/fazai" - ) - - for dir in "${directories[@]}"; do - if [ ! -d "$dir" ]; then - mkdir -p "$dir" - log "DEBUG" "Diretório criado: $dir" - else - log "DEBUG" "Diretório já existe: $dir" - fi - done - # Diretório de segredos OPNsense (permissões estritas) - mkdir -p /etc/fazai/secrets/opnsense && chmod 700 /etc/fazai/secrets/opnsense || true - - # Garantir diretório de modelos com permissões apropriadas - if [ ! -d "/opt/fazai/models" ]; then - mkdir -p /opt/fazai/models - chown root:root /opt/fazai/models - chmod 755 /opt/fazai/models - log "DEBUG" "Diretório /opt/fazai/models criado" - fi - - log "SUCCESS" "Estrutura de diretórios criada com sucesso." -} - -# Verifica saúde do serviço e tenta autorreparo básico -health_check_repair() { - log "INFO" "Executando health-check do FazAI (/agent/status)" - local API="http://127.0.0.1:3120" - local ok=false - for attempt in 1 2 3; do - if curl -fsS --max-time 3 "$API/agent/status" >/dev/null 2>&1; then - ok=true - break - fi - log "WARNING" "Health-check falhou (tentativa $attempt). Tentando reparo..." - # Reinicia o worker e o serviço mestre - systemctl restart fazai-gemma-worker 2>/dev/null || true - sleep 1 - # Garante diretório do socket - mkdir -p /run/fazai && chmod 755 /run/fazai || true - systemctl restart fazai 2>/dev/null || true - sleep 2 - # Se o binário do worker não existir, tenta compilar/instalar - if [ ! -x "/opt/fazai/bin/fazai-gemma-worker" ] && [ -d "worker" ] && [ -f "worker/CMakeLists.txt" ]; then - log "INFO" "Binário do worker ausente; tentando compilar/instalar..." - (cd worker && ./build.sh && sudo make install) || true - systemctl restart fazai-gemma-worker 2>/dev/null || true - sleep 1 - fi - done - if [ "$ok" = true ]; then - log "SUCCESS" "Health-check OK: /agent/status respondeu" - else - log "ERROR" "Health-check ainda falhou após tentativas de reparo. Verifique logs do serviço." - fi -} - -# Função para copiar arquivos -copy_files() { - log "INFO" "Copiando arquivos para diretórios de instalação..." - - local copy_errors=0 - - # Cria função auxiliar para cópia com verificação de erros - copy_with_verification() { - local source=$1 - local destination=$2 - local description=$3 - - if [ ! -e "$source" ]; then - log "ERROR" "Arquivo de origem ausente para $description: $source" - return 1 - fi - - local output - if output=$(cp -r "$source" "$destination" 2>&1); then - local dest_path="$destination" - if [ -d "$destination" ]; then - dest_path="$destination/$(basename "$source")" - fi - if [ -e "$dest_path" ]; then - log "DEBUG" "$description copiado de $source para $destination" - return 0 - else - log "ERROR" "Arquivo não encontrado após copiar $source para $destination" - return 1 - fi - else - log "ERROR" "Falha ao copiar $description ($source -> $destination): $output" - return 1 - fi - } - - - - # Cria CLI básico se não existir - if [ ! -f "bin/fazai" ]; then - log "INFO" "Criando CLI básico..." - mkdir -p "bin" - cat > "bin/fazai" << 'EOF' -#!/usr/bin/env node - -/** - * FazAI CLI - */ - -const { spawn } = require('child_process'); -const fs = require('fs'); - -const args = process.argv.slice(2); - -if (args.includes('--version')) { - console.log('FazAI v2.0.0'); - process.exit(0); -} - -if (args.includes('--help')) { - console.log('FazAI - Orquestrador Inteligente de Automação'); - console.log(''); - console.log('Uso: fazai [comando] [opções]'); - console.log(''); - console.log('Comandos:'); - console.log(' --version Mostra a versão'); - console.log(' --help Mostra esta ajuda'); - console.log(' --status Status do daemon'); - console.log(' --start Inicia o daemon'); - console.log(' --stop Para o daemon'); - console.log(' --restart Reinicia o daemon'); - process.exit(0); -} - -if (args.includes('--status')) { - const { execSync } = require('child_process'); - try { - const status = execSync('systemctl is-active fazai', { encoding: 'utf8' }).trim(); - console.log(`FazAI daemon: ${status}`); - } catch (error) { - console.log('FazAI daemon: inativo'); - } - process.exit(0); -} - -console.log('FazAI CLI v2.0.0 - Use --help para mais informações'); -EOF - chmod +x "bin/fazai" - fi - - # Garante que o arquivo de configuração exemplo exista - if [ ! -f "etc/fazai/fazai.conf.example" ]; then - log "ERROR" "etc/fazai/fazai.conf.example não encontrado. Verifique o repositório." - exit 1 - fi - - # Agora copia os arquivos - # Copia toda a biblioteca (inclui handlers, core, providers, etc.) - if ! copy_with_verification "opt/fazai/lib" "/opt/fazai/" "Biblioteca FazAI"; then - copy_errors=$((copy_errors+1)) - else - # Garante permissão de execução no entrypoint - chmod 755 /opt/fazai/lib/main.js 2>/dev/null || true - fi - - - - # Copia módulos e integrações adicionais necessários - for f in \ - "opt/fazai/lib/mcp_opnsense.js" \ - "opt/fazai/lib/complex_tasks.js" \ - "opt/fazai/tools/fazai_web_frontend.html" \ - "opt/fazai/tools/web_search.js" \ - "opt/fazai/tools/suricata_setup.js" \ - "opt/fazai/tools/modsecurity_setup.js" \ - "opt/fazai/tools/crowdsec_setup.js" \ - "opt/fazai/tools/spamexperts.js" \ - "opt/fazai/tools/cloudflare.js" \ - ; do - if [ -f "$f" ]; then - if ! copy_with_verification "$f" "/opt/fazai/$(dirname ${f#opt/fazai/})/" "$(basename $f)"; then - copy_errors=$((copy_errors+1)) - fi - fi - done - - # Copia todas as ferramentas para garantir que plugins sejam carregados - if [ -d "opt/fazai/tools" ]; then - if ! copy_with_verification "opt/fazai/tools" "/opt/fazai/" "Ferramentas FazAI"; then - copy_errors=$((copy_errors+1)) - fi - fi - - # Copia interface web (DOCLER) - if [ -d "opt/fazai/web" ]; then - if ! copy_with_verification "opt/fazai/web" "/opt/fazai/" "Interface Web"; then - copy_errors=$((copy_errors+1)) - fi - # Instalar dependências do web server (express, ws) - if [ -f "/opt/fazai/web/package.json" ]; then - log "INFO" "Instalando dependências da interface web (/opt/fazai/web)" - (cd /opt/fazai/web && npm install --omit=dev --no-audit --no-progress || true) - # Tenta instalar autenticação PAM (opcional) - (cd /opt/fazai/web && npm install authenticate-pam --no-audit --no-progress || true) - fi - - # Cria usuário de serviço não-root para o Docler - if ! id -u fazai-web >/dev/null 2>&1; then - log "INFO" "Criando usuário de serviço 'fazai-web' (sem shell de login)" - useradd --system --home /opt/fazai/web --shell /usr/sbin/nologin fazai-web || true - fi - # Corrige permissões para acesso do usuário fazai-web - chmod 755 /opt/fazai || true - chmod 755 /opt/fazai/web || true - chown -R fazai:fazai-web /opt/fazai/web || true - chmod -R g+rx /opt/fazai/web || true - fi - - # Instalar Qdrant Vector Database - log "INFO" "Instalando Qdrant Vector Database..." - if [ ! -f "/opt/fazai/bin/qdrant" ]; then - log "INFO" "Baixando Qdrant binário..." - if curl -L https://github.com/qdrant/qdrant/releases/latest/download/qdrant-x86_64-unknown-linux-gnu.tar.gz -o /tmp/qdrant.tar.gz 2>/dev/null; then - tar -xzf /tmp/qdrant.tar.gz -C /opt/fazai/bin/ 2>/dev/null || log "WARN" "Falha ao extrair Qdrant - usando Docker fallback" - chmod +x /opt/fazai/bin/qdrant 2>/dev/null || true - rm -f /tmp/qdrant.tar.gz - log "INFO" "Qdrant binário instalado" - else - log "WARN" "Falha no download do Qdrant - será usado via Docker" - fi - fi - - # Criar diretórios e configuração do Qdrant - mkdir -p /var/lib/qdrant /opt/fazai/web/static - chown -R fazai:fazai /var/lib/qdrant - - # Configuração Qdrant - cat > /etc/fazai/qdrant.yaml << 'EOF' -log_level: INFO -storage: - storage_path: /var/lib/qdrant/storage - snapshots_path: /var/lib/qdrant/snapshots - on_disk_payload: true - -service: - http_port: 6333 - grpc_port: 6334 - host: 0.0.0.0 - max_request_size_mb: 32 - max_workers: 0 - static_content_dir: /opt/fazai/web/static - enable_cors: true - -web_ui: - enabled: true - -cluster: - enabled: false - -telemetry_disabled: false -EOF - - # Copia binários auxiliares (inclui fazai-gemma-worker e utilitários) - if [ -d "opt/fazai/bin" ]; then - if ! copy_with_verification "opt/fazai/bin" "/opt/fazai/" "Binários FazAI"; then - copy_errors=$((copy_errors+1)) - else - chmod -R 755 /opt/fazai/bin 2>/dev/null || true - fi - fi - - # Copia modelos Gemma se estiverem no repositório (estrutura antiga) - if [ -d "opt/fazai/models/gemma" ]; then - if ! copy_with_verification "opt/fazai/models/gemma" "/opt/fazai/models/" "Modelos Gemma"; then - copy_errors=$((copy_errors+1)) - fi - else - # Nova estrutura: pesos e tokenizer embarcados junto ao fonte - # Preferir em worker/src/gemma.cpp/, fallback para gemma.cpp/ na raiz - SRC_DIR="" - if [ -f "worker/src/gemma.cpp/2.0-2b-it-sfp.sbs" ] || [ -f "worker/src/gemma.cpp/tokenizer.spm" ]; then - SRC_DIR="worker/src/gemma.cpp" - elif [ -f "gemma.cpp/2.0-2b-it-sfp.sbs" ] || [ -f "gemma.cpp/tokenizer.spm" ]; then - SRC_DIR="gemma.cpp" - fi - if [ -n "$SRC_DIR" ]; then - mkdir -p /opt/fazai/models/gemma - if [ -f "$SRC_DIR/2.0-2b-it-sfp.sbs" ]; then - log "INFO" "Copiando pesos Gemma de $SRC_DIR para /opt/fazai/models/gemma/" - cp -f "$SRC_DIR/2.0-2b-it-sfp.sbs" "/opt/fazai/models/gemma/" || copy_errors=$((copy_errors+1)) - fi - if [ -f "$SRC_DIR/tokenizer.spm" ]; then - log "INFO" "Copiando tokenizer Gemma de $SRC_DIR para /opt/fazai/models/gemma/" - cp -f "$SRC_DIR/tokenizer.spm" "/opt/fazai/models/gemma/" || copy_errors=$((copy_errors+1)) - fi - chmod 644 /opt/fazai/models/gemma/* 2>/dev/null || true - - # Atualiza fazai.conf com caminhos detectados - if [ -f "/etc/fazai/fazai.conf" ]; then - WEIGHTS_PATH="/opt/fazai/models/gemma/2.0-2b-it-sfp.sbs" - TOKENIZER_PATH="/opt/fazai/models/gemma/tokenizer.spm" - if [ -f "$WEIGHTS_PATH" ]; then - sed -i "/^\[gemma_cpp\]/,/^\[/ s|^weights\s*=.*|weights = $WEIGHTS_PATH|" /etc/fazai/fazai.conf || true - fi - if [ -f "$TOKENIZER_PATH" ]; then - sed -i "/^\[gemma_cpp\]/,/^\[/ s|^tokenizer\s*=.*|tokenizer = $TOKENIZER_PATH|" /etc/fazai/fazai.conf || true - fi - sed -i "/^\[gemma_cpp\]/,/^\[/ s|^endpoint\s*=.*|endpoint = /opt/fazai/bin/gemma_oneshot|" /etc/fazai/fazai.conf || true - sed -i "/^\[gemma_cpp\]/,/^\[/ s|^default_model\s*=.*|default_model = gemma2-2b-it|" /etc/fazai/fazai.conf || true - fi - else - # Fallback: caminho externo informado pelo usuário - if [ -d "/media/rluft/fedora/root/opt/fazai/models/gemma" ]; then - if ! copy_with_verification "/media/rluft/fedora/root/opt/fazai/models/gemma" "/opt/fazai/models/" "Modelos Gemma (externo)"; then - copy_errors=$((copy_errors+1)) - fi - fi - fi - fi - - # Compila e instala o binário real gemma_oneshot se as fontes estiverem em worker/src/gemma.cpp - if [ -d "worker/src/gemma.cpp" ] && [ -f "worker/src/gemma.cpp/CMakeLists.txt" ]; then - log "INFO" "Compilando gemma.cpp (gemma_oneshot) a partir de worker/src/gemma.cpp..." - ( - cd worker/src/gemma.cpp - mkdir -p build - cd build - cmake .. -DCMAKE_BUILD_TYPE=Release || true - make -j$(nproc) gemma_oneshot || make gemma_oneshot || true - ) - if [ -x "worker/src/gemma.cpp/build/gemma_oneshot" ]; then - install -m 0755 "worker/src/gemma.cpp/build/gemma_oneshot" "/opt/fazai/bin/gemma_oneshot.real" || true - log "SUCCESS" "gemma_oneshot.real instalado em /opt/fazai/bin" - else - log "WARNING" "Falha ao compilar gemma_oneshot. O wrapper tentará outros caminhos se existir um binário no sistema." - fi - fi - - # DeepSeek helper removido (no-op) - - if ! copy_with_verification "etc/fazai/fazai.conf.example" "/etc/fazai/fazai.conf.default" "Configuração padrão"; then - copy_errors=$((copy_errors+1)) - fi - - # Preserva configuracao atual antes de substituir - if [ -f "/etc/fazai/fazai.conf" ]; then - cp /etc/fazai/fazai.conf /etc/fazai/fazai.conf.bak && \ - log "INFO" "Backup criado em fazai.conf.bak" - mv /etc/fazai/fazai.conf /etc/fazai/fazai.conf.old - log "INFO" "Configuração existente renomeada para fazai.conf.old" - fi - - if ! copy_with_verification "etc/fazai/fazai.conf.example" "/etc/fazai/fazai.conf" "Configuração de sistema"; then - copy_errors=$((copy_errors+1)) - else - log "SUCCESS" "Novo arquivo de configuração criado em /etc/fazai/fazai.conf" - - if [ -f "/etc/fazai/fazai.conf.old" ]; then - for prov in openrouter requesty openai; do - key_val=$(awk -v sec="[$prov]" '$0==sec{f=1;next} /^\[/{f=0} f && /api_key/{print $3}' /etc/fazai/fazai.conf.old) - if [ -n "$key_val" ]; then - sed -i "/^\[$prov\]/,/^$/s|api_key =.*|api_key = $key_val|" /etc/fazai/fazai.conf - fi - done - fi - if [ -f "/root/.env" ]; then - /bin/bash /opt/fazai/tools/sync-keys.sh >/dev/null 2>&1 && log "INFO" "Chaves sincronizadas do .env" - fi - fi - - # Copia gemma_bootstrap - if [ -f "opt/fazai/tools/gemma_bootstrap.sh" ]; then - if ! copy_with_verification "opt/fazai/tools/gemma_bootstrap.sh" "/opt/fazai/tools/" "Gemma bootstrap"; then - copy_errors=$((copy_errors+1)) - else - chmod +x /opt/fazai/tools/gemma_bootstrap.sh - log "SUCCESS" "Gemma bootstrap instalado" - fi - fi - - # Copia complex_tasks.conf.example se existir - if [ -f "etc/fazai/complex_tasks.conf.example" ]; then - if ! copy_with_verification "etc/fazai/complex_tasks.conf.example" "/etc/fazai/complex_tasks.conf.default" "Configuração de tarefas complexas"; then - copy_errors=$((copy_errors+1)) - else - log "SUCCESS" "Configuração de tarefas complexas copiada" - fi - fi - - # Copia manual para /opt/fazai/MANUAL_COMPLETO.md (fallback para MANUAL_FERRAMENTAS.md) - if [ -f "MANUAL_COMPLETO.md" ]; then - if ! copy_with_verification "MANUAL_COMPLETO.md" "/opt/fazai/" "Manual completo"; then - copy_errors=$((copy_errors+1)) - fi - elif [ -f "MANUAL_FERRAMENTAS.md" ]; then - if ! copy_with_verification "MANUAL_FERRAMENTAS.md" "/opt/fazai/" "Manual de ferramentas"; then - copy_errors=$((copy_errors+1)) - else - # Mantém o nome esperado pelo CLI - cp -f "/opt/fazai/MANUAL_FERRAMENTAS.md" "/opt/fazai/MANUAL_COMPLETO.md" 2>/dev/null || true - fi - else - log "WARNING" "Manual não encontrado no repositório (MANUAL_COMPLETO.md/MANUAL_FERRAMENTAS.md)" - fi - - if ! copy_with_verification "bin/fazai" "/opt/fazai/bin/" "CLI"; then - copy_errors=$((copy_errors+1)) - fi - chmod 755 /opt/fazai/bin/fazai - ln -sf /opt/fazai/bin/fazai /usr/local/bin/fazai - log "SUCCESS" "CLI instalado em /usr/local/bin/fazai" - - # Instala GPT-Web2Shell (utilitário externo, exclusivo - OPT-IN via FAZAI_ENABLE_GPT_WEB2SHELL=1) - if [ "${FAZAI_ENABLE_GPT_WEB2SHELL}" = "1" ]; then - EXTRA_DIR="${FAZAI_LOCAL_EXTRAS_DIR:-}" - # Preferir extras externos - if [ -n "$EXTRA_DIR" ] && [ -f "$EXTRA_DIR/gpt-web2shell/bin/gpt-web2shell" ]; then - log "INFO" "Instalando GPT-Web2Shell a partir de FAZAI_LOCAL_EXTRAS_DIR=$EXTRA_DIR" - mkdir -p /opt/fazai/bin /opt/fazai/tools - cp -f "$EXTRA_DIR/gpt-web2shell/bin/gpt-web2shell" /opt/fazai/bin/gpt-web2shell - cp -f "$EXTRA_DIR/gpt-web2shell/opt/fazai/tools/gpt-web2shell.js" /opt/fazai/tools/gpt-web2shell.js - chmod 755 /opt/fazai/bin/gpt-web2shell /opt/fazai/tools/gpt-web2shell.js || true - ln -sf /opt/fazai/bin/gpt-web2shell /usr/local/bin/gpt-web2shell - log "SUCCESS" "GPT-Web2Shell instalado em /usr/local/bin/gpt-web2shell (extras externos)" - elif [ -f "bin/gpt-web2shell" ] && [ -f "opt/fazai/tools/gpt-web2shell.js" ]; then - # fallback: se os arquivos estiverem presentes no diretório do repositório - if copy_with_verification "bin/gpt-web2shell" "/opt/fazai/bin/" "GPT-Web2Shell"; then - mkdir -p /opt/fazai/tools - cp -f "opt/fazai/tools/gpt-web2shell.js" "/opt/fazai/tools/gpt-web2shell.js" - chmod 755 /opt/fazai/bin/gpt-web2shell /opt/fazai/tools/gpt-web2shell.js || true - ln -sf /opt/fazai/bin/gpt-web2shell /usr/local/bin/gpt-web2shell - log "SUCCESS" "GPT-Web2Shell instalado em /usr/local/bin/gpt-web2shell" - else - log "WARNING" "Falha ao instalar GPT-Web2Shell (arquivos locais)" - fi - else - log "WARNING" "FAZAI_ENABLE_GPT_WEB2SHELL=1 definido, mas arquivos não encontrados. Use scripts/install-web2shell.sh com FAZAI_LOCAL_EXTRAS_DIR." - fi - else - log "INFO" "GPT-Web2Shell não instalado (exclusivo). Para instalar, exporte FAZAI_ENABLE_GPT_WEB2SHELL=1 e forneça os arquivos via FAZAI_LOCAL_EXTRAS_DIR." - fi - - # Copia ferramentas do bin/tools para /opt/fazai/tools - if [ -d "bin/tools" ]; then - log "INFO" "Copiando ferramentas do bin/tools..." - if ! copy_with_verification "bin/tools/github-setup.sh" "/opt/fazai/tools/" "GitHub Setup Script"; then - copy_errors=$((copy_errors+1)) - fi - if ! copy_with_verification "bin/tools/sync-changes.sh" "/opt/fazai/tools/" "Sync Changes Script"; then - copy_errors=$((copy_errors+1)) - fi - if ! copy_with_verification "bin/tools/sync-keys.sh" "/opt/fazai/tools/" "Sync Keys Script"; then - copy_errors=$((copy_errors+1)) - fi - if ! copy_with_verification "bin/tools/system-check.sh" "/opt/fazai/tools/" "System Check Script"; then - copy_errors=$((copy_errors+1)) - fi - if ! copy_with_verification "bin/tools/test-all-tools.sh" "/opt/fazai/tools/" "Test All Tools Script"; then - copy_errors=$((copy_errors+1)) - fi - if ! copy_with_verification "bin/tools/version-bump.sh" "/opt/fazai/tools/" "Version Bump Script"; then - copy_errors=$((copy_errors+1)) - fi - if ! copy_with_verification "bin/tools/install-llamacpp.sh" "/opt/fazai/tools/" "LLaMA Install Script"; then - copy_errors=$((copy_errors+1)) - fi - - # Torna os scripts executáveis - chmod +x /opt/fazai/tools/*.sh 2>/dev/null - log "SUCCESS" "Ferramentas copiadas e tornadas executáveis" - fi - - # Copia módulos nativos se existirem - if [ -f "opt/fazai/mods/system_mod.so" ]; then - if ! copy_with_verification "opt/fazai/mods/system_mod.so" "/opt/fazai/mods/" "Módulo nativo system_mod"; then - copy_errors=$((copy_errors+1)) - else - log "SUCCESS" "Módulo nativo copiado" - fi - fi - - # Compila módulo system_mod.c se existir - if [ -f "opt/fazai/lib/mods/system_mod.c" ]; then - log "INFO" "Compilando módulo system_mod.c..." - mkdir -p /opt/fazai/lib/mods/ - cp -r opt/fazai/lib/mods/* /opt/fazai/lib/mods/ 2>/dev/null || true - - cd /opt/fazai/lib/mods/ - if [ -f "compile_system_mod.sh" ]; then - chmod +x compile_system_mod.sh - # Verifica dependências primeiro (sem instalar) - ./compile_system_mod.sh --check || log "WARNING" "Pendências detectadas; tentando auto-instalação e compilação." - # Compila (com auto-instalação de pacotes quando necessário) - ./compile_system_mod.sh || log "WARNING" "Falha na compilação do system_mod.c" - # Publica .so - mkdir -p /opt/fazai/mods - cp -f /opt/fazai/lib/mods/*.so /opt/fazai/mods/ 2>/dev/null || true - if ls /opt/fazai/mods/*.so >/dev/null 2>&1; then - log "SUCCESS" "Módulos nativos disponibilizados em /opt/fazai/mods" - else - log "WARNING" "Nenhum módulo .so encontrado após compilação" - fi - else - # Compilação manual se o script não existir - log "WARNING" "Script de compilação não encontrado, tentando compilação manual..." - gcc -shared -fPIC -o system_mod.so system_mod.c -lclamav -lcurl -ljson-c -lpthread 2>/dev/null || log "WARNING" "Falha na compilação do system_mod.c (dependências podem estar faltando)" - mkdir -p /opt/fazai/mods - cp -f /opt/fazai/lib/mods/system_mod.so /opt/fazai/mods/ 2>/dev/null || true - fi - cd - > /dev/null - fi - - - - # Copia novas tools - for t in \ - "opt/fazai/tools/auto_tool.js" \ - "opt/fazai/tools/net_qos_monitor.js" \ - "opt/fazai/tools/agent_supervisor.js" \ - "opt/fazai/tools/qdrant_setup.js" \ - "opt/fazai/tools/snmp_monitor.js" \ - "opt/fazai/tools/modsecurity_setup.js" \ - "opt/fazai/tools/suricata_setup.js" \ - "opt/fazai/tools/crowdsec_setup.js" \ - "opt/fazai/tools/monit_setup.js" \ - "opt/fazai/tools/rag_ingest.js" \ - "opt/fazai/tools/download_gemma2.sh" \ - "opt/fazai/tools/install_python_deps.sh" \ - "opt/fazai/tools/alerts.js" \ - "opt/fazai/tools/blacklist_check.js" \ - "opt/fazai/tools/email_relay.js" \ - "opt/fazai/tools/geoip_lookup.js" \ - "opt/fazai/tools/http_fetch.js" \ - "opt/fazai/tools/ports_monitor.js" \ - "opt/fazai/tools/system_info.js" \ - "opt/fazai/tools/test_complex_tasks.js" \ - "opt/fazai/tools/weather.js" \ - "opt/fazai/tools/crowdsec.js" \ - "opt/fazai/tools/modsecurity.js" \ - "opt/fazai/tools/spamexperts.js" \ - "opt/fazai/tools/web_search.js" \ - "opt/fazai/tools/cloudflare.js"; do - if [ -f "$t" ]; then - if ! copy_with_verification "$t" "/opt/fazai/tools/" "Tool $(basename $t)"; then - copy_errors=$((copy_errors+1)) - else - chmod 755 "/opt/fazai/tools/$(basename $t)" || true - fi - fi - done - - # Instala dependência dialog para alguns scripts - install_dialog - - # Copia interface web front-end - if [ -f "opt/fazai/tools/fazai_web_frontend.html" ]; then - if ! copy_with_verification "opt/fazai/tools/fazai_web_frontend.html" "/opt/fazai/tools/" "Interface web"; then - copy_errors=$((copy_errors+1)) - else - chmod 644 "/opt/fazai/tools/fazai_web_frontend.html" - log "SUCCESS" "Interface web instalada" - fi - else - log "WARNING" "Interface web não encontrado, crio fallback básico..." - cat > "/opt/fazai/tools/fazai_web_frontend.html" << 'EOF' - - - - - - FazAI - Interface Web - - -

FazAI Interface Web

-

Interface básica gerada automaticamente.

- - -EOF - log "SUCCESS" "Interface web fallback criada" - fi - if [ -f "opt/fazai/tools/fazai-tui.sh" ]; then - if ! copy_with_verification "opt/fazai/tools/fazai-tui.sh" "/opt/fazai/tools/" "Dashboard TUI completo"; then - copy_errors=$((copy_errors+1)) - else - chmod +x /opt/fazai/tools/fazai-tui.sh - ln -sf /opt/fazai/tools/fazai-tui.sh /usr/local/bin/fazai-tui - log "SUCCESS" "Dashboard TUI completo instalado em /usr/local/bin/fazai-tui" - fi - if command -v cargo >/dev/null 2>&1; then - log "INFO" "Compilando TUI em Rust..." - if cargo build --release --manifest-path=tui/Cargo.toml >/tmp/fazai_tui_build.log 2>&1; then - cp tui/target/release/fazai-tui /opt/fazai/tools/fazai-tui-rs - ln -sf /opt/fazai/tools/fazai-tui-rs /usr/local/bin/fazai-tui - log "SUCCESS" "TUI Rust instalado em /usr/local/bin/fazai-tui" - else - log "WARNING" "Falha ao compilar TUI Rust, utilizando script bash" - fi - fi - else - log "WARNING" "Dashboard TUI não encontrado, criando versão básica..." - cat > "/opt/fazai/tools/fazai-tui.sh" << 'EOF' -#!/bin/bash -# FazAI Dashboard TUI - Versão Básica -echo "FazAI Dashboard TUI v2.0.0" -echo "Opções:" -echo " [l] Ver logs | [s] Status | [q] Sair" -while read -r -n1 -p "Selecione: " k; do - echo - case "$k" in - l) curl -fsS http://localhost:3120/logs | jq . || true ;; - s) curl -fsS http://localhost:3120/status | jq . || true ;; - q) echo "Saindo..."; exit 0 ;; - *) echo "Opção inválida" ;; - esac -done -EOF - chmod +x "/opt/fazai/tools/fazai-tui.sh" - ln -sf /opt/fazai/tools/fazai-tui.sh /usr/local/bin/fazai-tui - log "SUCCESS" "Dashboard TUI básico instalado em /usr/local/bin/fazai-tui" - - log "WARNING" "Interface web não encontrada, criando versão básica..." - # Cria uma versão básica se não existir - cat > "/opt/fazai/tools/fazai_web_frontend.html" << 'EOF' - - - - - - FazAI - Interface Web - - - -
-

FazAI - Interface Web

-
-

Gerenciamento de Logs

- - - -
-
-

Status do Sistema

- -
-
-
- - - -EOF - log "SUCCESS" "Interface web básica criada" - fi - - # Copia script de lançamento da interface web - if [ -f "opt/fazai/tools/fazai_web.sh" ]; then - if ! copy_with_verification "opt/fazai/tools/fazai_web.sh" "/opt/fazai/tools/" "Script de lançamento web"; then - copy_errors=$((copy_errors+1)) - else - chmod +x "/opt/fazai/tools/fazai_web.sh" - log "SUCCESS" "Script de lançamento web instalado" - fi - else - log "WARNING" "Script de lançamento web não encontrado, criando versão básica..." - cat > "/opt/fazai/tools/fazai_web.sh" << 'EOF' - #!/bin/bash - # FazAI Web Frontend Launcher - # Caminho: /opt/fazai/tools/fazai_web.sh - - FRONTEND_FILE="/opt/fazai/tools/fazai_web_frontend.html" - - if [ ! -f "$FRONTEND_FILE" ]; then - echo "Erro: Interface web não encontrada: $FRONTEND_FILE" - exit 1 - fi - - echo "Iniciando interface web do FazAI..." - - # Detecta o sistema e abre o navegador - if [[ "$OSTYPE" == "linux-gnu"* ]]; then - if command -v xdg-open > /dev/null; then - xdg-open "$FRONTEND_FILE" - elif command -v firefox > /dev/null; then - firefox "$FRONTEND_FILE" - else - echo "Abra manualmente: $FRONTEND_FILE" - fi - elif [[ "$OSTYPE" == "darwin"* ]]; then - open "$FRONTEND_FILE" - elif [[ "$OSTYPE" == "cygwin" || "$OSTYPE" == "msys" ]]; then - start "$FRONTEND_FILE" - else - echo "Abra manualmente: $FRONTEND_FILE" - fi - - echo "Interface web disponível em: file://$FRONTEND_FILE" -EOF - chmod +x "/opt/fazai/tools/fazai_web.sh" - log "SUCCESS" "Script de lançamento web básico criado" - fi - - # Copia gerador de visualização HTML - if [ -f "opt/fazai/tools/fazai_html_v1.sh" ]; then - if ! copy_with_verification "opt/fazai/tools/fazai_html_v1.sh" "/opt/fazai/tools/" "Gerador HTML"; then - copy_errors=$((copy_errors+1)) - else - chmod +x "/opt/fazai/tools/fazai_html_v1.sh" - ln -sf /opt/fazai/tools/fazai_html_v1.sh /usr/local/bin/fazai-html - log "SUCCESS" "Gerador HTML instalado em /usr/local/bin/fazai-html" - fi - fi - - if [ "$copy_errors" -ne 0 ]; then - log "ERROR" "$copy_errors falha(s) ao copiar arquivos. Veja $LOG_FILE para detalhes." - return 1 - fi - - log "SUCCESS" "Arquivos copiados com sucesso." - } - - # Função para importar configurações de .env - import_env_config() { - log "INFO" "Verificando configurações de ambiente..." - - # Locais possíveis do arquivo .env - local env_locations=( - "/root/.env" - "$HOME/.env" - "./.env" - ".env.example" - ) - - local env_file="" - - # Procura o primeiro arquivo .env disponível - for location in "${env_locations[@]}"; do - if [ -f "$location" ]; then - env_file="$location" - log "INFO" "Arquivo .env encontrado em $env_file" - break - fi - done - - if [ -n "$env_file" ]; then - log "INFO" "Arquivo .env encontrado. Importando configurações..." - - # Extrai chaves de API - local api_keys=( - "OPENAI_API_KEY" - "ANTHROPIC_API_KEY" - "GOOGLE_API_KEY" - "AZURE_API_KEY" - ) - - local fazai_conf="/etc/fazai/fazai.conf" - local changes_made=false - - for key in "${api_keys[@]}"; do - local value=$(grep "^$key=" "$env_file" 2>/dev/null | cut -d'=' -f2 | tr -d '"' | tr -d "'") - if [ -n "$value" ]; then - local config_key=$(echo "$key" | tr '[:upper:]' '[:lower:]') - - # Verifica se a chave já existe no arquivo de configuração - if grep -q "^$config_key" "$fazai_conf"; then - # Substitui o valor existente - sed -i "s|^$config_key.*|$config_key = $value|" "$fazai_conf" - else - # Adiciona nova entrada na seção de APIs - if grep -q "^\[apis\]" "$fazai_conf"; then - sed -i "/^\[apis\]/a $config_key = $value" "$fazai_conf" - else - # Se não houver seção de APIs, adiciona ao final do arquivo - echo -e "\n[apis]\n$config_key = $value" >> "$fazai_conf" - fi - fi - - log "SUCCESS" "Chave $key importada com sucesso." - changes_made=true - fi - done - - if [ "$changes_made" = true ]; then - log "SUCCESS" "Configurações importadas para $fazai_conf" - else - log "WARNING" "Nenhuma configuração relevante encontrada em $env_file" - fi - else - log "INFO" "Nenhum arquivo .env encontrado nas localizações padrão." - fi - } - - # Função para configurar o serviço systemd -configure_systemd() { - log "INFO" "Configurando serviço systemd..." - - local service_file="/etc/systemd/system/fazai.service" - - # Gera um arquivo de serviço melhorado - cat > "$service_file" << EOF - [Unit] - Description=FazAI Service - After=network.target fazai-gemma-worker.service fazai-docler.service fazai-qdrant.service - Wants=fazai-gemma-worker.service fazai-docler.service - Wants=fazai-qdrant.service - StartLimitIntervalSec=0 - - [Service] - Type=simple - Restart=always - RestartSec=1 - User=root - ExecStart=/usr/bin/node /opt/fazai/lib/main.js - WorkingDirectory=/opt/fazai - Environment=NODE_ENV=production - StandardOutput=append:/var/log/fazai/stdout.log - StandardError=append:/var/log/fazai/stderr.log - - # Limites de recursos - LimitNOFILE=65535 - LimitMEMLOCK=512M - - [Install] - WantedBy=multi-user.target -EOF - - chmod 644 "$service_file" - log "SUCCESS" "Arquivo de serviço systemd criado em $service_file" - - systemctl daemon-reload - systemctl enable fazai - log "SUCCESS" "Serviço systemd habilitado." - - # Instala serviço do Gemma Worker se binário existir - if [ -x "/opt/fazai/bin/fazai-gemma-worker" ]; then - log "INFO" "Configurando serviço fazai-gemma-worker..." - cat > "/etc/systemd/system/fazai-gemma-worker.service" << EOF -[Unit] -Description=FazAI Gemma Worker v2.0 -After=network.target fazai-qdrant.service -Wants=fazai-qdrant.service -PartOf=fazai.service - -[Service] -Type=simple -User=root -WorkingDirectory=/opt/fazai -EnvironmentFile=-/etc/fazai/env -RuntimeDirectory=fazai -RuntimeDirectoryMode=0777 -UMask=0000 -ExecStartPre=/usr/bin/install -d -m 0777 -o root -g root /run/fazai -ExecStartPre=/bin/rm -f /run/fazai/gemma.sock -ExecStart=/opt/fazai/bin/fazai_gemma_worker.py -ExecStopPost=/bin/rm -f /run/fazai/gemma.sock -Restart=always -RestartSec=5 -StandardOutput=journal -StandardError=journal - -[Install] -WantedBy=multi-user.target -EOF - chmod 644 "/etc/systemd/system/fazai-gemma-worker.service" - systemctl daemon-reload - systemctl enable fazai-gemma-worker || true - log "SUCCESS" "Serviço fazai-gemma-worker preparado." - else - log "WARNING" "Binário fazai-gemma-worker não encontrado; serviço do worker não será criado." - fi - - # Serviço DOCLER Web (portas 3220/3221 para evitar conflito com daemon 3120) - if [ -f "/opt/fazai/web/docler-server.js" ]; then - log "INFO" "Configurando serviço fazai-docler..." - cat > "/etc/systemd/system/fazai-docler.service" << 'EOF' -[Unit] -Description=FazAI DOCLER Web Server -After=network.target -PartOf=fazai.service - -[Service] -Type=simple -User=fazai-web -Group=fazai-web -Environment=DOCLER_PORT=3220 -Environment=DOCLER_ADMIN_PORT=3221 -Environment=DOCLER_HOST=0.0.0.0 -WorkingDirectory=/opt/fazai/web -ExecStart=/usr/bin/node /opt/fazai/web/docler-server.js -Restart=always -RestartSec=5 - -[Install] -WantedBy=multi-user.target -EOF - chmod 644 "/etc/systemd/system/fazai-docler.service" - systemctl daemon-reload - systemctl enable fazai-docler || true - # Tenta iniciar se dependências foram instaladas - systemctl start fazai-docler || true - log "SUCCESS" "Serviço fazai-docler preparado (portas 3220/3221)." - else - log "WARNING" "docler-server.js não encontrado; serviço DOCLER não será criado." - fi - - # Serviço Qdrant Vector Database - log "INFO" "Configurando serviço fazai-qdrant..." - if command -v docker >/dev/null 2>&1 && systemctl is-active docker >/dev/null 2>&1; then - # Usar Docker se disponível - cat > "/etc/systemd/system/fazai-qdrant.service" << 'EOF' -[Unit] -Description=FazAI Qdrant Vector Database (Docker) -After=network.target docker.service -Requires=docker.service -PartOf=fazai.service - -[Service] -Type=oneshot -RemainAfterExit=yes -ExecStartPre=/usr/bin/docker pull qdrant/qdrant:latest -ExecStart=/usr/bin/docker run -d \ - --name fazai-qdrant \ - --restart unless-stopped \ - -p 6333:6333 \ - -p 6334:6334 \ - -v /var/lib/qdrant:/qdrant/storage \ - -v /opt/fazai/web/static:/opt/qdrant/web/static \ - -e QDRANT__SERVICE__HTTP_PORT=6333 \ - -e QDRANT__SERVICE__GRPC_PORT=6334 \ - -e QDRANT__SERVICE__HOST=0.0.0.0 \ - -e QDRANT__WEB_UI__ENABLED=true \ - -e QDRANT__SERVICE__ENABLE_CORS=true \ - qdrant/qdrant:latest -ExecStop=/usr/bin/docker stop fazai-qdrant -ExecStopPost=/usr/bin/docker rm fazai-qdrant - -[Install] -WantedBy=multi-user.target -EOF - elif [ -f "/opt/fazai/bin/qdrant" ]; then - # Usar binário nativo se disponível - cat > "/etc/systemd/system/fazai-qdrant.service" << 'EOF' -[Unit] -Description=FazAI Qdrant Vector Database -After=network.target -PartOf=fazai.service - -[Service] -Type=simple -User=fazai -Group=fazai -WorkingDirectory=/var/lib/qdrant -ExecStart=/opt/fazai/bin/qdrant --config-path /etc/fazai/qdrant.yaml -Restart=always -RestartSec=5 -Environment=RUST_LOG=info - -[Install] -WantedBy=multi-user.target -EOF - fi - - chmod 644 "/etc/systemd/system/fazai-qdrant.service" 2>/dev/null || true - systemctl daemon-reload - systemctl enable fazai-qdrant || true - systemctl start fazai-qdrant || true - log "SUCCESS" "Serviço fazai-qdrant preparado (porta 6333)." - - - - # Instalar GPT-Web2Shell se local-extras existe - if [ -d "local-extras/gpt-web2shell" ]; then - log "INFO" "Instalando GPT-Web2Shell..." - mkdir -p /home/${SUDO_USER}/fazai/local-extras/gpt-web2shell - cp -r local-extras/gpt-web2shell/* /home/${SUDO_USER}/fazai/local-extras/gpt-web2shell/ - chown -R ${SUDO_USER}:${SUDO_USER} /home/${SUDO_USER}/fazai/local-extras/ 2>/dev/null || true - chmod +x /home/${SUDO_USER}/fazai/local-extras/gpt-web2shell/bin/gpt-web2shell 2>/dev/null || true - chmod +x /opt/fazai/tools/gpt-web2shell.js 2>/dev/null || true - log "SUCCESS" "GPT-Web2Shell instalado para transcendência CLI." - fi - - # Detecta runtime de contêiner (Docker/Podman) - local CONTAINER="" - if command -v docker >/dev/null 2>&1; then CONTAINER="docker"; fi - if [ -z "$CONTAINER" ] && command -v podman >/dev/null 2>&1; then CONTAINER="podman"; fi - - # Serviço Qdrant (via Docker/Podman) se disponível - if [ -n "$CONTAINER" ]; then - log "INFO" "Configurando serviço Qdrant ($CONTAINER)..." - mkdir -p /var/lib/fazai/qdrant - cat > "/etc/systemd/system/fazai-qdrant.service" << 'EOF' -[Unit] -Description=FazAI Qdrant Vector DB (Docker) -After=network-online.target -PartOf=fazai.service - -[Service] -Type=oneshot -RemainAfterExit=yes -ExecStartPre=-/usr/bin/CONTAINER_BIN rm -f fazai-qdrant -ExecStart=/usr/bin/CONTAINER_BIN run -d --name fazai-qdrant -p 6333:6333 -v /var/lib/fazai/qdrant:/qdrant/storage qdrant/qdrant:v1.7.3 -ExecStop=/usr/bin/CONTAINER_BIN stop fazai-qdrant -TimeoutStartSec=120 -TimeoutStopSec=30 - -[Install] -WantedBy=multi-user.target -EOF - # Substitui placeholder pelo runtime - sed -i "s|CONTAINER_BIN|$CONTAINER|g" "/etc/systemd/system/fazai-qdrant.service" - chmod 644 "/etc/systemd/system/fazai-qdrant.service" - systemctl daemon-reload - systemctl enable fazai-qdrant || true - systemctl start fazai-qdrant || true - log "SUCCESS" "Serviço Qdrant preparado (porta 6333)." - - - else - log "WARNING" "Docker/Podman não encontrado; Qdrant não será instalado automaticamente. Instale um runtime de contêiner ou configure Qdrant manualmente." - fi - - # Observabilidade foi movida para repo separado (~/fazaiserverlogs) - if [ -n "$CONTAINER" ]; then - log "INFO" "Monitoring Prometheus/Grafana não é mais instalado neste host. Use o repositório fazaiserverlogs." - fi -} - -# Compila e instala o Gemma Worker (C++) se fontes estiverem presentes -build_gemma_worker() { - if [ -d "worker" ] && [ -f "worker/CMakeLists.txt" ]; then - log "INFO" "Compilando Gemma Worker (C++)..." - mkdir -p worker/build - pushd worker/build >/dev/null - if cmake .. && cmake --build . -j$(nproc) && cmake --install .; then - log "SUCCESS" "Gemma Worker compilado e instalado em /opt/fazai/bin" - else - log "WARNING" "Falha ao compilar o Gemma Worker. O agente local poderá não funcionar." - fi - popd >/dev/null - # Garante diretório de socket - mkdir -p /run/fazai - chmod 755 /run/fazai - else - log "INFO" "Fontes do Gemma Worker não encontradas; pulando compilação." - fi -} - -# Instala Gemma one-shot e pesos padrão (máquinas pequenas) -bootstrap_gemma() { - if [ -x "/opt/fazai/bin/gemma_oneshot" ] && [ -f "/opt/fazai/models/gemma/2.0-2b-it-sfp.sbs" ]; then - log "INFO" "Gemma (oneshot + pesos) já presente." - return 0 - fi - if [ -x "/opt/fazai/tools/gemma_bootstrap.sh" ]; then - log "INFO" "Executando gemma_bootstrap.sh (download/instalação do modelo)." - bash /opt/fazai/tools/gemma_bootstrap.sh || log "WARNING" "Falha no gemma_bootstrap.sh" - else - log "WARNING" "gemma_bootstrap.sh não encontrado." - fi -} - - # Função para instalar dependências do Node.js com retry - install_node_dependencies() { - log "INFO" "Instalando dependências do Node.js..." - - # Cria package.json se não existir - if [ ! -f "package.json" ]; then - log "INFO" "Criando package.json..." - cat > "package.json" << 'EOF' - { - "name": "fazai", - "version": "2.0.0", - "description": "FazAI - Orquestrador Inteligente de Automação", - "main": "main.js", - "dependencies": { - "axios": ">=0.27.2", - "express": ">=4.18.1", - "winston": ">=3.8.1", - - "chalk": ">=4.1.2", - "figlet": ">=1.5.2", - "inquirer": ">=8.2.4" - } - } -EOF - fi - - # Instala no diretório atual primeiro - log "INFO" "Instalando dependências no diretório atual..." - if ! npm install --no-audit --no-progress; then - log "WARNING" "Falha na instalação inicial de dependências. Tentando método alternativo..." - - # Tenta instalar pacotes críticos individualmente - for module in "${DEPENDENCY_MODULES[@]}"; do - log "INFO" "Instalando módulo: $module" - npm install "$module" --no-audit --no-progress || log "WARNING" "Falha ao instalar $module" - done - fi - - # Agora instala em /opt/fazai - log "INFO" "Instalando dependências em /opt/fazai..." - cp package.json /opt/fazai/ - cd /opt/fazai - - if ! npm install --no-audit --no-progress; then - log "WARNING" "Falha ao instalar dependências em /opt/fazai. Tentando método alternativo..." - - # Tenta instalar pacotes críticos individualmente - for module in "${DEPENDENCY_MODULES[@]}"; do - log "INFO" "Instalando módulo em /opt/fazai: $module" - npm install "$module" --no-audit --no-progress || log "WARNING" "Falha ao instalar $module" - done - fi - - cd - > /dev/null - - # Verifica se os módulos essenciais foram instalados - if npm list express winston >> "$LOG_FILE" 2>&1; then - log "SUCCESS" "Módulos express e winston instalados corretamente." - else - log "WARNING" "Módulos express ou winston ausentes. Possível problema de conexão. Execute 'npm install' manualmente." - fi - - log "SUCCESS" "Dependências do Node.js instaladas." - } - - # Função para compilar módulos nativos - compile_native_modules() { - log "INFO" "Verificando módulos nativos..." - - # Cria um módulo nativo básico se não existir - if [ ! -d "/opt/fazai/mods" ]; then - mkdir -p "/opt/fazai/mods" - fi - - cd /opt/fazai/mods - - if [ ! -f "system_mod.c" ]; then - log "INFO" "Criando módulo nativo básico..." - cat > "system_mod.c" << 'EOF' - #include - #include - - // Função básica para teste do módulo nativo - int fazai_test() { - return 42; - } -EOF - fi - - if [ -f "system_mod.c" ]; then - log "DEBUG" "Compilando system_mod.c..." - if gcc -shared -fPIC -o system_mod.so system_mod.c; then - log "SUCCESS" "Módulos nativos compilados com sucesso." - else - log "WARNING" "Falha ao compilar módulos nativos. Continuando sem eles..." - fi - else - log "INFO" "Nenhum módulo nativo para compilar." - fi - - cd - > /dev/null - } - - # Função opcional para instalar o llama.cpp - install_llamacpp() { - if [ "$WITH_LLAMA" != true ]; then - log "INFO" "Instalação do llama.cpp ignorada (--with-llama)" - return 0 - fi - - log "INFO" "Instalando llama.cpp..." - local script_dir="$(cd "$(dirname "$0")" && pwd)" - if bash "$script_dir/bin/tools/install-llamacpp.sh"; then - log "SUCCESS" "llama.cpp instalado" - return 0 - else - log "ERROR" "Falha ao instalar llama.cpp" - return 1 - fi - } - - # Função para instalar interface TUI - - # Função para configurar permissões de segurança - configure_security() { - log "INFO" "Configurando permissões de segurança..." - - # Cria grupo fazai se não existir - if ! getent group fazai > /dev/null 2>&1; then - groupadd -r fazai - log "SUCCESS" "Grupo 'fazai' criado" - fi - - # Cria usuário fazai se não existir - if ! getent passwd fazai > /dev/null 2>&1; then - useradd -r -g fazai -s /bin/false -d /opt/fazai fazai - log "SUCCESS" "Usuário 'fazai' criado" - fi - - # Define permissões dos diretórios - chown -R fazai:fazai /opt/fazai - chown -R fazai:fazai /var/log/fazai - chown -R fazai:fazai /var/lib/fazai - - # Permissões específicas - chmod 750 /opt/fazai - chmod 755 /opt/fazai/bin/fazai - # Conf: dono fazai, grupo root, 640 - chown fazai:root /etc/fazai/fazai.conf 2>/dev/null || true - chmod 640 /etc/fazai/fazai.conf - chmod 755 /opt/fazai/tools/fazai-config.js - - # Configura sudoers para permitir comandos específicos do fazai - if [ ! -f /etc/sudoers.d/fazai ]; then - cat > /etc/sudoers.d/fazai << 'EOF' - # FazAI sudoers configuration - %fazai ALL=(ALL) NOPASSWD: /bin/systemctl start fazai - %fazai ALL=(ALL) NOPASSWD: /bin/systemctl stop fazai - %fazai ALL=(ALL) NOPASSWD: /bin/systemctl restart fazai - %fazai ALL=(ALL) NOPASSWD: /bin/systemctl status fazai - %fazai ALL=(ALL) NOPASSWD: /usr/bin/apt-get update - %fazai ALL=(ALL) NOPASSWD: /usr/bin/apt-get install * - %fazai ALL=(ALL) NOPASSWD: /usr/sbin/service * * -EOF - chmod 440 /etc/sudoers.d/fazai - log "SUCCESS" "Configuração sudoers criada" - fi - - log "SUCCESS" "Permissões de segurança configuradas" - } - - # Função para criar scripts auxiliares - create_helper_scripts() { - log "INFO" "Criando scripts auxiliares..." - - # Script de uninstall - cat > /opt/fazai/bin/uninstall.sh << 'EOF' - #!/bin/bash - # FazAI Uninstall Script - - echo "Desinstalando FazAI..." - - # Para o serviço - systemctl stop fazai 2>/dev/null - systemctl disable fazai 2>/dev/null - - # Remove arquivos de serviço - rm -f /etc/systemd/system/fazai.service - systemctl daemon-reload - - # Remove links simbólicos - rm -f /usr/local/bin/fazai - rm -f /usr/local/bin/fazai-config - - # Remove diretórios (com confirmação) - read -p "Remover todos os dados do FazAI? (logs, configurações, etc.) [s/N]: " -n 1 -r - echo - if [[ $REPLY =~ ^[Ss]$ ]]; then - rm -rf /opt/fazai - rm -rf /etc/fazai - rm -rf /var/log/fazai - rm -rf /var/lib/fazai - echo "Todos os dados removidos." - else - echo "Dados preservados em /etc/fazai, /var/log/fazai e /var/lib/fazai" - fi - - # Remove usuário e grupo - userdel fazai 2>/dev/null - groupdel fazai 2>/dev/null - - # Remove sudoers - rm -f /etc/sudoers.d/fazai - - echo "FazAI desinstalado com sucesso!" -EOF - - chmod +x /opt/fazai/bin/uninstall.sh - ln -sf /opt/fazai/bin/uninstall.sh /usr/local/bin/fazai-uninstall - - # Script de backup - cat > /opt/fazai/bin/backup.sh << 'EOF' - #!/bin/bash - # FazAI Backup Script - - BACKUP_DIR="/tmp/fazai-backup-$(date +%Y%m%d-%H%M%S)" - mkdir -p "$BACKUP_DIR" - - echo "Criando backup em $BACKUP_DIR..." - - # Backup de configurações - cp -r /etc/fazai "$BACKUP_DIR/" - cp -r /var/lib/fazai "$BACKUP_DIR/" - - # Backup de logs (últimos 7 dias) - find /var/log/fazai -name "*.log" -mtime -7 -exec cp {} "$BACKUP_DIR/" \; - - # Compacta o backup - cd /tmp - tar -czf "fazai-backup-$(date +%Y%m%d-%H%M%S).tar.gz" "$(basename $BACKUP_DIR)" - rm -rf "$BACKUP_DIR" - - echo "Backup criado: /tmp/fazai-backup-$(date +%Y%m%d-%H%M%S).tar.gz" -EOF - - chmod +x /opt/fazai/bin/backup.sh - ln -sf /opt/fazai/bin/backup.sh /usr/local/bin/fazai-backup - - log "SUCCESS" "Scripts auxiliares criados" - } - - # Compila o worker Gemma usando o script interno - build_gemma_worker() { - log "INFO" "Compilando FazAI Gemma Worker" - if [ -d "worker" ]; then - pushd worker >/dev/null - ./build.sh || { log "ERROR" "Falha ao compilar worker"; popd >/dev/null; return 1; } - popd >/dev/null - log "SUCCESS" "Worker compilado e instalado em /opt/fazai/bin" - return 0 - else - log "ERROR" "Diretório worker não encontrado" - return 1 - fi - } - - # Função para configurar logrotate - configure_logrotate() { - log "INFO" "Configurando rotação de logs..." - - cat > /etc/logrotate.d/fazai << 'EOF' - /var/log/fazai/*.log { - daily - missingok - rotate 30 - compress - delaycompress - notifempty - create 644 fazai fazai - postrotate - systemctl reload fazai > /dev/null 2>&1 || true - endscript - } -EOF - - log "SUCCESS" "Configuração de logrotate criada" - } - - # Função para validar a instalação - validate_installation() { - log "INFO" "Validando instalação..." - - local validation_errors=0 - - # Verifica arquivos essenciais - local essential_files=( - "/opt/fazai/lib/main.js" - "/opt/fazai/bin/fazai" - "/etc/fazai/fazai.conf" - "/etc/fazai/complex_tasks.conf.default" - "/etc/systemd/system/fazai.service" - "/usr/local/bin/fazai" - "/opt/fazai/tools/fazai_web_frontend.html" - "/opt/fazai/tools/fazai_web.sh" - "/opt/fazai/tools/fazai_html_v1.sh" - "/opt/fazai/tools/auto_tool.js" - "/opt/fazai/tools/net_qos_monitor.js" - "/opt/fazai/tools/agent_supervisor.js" - "/opt/fazai/tools/qdrant_setup.js" - "/opt/fazai/tools/snmp_monitor.js" - "/opt/fazai/tools/modsecurity_setup.js" - "/opt/fazai/tools/suricata_setup.js" - "/opt/fazai/tools/crowdsec_setup.js" - "/opt/fazai/tools/monit_setup.js" - ) - - for file in "${essential_files[@]}"; do - if [ ! -f "$file" ]; then - log "ERROR" "Arquivo essencial não encontrado: $file" - validation_errors=$((validation_errors + 1)) - else - log "DEBUG" "Arquivo validado: $file" - fi - done - - # Verifica diretórios - local essential_dirs=( - "/opt/fazai" - "/etc/fazai" - "/var/log/fazai" - "/var/lib/fazai" - ) - - for dir in "${essential_dirs[@]}"; do - if [ ! -d "$dir" ]; then - log "ERROR" "Diretório essencial não encontrado: $dir" - validation_errors=$((validation_errors + 1)) - else - log "DEBUG" "Diretório validado: $dir" - fi - done - - # Verifica comandos - if ! command -v fazai &> /dev/null; then - log "ERROR" "Comando 'fazai' não está disponível" - validation_errors=$((validation_errors + 1)) - fi - - # Verifica serviço systemd - if ! systemctl is-enabled fazai &> /dev/null; then - log "WARNING" "Serviço fazai não está habilitado" - fi - - # Verifica dependências Node.js críticas - cd /opt/fazai - local critical_modules=("express" "winston") - for module in "${critical_modules[@]}"; do - if ! npm list "$module" &> /dev/null; then - log "WARNING" "Módulo Node.js crítico não encontrado: $module" - fi - done - - if [ $validation_errors -eq 0 ]; then - log "SUCCESS" "Validação da instalação concluída com sucesso!" - return 0 - else - log "ERROR" "Validação falhou com $validation_errors erro(s)" - return 1 - fi - } - - # Função para executar testes pós-instalação - run_post_install_tests() { - log "INFO" "Executando testes pós-instalação..." - - # Teste 1: Verifica se o CLI responde - log "DEBUG" "Testando CLI..." - if fazai --version &> /dev/null; then - log "SUCCESS" "Teste CLI: OK" - else - log "WARNING" "Teste CLI: Falhou" - fi - - # Teste 2: Verifica se o serviço pode ser iniciado - log "DEBUG" "Testando serviço systemd..." - if systemctl start fazai && sleep 2 && systemctl is-active fazai &> /dev/null; then - log "SUCCESS" "Teste serviço: OK" - systemctl stop fazai - else - log "WARNING" "Teste serviço: Falhou" - fi - - # Teste 3: Verifica permissões - log "DEBUG" "Testando permissões..." - if [ -r /etc/fazai/fazai.conf ] && [ -x /opt/fazai/bin/fazai ]; then - log "SUCCESS" "Teste permissões: OK" - else - log "WARNING" "Teste permissões: Falhou" - fi - - log "SUCCESS" "Testes pós-instalação concluídos" - } - - # Função para mostrar informações finais - show_installation_summary() { - log "INFO" "====== Resumo da Instalação ======" - - echo -e "\n${GREEN}✓ FazAI v$VERSION instalado com sucesso!${NC}\n" - - echo -e "${BLUE}Localização dos arquivos:${NC}" - echo " • Binários: /opt/fazai" - echo " • Configuração: /etc/fazai/fazai.conf" - echo " • Configuração de tarefas complexas: /etc/fazai/complex_tasks.conf.default" - echo " • Logs: /var/log/fazai" - echo " • Dados: /var/lib/fazai" - echo "" - - echo -e "${BLUE}Comandos disponíveis:${NC}" - echo " • fazai --help - Ajuda do sistema" - echo " • fazai --version - Versão instalada" - echo " • fazai --status - Status do daemon" - echo " • fazai web - Interface web com gerenciamento de logs" - - echo " • fazai logs [n] - Ver últimas n entradas de log" - echo " • fazai limpar-logs - Limpar logs (com backup)" - - echo " • fazai-backup - Criar backup" - echo " • fazai-uninstall - Desinstalar" - echo "" - - echo -e "${BLUE}Gerenciamento do serviço:${NC}" - echo " • systemctl start fazai - Iniciar" - echo " • systemctl stop fazai - Parar" - echo " • systemctl restart fazai - Reiniciar" - echo " • systemctl status fazai - Ver status" - echo "" - - echo -e "${YELLOW}Próximos passos:${NC}" - echo " 1. Configure suas API keys editando /etc/fazai/fazai.conf" - echo " 2. Inicie o serviço: systemctl start fazai" - echo " 3. Teste o sistema: fazai --status" - echo "" - - echo -e "${PURPLE}Para suporte e documentação:${NC}" - echo " • GitHub: https://github.com/RLuf/FazAI" - echo " • Logs: /var/log/fazai_install.log" - echo "" - - # Salva estado final - save_install_state "installation_complete" "success" - - log "SUCCESS" "====== Instalação Finalizada ======" - } - - # Função principal de instalação - main_install() { - log "INFO" "Iniciando instalação do FazAI v$VERSION" - - # Carrega estado anterior se existir - load_install_state - - # Executa etapas de instalação - local install_steps=( - "setup_logging:Configurando sistema de logs" - "check_root:Verificando permissões" - "check_system:Verificando sistema operacional" - "convert_files_to_unix:Convertendo arquivos para formato Linux" - "install_nodejs:Instalando Node.js" - "install_npm:Verificando npm" - "install_python:Instalando Python 3" - "install_gcc:Instalando ferramentas de compilação" - "ensure_container_runtime:Instalando runtime de contêiner (Docker)" - "create_directories:Criando estrutura de diretórios" - "build_gemma_worker:Compilando Gemma Worker" - "bootstrap_gemma:Instalando Gemma one-shot e pesos padrão" - "copy_files:Copiando arquivos" - "import_env_config:Importando configurações" - "configure_systemd:Configurando serviço systemd" - "install_node_dependencies:Instalando dependências Node.js" - "compile_native_modules:Compilando módulos nativos" - ) - - if [ "$WITH_LLAMA" = true ]; then - install_steps+=("install_llamacpp:Instalando llama.cpp") - fi - - install_steps+=( - - "configure_security:Configurando segurança" - "create_helper_scripts:Criando scripts auxiliares" - "configure_logrotate:Configurando rotação de logs" - "install_bash_completion:Instalando autocompletar" - ) - - local total_steps=${#install_steps[@]} - local current_step=0 - - for step_info in "${install_steps[@]}"; do - local step_function=$(echo "$step_info" | cut -d: -f1) - local step_description=$(echo "$step_info" | cut -d: -f2) - - current_step=$((current_step + 1)) - - # Verifica se já foi executado - if [ "${INSTALL_STATE[$step_function]}" = "completed" ]; then - log "INFO" "[$current_step/$total_steps] $step_description (já concluído)" - continue - fi - - log "INFO" "[$current_step/$total_steps] $step_description" - - # Executa a função - if $step_function; then - save_install_state "$step_function" "completed" - log "SUCCESS" "$step_description - Concluído" - else - log "ERROR" "$step_description - Falhou" - save_install_state "$step_function" "failed" - - if [ "$step_function" = "copy_files" ]; then - log "ERROR" "Falha ao copiar arquivos. Instalação interrompida. Verifique $LOG_FILE para detalhes." - ai_help "Falha ao copiar arquivos durante a instalação do FazAI" - exit 1 - fi - - # Consulta ajuda da IA e pergunta se deve continuar - ai_help "Erro na etapa '$step_description'" - read -p "Erro na etapa '$step_description'. Continuar mesmo assim? (s/N): " -n 1 -r - echo - if [[ ! $REPLY =~ ^[Ss]$ ]]; then - log "ERROR" "Instalação interrompida pelo usuário" - exit 1 - fi - fi - done - - # Validação e testes finais - log "INFO" "Executando validação final..." - if validate_installation; then - run_post_install_tests - show_installation_summary - - # Inicia o serviço se tudo estiver OK - if systemctl start fazai; then - log "SUCCESS" "Serviço FazAI iniciado com sucesso!" - # Health-check com autorreparo - health_check_repair - # Resumo da engine/módulo nativo, se o verificador existir - if [ -x "scripts/verify-engine.sh" ]; then - log "INFO" "Resumo de verificação pós-instalação:" - bash scripts/verify-engine.sh || true - fi - else - log "WARNING" "Falha ao iniciar o serviço. Inicie manualmente: systemctl start fazai" - fi - else - log "ERROR" "Validação da instalação falhou. Verifique os logs em $LOG_FILE" - exit 1 - fi - } - - # Função para limpeza em caso de interrupção - cleanup_on_exit() { - local exit_code=$? - if [ $exit_code -ne 0 ]; then - log "WARNING" "Instalação interrompida (código: $exit_code)" - log "INFO" "Estado salvo em $INSTALL_STATE_FILE" - log "INFO" "Execute novamente o script para continuar de onde parou" - fi - } - - # Captura sinais para limpeza - trap cleanup_on_exit EXIT INT TERM - - - # Verifica argumentos de linha de comando - while [[ $# -gt 0 ]]; do - case "$1" in - --debug) - DEBUG_MODE=true - log "INFO" "Modo debug ativado" - ;; - --clean) - rm -f "$INSTALL_STATE_FILE" - log "INFO" "Estado de instalação limpo" - ;; - --with-llama) - WITH_LLAMA=true - ;; - --help) - echo "FazAI Installer v$VERSION" - echo "Uso: $0 [opções]" - echo "" - echo "Opções:" - echo " --debug Ativa modo debug com logs detalhados" - echo " --clean Remove estado de instalação anterior" - echo " --with-llama Instala o mecanismo local llama.cpp" - echo " --help Mostra esta ajuda" - exit 0 - ;; - esac - shift - done - - # Inicia instalação principal - main_install - - log "SUCCESS" "Instalação do FazAI v2.0 concluída com sucesso!" - echo -e "\n${GREEN}🎉 FazAI v2.0 - Sistema de Fluxo Inteligente está pronto!${NC}" - echo -e "${CYAN}Novos recursos disponíveis:${NC}" - echo -e " 🤖 ${YELLOW}fazai agent${NC} - Agente inteligente cognitivo" - echo -e " 📊 ${YELLOW}fazai relay${NC} - Sistema de relay SMTP inteligente" - echo -e " 🔧 ${YELLOW}Edite /etc/fazai/fazai.conf${NC} - Configurar API keys" - echo -e " 📚 ${YELLOW}fazai manual${NC} - Manual completo" - echo -e "\n${GREEN}Exemplos de uso:${NC}" - echo -e " fazai agent \"configurar servidor de email relay com antispam\"" - echo -e " fazai relay analyze" - echo -e " fazai relay configure" - -exit 0 From 533d429d787bde4fce4bf7ff14be401a57876799 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 11 Oct 2025 22:56:11 +0000 Subject: [PATCH 4/4] Document install.sh fixes in CHANGELOG and create comprehensive summary Co-authored-by: RLuf <74881309+RLuf@users.noreply.github.com> --- CHANGELOG.md | 9 ++ INSTALL_SH_FIX_SUMMARY.md | 267 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 276 insertions(+) create mode 100644 INSTALL_SH_FIX_SUMMARY.md diff --git a/CHANGELOG.md b/CHANGELOG.md index f5352af..3e06aab 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,15 @@ ## Unreleased +### Fixed +- **install.sh**: Corrigidos erros críticos de sintaxe e estrutura + - Removido código órfão (linhas 298-323): corpo duplicado da função log() sem abertura + - Removido instalador simples legado (linhas 69-297) que conflitava com framework moderno + - Corrigido comentário estilo C++ (linha 93: `//` → estrutura adequada) + - Verificadas 42 funções incluindo main_install(), log(), copy_files(), build_gemma_worker() + - Reduzido de 2553 para 2296 linhas (-257 linhas quebradas) + - Sintaxe validada com `bash -n` e `shellcheck` (0 erros) + ### Added - Installer: Post-start helper ensures `/run/fazai/gemma.sock` is chmod 0666 reliably. - Qdrant migration: added one‑time script `scripts/qdrant_migrate_persona.py` (claudio_soul → fazai_memory). Removed from installer. diff --git a/INSTALL_SH_FIX_SUMMARY.md b/INSTALL_SH_FIX_SUMMARY.md new file mode 100644 index 0000000..a82f14b --- /dev/null +++ b/INSTALL_SH_FIX_SUMMARY.md @@ -0,0 +1,267 @@ +# FazAI Install.sh Integration and Fixes - Summary Report + +## Overview +This document summarizes the integration work performed on the FazAI repository's `install.sh` script, addressing critical syntax errors and structural issues that prevented proper installation. + +## Problem Analysis + +### Initial State +The `install.sh` script (2553 lines) had multiple critical issues: + +1. **Syntax Errors**: `bash -n install.sh` reported errors at line 323 +2. **Orphaned Code**: Lines 298-323 contained a function body without opening declaration +3. **Structural Conflict**: Two different installation approaches merged incorrectly +4. **Missing Functions**: `main_install()` was called but not accessible +5. **C++ Style Comment**: Line 93 used `//` instead of `#` + +### Root Cause +The file contained two conflicting installation scripts merged together: +- **Old Simple Installer** (lines 1-297): Direct execution style, legacy approach +- **Modern Framework** (lines 324+): Function-based modular architecture + +This created an inconsistent structure where: +- The log() function body appeared twice (once properly, once orphaned) +- Installation logic was duplicated +- Function calls referenced undefined functions + +## Solution Implemented + +### 1. File Restructuring +Created a clean, well-organized structure: + +**Header Section** (lines 1-66): +```bash +#!/bin/bash +set -e + +# Variables +VERSION="2.0.0" +LOG_FILE="/var/log/fazai/install.log" +INSTALL_STATE_FILE="/var/log/fazai/install_state.txt" +DEBUG_MODE="${DEBUG_MODE:-false}" +WITH_LLAMA="${WITH_LLAMA:-false}" + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +PURPLE='\033[0;35m' +CYAN='\033[0;36m' +NC='\033[0m' # No Color + +# State tracking +declare -A INSTALL_STATE + +# Logging function with colors and file output +log() { + local level="$1" + local message="$2" + local timestamp=$(date '+%Y-%m-%d %H:%M:%S') + + mkdir -p "$(dirname "$LOG_FILE")" + echo "[$timestamp] [$level] $message" >> "$LOG_FILE" + + case $level in + "INFO") echo -e "${BLUE}[INFO]${NC} $message" ;; + "SUCCESS") echo -e "${GREEN}[SUCESSO]${NC} $message" ;; + "ERROR") echo -e "${RED}[ERRO]${NC} $message" ;; + "WARNING") echo -e "${YELLOW}[AVISO]${NC} $message" ;; + "DEBUG") + if [ "$DEBUG_MODE" = true ]; then + echo -e "${PURPLE}[DEBUG]${NC} $message" + fi + ;; + esac +} + +# Root permission check +if [[ $EUID -ne 0 ]]; then + log "ERROR" "Execute como root: sudo ./install.sh" + exit 1 +fi +``` + +**Function Framework** (lines 67-2296): +- 42 modular functions +- Proper error handling +- State management for resumable installation +- Modern installation orchestration via `main_install()` + +### 2. Code Removals +Removed 257 lines of problematic code: +- Lines 69-297: Old simple installer (direct execution) +- Lines 298-323: Orphaned log() function body +- Fixed line 93: C++ comment style + +### 3. Validation Results + +**Syntax Check**: +```bash +$ bash -n install.sh +# No output - validation passed ✅ +``` + +**Shellcheck Analysis**: +``` +Errors: 0 ✅ +Warnings: 11 (minor style issues, not critical) +- SC2155: Declare and assign separately (performance optimization) +- SC2046: Quote command substitution (style preference) +- SC2188: Redirection without command (minor issue) +``` + +**Function Inventory** (42 total): +- ✅ log() - Logging with colors +- ✅ ai_help() - AI assistance integration +- ✅ save_install_state() - State persistence +- ✅ load_install_state() - State recovery +- ✅ check_dependency_version() - Dependency validation +- ✅ convert_files_to_unix() - Line ending conversion +- ✅ install_bash_completion() - Shell completion +- ✅ setup_logging() - Log initialization +- ✅ check_root() - Permission validation +- ✅ check_system() - OS detection +- ✅ ensure_container_runtime() - Docker setup +- ✅ ensure_network_utils() - Network tools +- ✅ install_nodejs() - Node.js installation +- ✅ install_nodejs_from_source() - Alternative Node.js install +- ✅ install_npm() - NPM verification +- ✅ install_python() - Python 3 setup +- ✅ install_gcc() - Compiler installation +- ✅ create_directories() - Directory structure +- ✅ health_check_repair() - System validation +- ✅ copy_files() - File deployment +- ✅ configure_systemd() - Service configuration +- ✅ build_gemma_worker() - Worker compilation +- ✅ bootstrap_gemma() - Model setup +- ✅ main_install() - Main orchestrator +- ✅ cleanup_on_exit() - Cleanup handler +- ... and 17 more support functions + +## Files Modified + +### install.sh +- **Before**: 2553 lines, syntax errors +- **After**: 2296 lines, clean syntax +- **Change**: -257 lines (10% reduction) + +### CHANGELOG.md +Added entry documenting the fixes: +```markdown +### Fixed +- **install.sh**: Corrigidos erros críticos de sintaxe e estrutura + - Removido código órfão (linhas 298-323) + - Removido instalador simples legado (linhas 69-297) + - Corrigido comentário estilo C++ (linha 93) + - Verificadas 42 funções incluindo main_install() + - Reduzido de 2553 para 2296 linhas (-257 linhas) + - Sintaxe validada com bash -n e shellcheck (0 erros) +``` + +## Installation Flow + +The fixed `install.sh` now follows a clean, modular approach: + +1. **Initialization** + - Load configuration and state + - Setup logging + - Check root permissions + +2. **System Validation** + - OS detection (Debian/Ubuntu/Fedora/RHEL) + - Dependency version checking + - File format conversion (dos2unix) + +3. **Dependency Installation** + - Node.js 22+ + - Python 3.10+ + - GCC/build tools + - Docker/container runtime + +4. **FazAI Components** + - Directory structure creation + - Gemma worker compilation + - Model bootstrapping + - File deployment + +5. **Configuration** + - Environment import + - Systemd service setup + - Security hardening + - Log rotation + +6. **Finalization** + - Bash completion install + - Validation tests + - Service activation + - Success summary + +## Testing Recommendations + +While the syntax is now valid, comprehensive testing is recommended: + +1. **Container Testing** + ```bash + # Use provided Dockerfile + docker build -f Dockerfile.installer-test -t fazai-test . + docker run -it fazai-test + ``` + +2. **Unit Tests** + ```bash + npm test + # Runs: version.test.sh, cli.test.sh, install_uninstall.test.sh + ``` + +3. **Manual Testing** + ```bash + sudo ./install.sh --debug + # Monitor: /var/log/fazai/install.log + ``` + +## Repository Context + +### Open Issues +- **Issue #61** (Epic): Python-based self-healing worker migration (75% complete) +- **Issue #66**: Qdrant dual-collection memory system bugs (critical) +- **Issue #69**: Testing, deployment, production migration (40% complete) + +### Related PRs +- **PR #70**: Gemma3-cpp integration scaffold +- **PR #59**: Docker Container Manager TUI +- **PR #58**: Dependency updates (dependabot) + +## Recommendations + +1. **Immediate**: + - Test installation in clean Ubuntu 22.04 environment + - Verify all 42 functions execute properly + - Monitor for any runtime errors + +2. **Short-term**: + - Address shellcheck warnings for code quality + - Add integration tests for install.sh + - Document installation prerequisites + +3. **Long-term**: + - Consider breaking install.sh into modules + - Implement dry-run mode + - Add unattended installation support + +## Conclusion + +The install.sh script has been successfully fixed and restructured: +- ✅ 0 syntax errors +- ✅ Clean, modular architecture +- ✅ All 42 functions present and validated +- ✅ 257 lines of broken code removed +- ✅ Ready for testing and deployment + +The script now provides a solid foundation for the FazAI v2.0 installation process with proper error handling, state management, and resumable installation capability. + +--- + +**Date**: 2025-10-11 +**Author**: GitHub Copilot +**PR**: #72 - Integrate main branch with improvements and fixes