UNPKG

overmind-mcp

Version:

Orchestrateur universel agents IA multi-modeles via MCP. Inclut le protocole 'Custom-Nickname' pour identifier vos agents avec des surnoms originaux (The Chaos Prophet, Shadow Sniper, etc.), l'isolation mémoire (Private Memory Context) et le support pour

196 lines (171 loc) • 9.27 kB
#!/usr/bin/env node /** * ═══════════════════════════════════════════════════════════════════════════════ * OVERMIND-MCP — Post-Install Verification (Smoke Test) * ═══════════════════════════════════════════════════════════════════════════════ * * Vérifie que l'installation overmind-mcp est fonctionnelle: * 1. Binaire overmind accessible dans le PATH * 2. ~/.overmind/.env existe et contient les vars critiques * 3. PostgreSQL est accessible (Docker ou natif) * 4. Port 3099 est libre ou répond * * Usage: * overmind-verify # après installation * node scripts/verify-install.mjs * ═══════════════════════════════════════════════════════════════════════════════ */ import { execSync } from 'child_process'; import { existsSync, readFileSync } from 'fs'; import { join } from 'path'; import { createRequire } from 'module'; const require = createRequire(import.meta.url); let PKG_VERSION = 'unknown'; try { const pkg = require('../../package.json'); PKG_VERSION = pkg.version; } catch {} const C = { green: '\x1b[32m', yellow: '\x1b[33m', red: '\x1b[31m', cyan: '\x1b[36m', bold: '\x1b[1m', reset: '\x1b[0m', }; const HOME = process.env.HOME || process.env.USERPROFILE || process.env.HOMEPATH || ''; const OVERMIND_DIR = join(HOME, '.overmind'); const OVERMIND_HERMES_DIR = join(OVERMIND_DIR, 'hermes'); const NATIVE_HERMES_DIR = join(HOME, '.hermes'); const ENV_FILE = join(OVERMIND_DIR, '.env'); let passed = 0; let warnings = 0; let failed = 0; function ok(msg) { console.log(`${C.green} ✅${C.reset} ${msg}`); passed++; } function warn(msg) { console.log(`${C.yellow} ⚠️ ${C.reset} ${msg}`); warnings++; } function fail(msg) { console.log(`${C.red} ❌${C.reset} ${msg}`); failed++; } function runCmd(cmd) { try { return execSync(cmd, { encoding: 'utf8', timeout: 5000, stdio: 'pipe' }).trim(); } catch { return null; } } // ═══════════════════════════════════════════════════════════════════════════════ console.log(`\n${C.bold}${C.cyan}══════════════════════════════════════════════════════${C.reset}`); console.log(`${C.bold}${C.cyan} 🧪 Overmind Post-Install Verification v${PKG_VERSION}${C.reset}`); console.log(`${C.bold}${C.cyan}══════════════════════════════════════════════════════${C.reset}\n`); // 1. Binaire overmind console.log(`${C.bold}1. Binaire overmind${C.reset}`); const overmindBin = runCmd('which overmind') || runCmd('where overmind'); if (overmindBin) { ok(`overmind trouvé: ${overmindBin}`); } else { fail('overmind non trouvé dans le PATH — rejeu: npm install -g overmind-mcp'); } const version = runCmd('overmind --version 2>&1') || runCmd('overmind version 2>&1'); if (version && (version.includes(PKG_VERSION) || version.length > 0)) { ok(`Version: ${version.split('\n')[0]}`); } else { warn('overmind --version ne répond pas (peut nécessiter .env configuré)'); } // 2. .env console.log(`\n${C.bold}2. Configuration .env${C.reset}`); if (!existsSync(ENV_FILE)) { fail(`${ENV_FILE} non trouvé — rejeu: overmind-setup`); } else { ok('.env existe'); const envContent = readFileSync(ENV_FILE, 'utf8'); const requiredVars = [ 'POSTGRES_HOST', 'POSTGRES_DATABASE', 'POSTGRES_PASSWORD', 'POSTGRES_USER', ]; for (const varName of requiredVars) { const re = new RegExp(`^${varName}=(.+)$`, 'm'); const match = envContent.match(re); if (match && match[1].trim() && !match[1].includes('change_me')) { ok(`${varName} = ${match[1].substring(0, 8)}...`); } else if (match && match[1].includes('change_me')) { warn(`${varName} contient encore le mot de passe par défaut — changez-le!`); } else { fail(`${varName} manquant dans .env`); } } // Check for old POSTGRES_DB (v2.x compat) if (envContent.match(/^POSTGRES_DB=/m) && !envContent.match(/^POSTGRES_DATABASE=/m)) { warn('POSTGRES_DB détecté (v2.x) — renommez en POSTGRES_DATABASE (v3.x)'); } } // 3. PostgreSQL console.log(`\n${C.bold}3. PostgreSQL${C.reset}`); const pgDocker = runCmd('docker ps --filter "name=postgres" --format "{{.Names}}" 2>/dev/null'); const pgNative = runCmd('pg_isready -h localhost -p 5432 2>/dev/null'); if (pgDocker && pgDocker.length > 0) { ok(`PostgreSQL Docker actif: ${pgDocker.split('\n')[0]}`); } else if (pgNative && pgNative.includes('accepting')) { ok('PostgreSQL natif actif sur :5432'); } else { warn('PostgreSQL non détecté — démarrez-le: overmind-postgres-mcp up (Docker) ou sudo apt install postgresql (natif)'); } // 4. Port 3099 console.log(`\n${C.bold}4. Port Overmind MCP${C.reset}`); const portCheck = runCmd('lsof -iTCP:3099 -sTCP:LISTEN 2>/dev/null') || runCmd('ss -tlnp 2>/dev/null | grep 3099'); if (portCheck && portCheck.length > 0) { ok('Port 3099 en écoute — Overmind MCP est démarré'); } else { warn('Port 3099 libre — démarrez: overmind --transport httpStream --port 3099'); } // 5. MCP health check if (portCheck) { console.log(`\n${C.bold}5. MCP Health Check${C.reset}`); const health = runCmd('curl -s -m 5 http://localhost:3099/mcp -X POST -H "Content-Type: application/json" -d \'{"jsonrpc":"2.0","id":1,"method":"ping","params":{}}\' 2>/dev/null'); if (health && (health.includes('jsonrpc') || health.includes('pong'))) { ok('MCP :3099 répond au ping'); } else { warn('MCP :3099 ne répond pas au ping (peut nécessiter auth token)'); } } // 6. Hermes root alignment console.log(`\n${C.bold}6. Hermes root alignment${C.reset}`); if (process.platform === 'win32') { ok('Windows Desktop: racine attendue = %LOCALAPPDATA%\\hermes (pas de symlink ~/.hermes)'); } else if (!existsSync(OVERMIND_HERMES_DIR)) { warn('~/.overmind/hermes absent — sera créé par overmind-install-native ou postinstall'); } else if (!existsSync(NATIVE_HERMES_DIR)) { warn('~/.hermes absent — postinstall devrait créer le symlink vers ~/.overmind/hermes'); } else { const linkTarget = runCmd(`readlink "${NATIVE_HERMES_DIR}" 2>/dev/null`); if (linkTarget === OVERMIND_HERMES_DIR) { ok('~/.hermes → ~/.overmind/hermes (symlink complet OK)'); } else { const nativeProfilesTarget = runCmd(`readlink "${NATIVE_HERMES_DIR}/profiles" 2>/dev/null`); const nativeConfigTarget = runCmd(`readlink "${NATIVE_HERMES_DIR}/config.yaml" 2>/dev/null`); if (nativeProfilesTarget && nativeConfigTarget) { warn('Mode hybride détecté: ~/.hermes est un vrai dossier mais profiles/config.yaml sont symlinkés. Rejeu recommandé: npm i -g overmind-mcp@latest ou overmind-install-native'); } else { warn('Dual-path détecté: ~/.hermes n’est pas symlinké vers ~/.overmind/hermes. Risque de config divergente.'); } } } // 7. Hermes (optionnel) console.log(`\n${C.bold}7. Hermes CLI (optionnel)${C.reset}`); const hermes = runCmd('which hermes 2>/dev/null'); if (hermes) { const hermesVersion = runCmd('hermes version 2>/dev/null'); ok(`Hermes trouvé: ${hermes} (${hermesVersion || 'version inconnue'})`); } else { warn('Hermes non installé — requis pour les agents Hermes: pip install hermes-agent'); } // ═══════════════════════════════════════════════════════════════════════════════ console.log(`\n${C.bold}${C.cyan}══════════════════════════════════════════════════════${C.reset}`); console.log(`${C.bold} Résultat: ${C.green}${passed} OK${C.reset}${failed > 0 ? `, ${C.red}${failed} échec${C.reset}` : ''}${warnings > 0 ? `, ${C.yellow}${warnings} avertissement${warnings > 1 ? 's' : ''}${C.reset}` : ''}`); console.log(`${C.bold}${C.cyan}══════════════════════════════════════════════════════${C.reset}\n`); if (failed > 0) { console.log(`${C.red}${C.bold}❌ Échec — corrigez les erreurs ci-dessus avant de continuer.${C.reset}\n`); process.exit(1); } else if (warnings > 0) { console.log(`${C.yellow}⚠️ Installation fonctionnelle avec avertissements.${C.reset}\n`); process.exit(0); } else { console.log(`${C.green}${C.bold}✅ Tout est prêt! Overmind MCP est opérationnel.${C.reset}\n`); process.exit(0); }