@genxis/whmrockstar
Version:
šø GenXis WHMRockStar - AI-powered multi-server WHM/cPanel management via Model Context Protocol (MCP). Enhanced with proper MCP stdio protocol support and multi-server management.
491 lines (423 loc) ⢠16.7 kB
JavaScript
/**
* GenXis WHMRockStar CLI
* Enhanced multi-server setup and management tool
*/
const fs = require('fs');
const path = require('path');
const inquirer = require('inquirer');
const chalk = require('chalk');
const { execSync } = require('child_process');
const MultiServerManager = require('../lib/multi-server-manager');
class GenXisCLI {
constructor() {
this.configDir = path.join(process.env.HOME || process.env.USERPROFILE, '.genxis-whmrockstar');
this.configFile = path.join(this.configDir, 'config.json');
this.mcpFile = path.join(this.configDir, 'mcp-settings.json');
this.serverManager = new MultiServerManager();
}
async run() {
const args = process.argv.slice(2);
const command = args[0] || 'help';
console.log(chalk.blue.bold('šø GenXis WHMRockStar'));
console.log(chalk.gray('AI-powered WHM/cPanel management via MCP\n'));
switch (command) {
case 'setup':
await this.setup(args.includes('--force'));
break;
case 'add-server':
await this.addServer();
break;
case 'remove-server':
await this.removeServer(args[1]);
break;
case 'list-servers':
await this.listServers();
break;
case 'test':
await this.test(args[1]);
break;
case 'test-all':
await this.testAllServers();
break;
case 'config':
await this.showConfig(args[1]);
break;
case 'start':
await this.start();
break;
case 'logs':
await this.showLogs();
break;
case 'help':
default:
this.showHelp();
break;
}
}
async setup(force = false) {
console.log(chalk.yellow('š Setting up GenXis WHMRockStar...\n'));
// Check if servers already configured
if (this.serverManager.hasServers() && !force) {
const { overwrite } = await inquirer.prompt([{
type: 'confirm',
name: 'overwrite',
message: 'Server configurations already exist. Add another server or reconfigure?',
default: false
}]);
if (!overwrite) {
console.log(chalk.green('ā
Setup cancelled. Use --force to overwrite or "add-server" to add more servers.'));
return;
}
}
// Create config directory
if (!fs.existsSync(this.configDir)) {
fs.mkdirSync(this.configDir, { recursive: true });
}
// Get server configuration
const serverConfig = await this.getServerConfig();
// Test connection
console.log(chalk.yellow('š Testing WHM connection...'));
const testResult = await this.testWHMConnection(serverConfig);
if (!testResult.success) {
console.log(chalk.red('ā Connection failed:'), testResult.error);
console.log(chalk.yellow('Please check your server IP and API token.'));
return;
}
console.log(chalk.green('ā
WHM connection successful!'));
// Add server to manager
const serverId = serverConfig.id || 'default';
try {
this.serverManager.addServer(serverId, serverConfig);
console.log(chalk.green('ā
Server configuration saved'));
} catch (error) {
console.log(chalk.red('ā Failed to save server configuration:'), error.message);
return;
}
// Generate MCP settings
await this.generateMCPSettings();
console.log(chalk.green('ā
MCP settings generated'));
// Install MCP integration
await this.installMCPIntegration();
console.log(chalk.green.bold('\nš Setup complete!'));
console.log(chalk.white('You can now use WHM management in your AI assistant.'));
console.log(chalk.gray('Run "genxis-whm start" to start the MCP server manually.'));
console.log(chalk.gray('Use "genxis-whm add-server" to add more servers.'));
}
async getServerConfig() {
const questions = [
{
type: 'input',
name: 'id',
message: 'Server ID (unique identifier):',
default: 'server1',
validate: (input) => {
if (!input || input.trim().length === 0) {
return 'Server ID is required';
}
if (this.serverManager.servers && this.serverManager.servers.has(input)) {
return 'Server ID already exists. Please choose a different ID.';
}
return true;
}
},
{
type: 'input',
name: 'name',
message: 'Server Name (display name):',
validate: (input) => input.length > 0 || 'Server name is required'
},
{
type: 'input',
name: 'server',
message: 'WHM Server IP Address:',
validate: (input) => {
const ipRegex = /^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$/;
return ipRegex.test(input) || 'Please enter a valid IP address';
}
},
{
type: 'input',
name: 'apiToken',
message: 'WHM API Token:',
validate: (input) => input.length > 10 || 'API token seems too short'
},
{
type: 'input',
name: 'port',
message: 'WHM Port:',
default: '2087'
},
{
type: 'input',
name: 'username',
message: 'WHM Username:',
default: 'root'
}
];
return await inquirer.prompt(questions);
}
async testWHMConnection(config) {
try {
const WHMService = require('../lib/whm-service');
const whm = new WHMService(config);
await whm.get('version');
return { success: true };
} catch (error) {
return { success: false, error: error.message };
}
}
async generateMCPSettings() {
const mcpSettings = {
mcpServers: {
"genxis-whm": {
command: "node",
args: [path.join(__dirname, '..', 'mcp-server.js')],
disabled: false,
alwaysAllow: [],
disabledTools: []
}
}
};
fs.writeFileSync(this.mcpFile, JSON.stringify(mcpSettings, null, 2));
}
async installMCPIntegration() {
console.log(chalk.yellow('š§ Installing MCP integration...'));
const integrations = [
{
name: 'VS Code (Roo-Cline)',
path: path.join(process.env.APPDATA || process.env.HOME, 'Code', 'User', 'globalStorage', 'rooveterinaryinc.roo-cline', 'settings', 'mcp_settings.json'),
check: () => fs.existsSync(path.dirname(this.getVSCodePath()))
},
{
name: 'VS Code (Claude)',
path: path.join(process.env.APPDATA || process.env.HOME, 'Code', 'User', 'settings.json'),
check: () => fs.existsSync(path.dirname(this.getVSCodePath()))
},
{
name: 'Windsurf',
path: path.join(process.env.APPDATA || process.env.HOME, 'Windsurf', 'mcp.json'),
check: () => fs.existsSync(path.dirname(this.getWindsurfPath()))
}
];
for (const integration of integrations) {
if (integration.check()) {
try {
await this.updateIDEConfig(integration.path);
console.log(chalk.green(`ā
${integration.name} integration installed`));
} catch (error) {
console.log(chalk.yellow(`ā ļø ${integration.name} integration failed: ${error.message}`));
}
}
}
}
getVSCodePath() {
const appData = process.env.APPDATA || path.join(process.env.HOME, '.config');
return path.join(appData, 'Code', 'User', 'globalStorage', 'rooveterinaryinc.roo-cline', 'settings', 'mcp_settings.json');
}
getWindsurfPath() {
const appData = process.env.APPDATA || path.join(process.env.HOME, '.config');
return path.join(appData, 'Windsurf', 'mcp.json');
}
async updateIDEConfig(configPath) {
const mcpSettings = JSON.parse(fs.readFileSync(this.mcpFile, 'utf8'));
// Ensure directory exists
const dir = path.dirname(configPath);
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
// Read existing config or create new
let existingConfig = {};
if (fs.existsSync(configPath)) {
try {
existingConfig = JSON.parse(fs.readFileSync(configPath, 'utf8'));
} catch (error) {
// Invalid JSON, start fresh
existingConfig = {};
}
}
// Merge configurations
if (!existingConfig.mcpServers) {
existingConfig.mcpServers = {};
}
Object.assign(existingConfig.mcpServers, mcpSettings.mcpServers);
// Write updated config
fs.writeFileSync(configPath, JSON.stringify(existingConfig, null, 2));
}
async addServer() {
console.log(chalk.yellow('ā Adding new WHM server...\n'));
const serverConfig = await this.getServerConfig();
// Test connection
console.log(chalk.yellow('š Testing WHM connection...'));
const testResult = await this.testWHMConnection(serverConfig);
if (!testResult.success) {
console.log(chalk.red('ā Connection failed:'), testResult.error);
return;
}
console.log(chalk.green('ā
WHM connection successful!'));
// Add server
try {
this.serverManager.addServer(serverConfig.id, serverConfig);
console.log(chalk.green(`ā
Server '${serverConfig.id}' added successfully!`));
} catch (error) {
console.log(chalk.red('ā Failed to add server:'), error.message);
}
}
async removeServer(serverId) {
if (!serverId) {
console.log(chalk.red('ā Server ID is required. Usage: genxis-whm remove-server <server-id>'));
return;
}
try {
this.serverManager.removeServer(serverId);
console.log(chalk.green(`ā
Server '${serverId}' removed successfully!`));
} catch (error) {
console.log(chalk.red('ā Failed to remove server:'), error.message);
}
}
async listServers() {
const servers = this.serverManager.listServers();
if (servers.length === 0) {
console.log(chalk.yellow('š No servers configured. Run "genxis-whm setup" to add a server.'));
return;
}
console.log(chalk.blue('š Configured WHM Servers:\n'));
servers.forEach((server, index) => {
const status = server.enabled ? chalk.green('ā
Enabled') : chalk.red('ā Disabled');
console.log(chalk.white(`${index + 1}. ${server.name}`));
console.log(chalk.gray(` ID: ${server.id}`));
console.log(chalk.gray(` Server: ${server.server}:${server.port}`));
console.log(chalk.gray(` Username: ${server.username}`));
console.log(` Status: ${status}\n`);
});
}
async test(serverId) {
if (!this.serverManager.hasServers()) {
console.log(chalk.red('ā No servers configured. Run "genxis-whm setup" first.'));
return;
}
if (serverId) {
// Test specific server
try {
console.log(chalk.yellow(`š Testing server '${serverId}'...`));
const result = await this.serverManager.testServer(serverId);
if (result.success) {
console.log(chalk.green(`ā
Server '${serverId}' connection successful!`));
console.log(chalk.white(`Server: ${result.server}`));
} else {
console.log(chalk.red(`ā Server '${serverId}' connection failed:`), result.error);
}
} catch (error) {
console.log(chalk.red('ā Test failed:'), error.message);
}
} else {
// Test all servers
await this.testAllServers();
}
}
async testAllServers() {
console.log(chalk.yellow('š Testing all configured servers...\n'));
const results = await this.serverManager.testAllServers();
results.forEach(result => {
if (result.success) {
console.log(chalk.green(`ā
${result.serverId}: Connection successful`));
} else {
console.log(chalk.red(`ā ${result.serverId}: ${result.error}`));
}
});
}
async showConfig(serverId) {
if (!this.serverManager.hasServers()) {
console.log(chalk.red('ā No servers configured. Run "genxis-whm setup" first.'));
return;
}
if (serverId) {
// Show specific server config
try {
const { config } = this.serverManager.getServer(serverId);
console.log(chalk.blue(`š Configuration for '${serverId}':`));
console.log(chalk.white(`Name: ${config.name}`));
console.log(chalk.white(`Server: ${config.server}:${config.port}`));
console.log(chalk.white(`Username: ${config.username}`));
console.log(chalk.white(`API Token: ${config.apiToken.substring(0, 8)}...`));
console.log(chalk.white(`Enabled: ${config.enabled !== false ? 'Yes' : 'No'}`));
} catch (error) {
console.log(chalk.red('ā Error:'), error.message);
}
} else {
// Show all servers
await this.listServers();
}
}
async start() {
if (!this.serverManager.hasServers()) {
console.log(chalk.red('ā No servers configured. Run "genxis-whm setup" first.'));
return;
}
console.log(chalk.yellow('š Starting GenXis WHMRockStar MCP Server...'));
try {
const WHMRockStarMCPServer = require('../mcp-server.js');
const server = new WHMRockStarMCPServer();
await server.start();
} catch (error) {
console.log(chalk.red('ā Failed to start server:'), error.message);
}
}
async showLogs() {
const logFile = path.join(this.configDir, 'logs', 'whm-operations.log');
if (!fs.existsSync(logFile)) {
console.log(chalk.yellow('š No logs found yet.'));
return;
}
console.log(chalk.blue('š Recent logs:'));
try {
const logs = fs.readFileSync(logFile, 'utf8');
const lines = logs.split('\n').slice(-20); // Last 20 lines
lines.forEach(line => {
if (line.includes('[ERROR]')) {
console.log(chalk.red(line));
} else if (line.includes('[WARN]')) {
console.log(chalk.yellow(line));
} else {
console.log(chalk.white(line));
}
});
} catch (error) {
console.log(chalk.red('ā Failed to read logs:'), error.message);
}
}
showHelp() {
console.log(chalk.blue('š Available Commands:\n'));
console.log(chalk.yellow('Setup & Configuration:'));
console.log(chalk.white(' setup ') + chalk.gray('Interactive setup wizard for first server'));
console.log(chalk.white(' setup --force ') + chalk.gray('Force overwrite existing config'));
console.log(chalk.white(' add-server ') + chalk.gray('Add additional WHM server'));
console.log(chalk.white(' remove-server <id> ') + chalk.gray('Remove a server configuration'));
console.log(chalk.white(' list-servers ') + chalk.gray('List all configured servers'));
console.log(chalk.yellow('\nTesting & Monitoring:'));
console.log(chalk.white(' test ') + chalk.gray('Test all server connections'));
console.log(chalk.white(' test <server-id> ') + chalk.gray('Test specific server connection'));
console.log(chalk.white(' test-all ') + chalk.gray('Test all servers with detailed output'));
console.log(chalk.yellow('\nConfiguration & Management:'));
console.log(chalk.white(' config ') + chalk.gray('Show all server configurations'));
console.log(chalk.white(' config <server-id> ') + chalk.gray('Show specific server configuration'));
console.log(chalk.white(' start ') + chalk.gray('Start MCP server'));
console.log(chalk.white(' logs ') + chalk.gray('Show recent operation logs'));
console.log(chalk.white(' help ') + chalk.gray('Show this help message'));
console.log(chalk.blue('\nš Quick Start:'));
console.log(chalk.white(' npx @genxis/whmrockstar setup'));
console.log(chalk.white(' npx @genxis/whmrockstar add-server'));
console.log(chalk.white(' npx @genxis/whmrockstar test'));
console.log(chalk.blue('\nš Documentation:'));
console.log(chalk.white(' https://www.npmjs.com/package/@genxis/whmrockstar'));
}
}
// Run CLI
if (require.main === module) {
const cli = new GenXisCLI();
cli.run().catch(error => {
console.error(chalk.red('ā CLI Error:'), error.message);
process.exit(1);
});
}
module.exports = GenXisCLI;