mcp-quiz-server
Version:
🧠 AI-Powered Quiz Management via Model Context Protocol (MCP) - Create, manage, and take quizzes directly from VS Code, Claude, and other AI agents.
255 lines (254 loc) • 10.2 kB
JavaScript
;
/**
* @fileoverview Setup Orchestrator - Coordinates the entire setup process
* @version 1.0.0
* @since 2025-07-31
* @module SetupOrchestrator
* @description Coordinates setup wizard execution and integration with server startup
* @contributors Claude Code Agent
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.SetupOrchestrator = void 0;
const AsciiAnimations_1 = __importDefault(require("./AsciiAnimations"));
const MinimalSetupWizard_1 = require("./MinimalSetupWizard");
class SetupOrchestrator {
constructor(config = {}) {
this.config = {
mode: 'interactive',
force: false,
skipValidation: false,
...config,
};
// Initialize setup wizard
this.wizard = new MinimalSetupWizard_1.MinimalSetupWizard();
}
/**
* Check if setup is required based on configuration and current state
*/
async isSetupRequired() {
if (this.config.force) {
return true;
}
const isComplete = await this.wizard.isSetupComplete();
return !isComplete;
}
/**
* Run setup process and return integration result
*/
async runSetup() {
try {
console.log('🎯 MCP Quiz Server Setup Starting...\n');
// Check if setup is needed
const setupRequired = await this.isSetupRequired();
if (!setupRequired) {
return {
setupRan: false,
result: null,
integrationSuccess: true,
message: 'Setup already completed, proceeding with server startup',
};
}
// Run the setup wizard
const setupResult = await this.wizard.runIfNeeded();
if (!setupResult) {
return {
setupRan: false,
result: null,
integrationSuccess: true,
message: 'No setup required',
};
}
// Validate setup result
await this.validateSetupResult(setupResult);
return {
setupRan: true,
result: setupResult,
integrationSuccess: true,
message: 'Setup completed successfully, server ready to start',
};
}
catch (error) {
console.error('❌ Setup failed:', error.message);
AsciiAnimations_1.default.displayError(`Setup orchestration failed: ${error.message}`);
return {
setupRan: false,
result: null,
integrationSuccess: false,
message: `Setup failed: ${error.message}`,
};
}
}
/**
* Validate that setup result is complete and valid
*/
async validateSetupResult(result) {
if (this.config.skipValidation) {
return;
}
// Validate admin configuration
if (!result.admin.username || !result.admin.password) {
throw new Error('Invalid admin configuration');
}
// Validate server configuration
if (!result.server.port || result.server.port < 1024 || result.server.port > 65535) {
throw new Error('Invalid server port configuration');
}
// Validate security configuration
if (!result.security.jwtSecret || result.security.jwtSecret.length < 32) {
throw new Error('Invalid security configuration');
}
// Validate features configuration
if (!result.features.userAuth) {
console.warn('⚠️ Warning: User authentication is disabled');
}
console.log('✅ Setup validation passed');
}
/**
* Get configuration object suitable for server integration
*/
static createServerConfig(setupResult) {
return {
server: {
port: setupResult.server.port,
host: setupResult.server.host,
environment: setupResult.server.environment,
},
features: setupResult.features,
security: {
jwtSecret: setupResult.security.jwtSecret,
sessionTimeout: setupResult.security.sessionTimeout,
maxSessions: setupResult.security.maxSessions,
enableRotation: setupResult.security.enableRotation,
},
admin: {
username: setupResult.admin.username,
email: setupResult.admin.email,
// Note: password hash should be computed separately for security
passwordHash: MinimalSetupWizard_1.MinimalSetupWizard.hashPassword(setupResult.admin.password),
},
setup: {
completed: true,
timestamp: setupResult.setupTimestamp,
version: '1.0.0',
},
};
}
/**
* Run silent setup with minimal prompts (for CI/CD)
*/
async runSilentSetup(defaults = {}) {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
console.log('🤖 Running silent setup with defaults...');
try {
const setupResult = {
admin: {
username: ((_a = defaults.admin) === null || _a === void 0 ? void 0 : _a.username) || 'admin',
password: ((_b = defaults.admin) === null || _b === void 0 ? void 0 : _b.password) || MinimalSetupWizard_1.MinimalSetupWizard.generateJenkinsStylePassword(),
email: ((_c = defaults.admin) === null || _c === void 0 ? void 0 : _c.email) || 'admin@localhost',
},
server: {
port: ((_d = defaults.server) === null || _d === void 0 ? void 0 : _d.port) || 3000,
host: ((_e = defaults.server) === null || _e === void 0 ? void 0 : _e.host) || '0.0.0.0',
environment: ((_f = defaults.server) === null || _f === void 0 ? void 0 : _f.environment) || 'production',
},
security: {
jwtSecret: ((_g = defaults.security) === null || _g === void 0 ? void 0 : _g.jwtSecret) || require('crypto').randomBytes(64).toString('hex'),
sessionTimeout: ((_h = defaults.security) === null || _h === void 0 ? void 0 : _h.sessionTimeout) || 30,
maxSessions: ((_j = defaults.security) === null || _j === void 0 ? void 0 : _j.maxSessions) || 3,
enableRotation: ((_k = defaults.security) === null || _k === void 0 ? void 0 : _k.enableRotation) || true,
},
features: defaults.features || {
userAuth: true,
cloudSync: false,
multiUser: false,
analytics: false,
localQuizzes: true,
timerFeature: true,
mcpProtocol: true,
},
setupTimestamp: new Date(),
};
// Save the setup result using the wizard's save method
await this.wizard.saveSetupResult(setupResult);
console.log('✅ Silent setup completed');
console.log(`📋 Admin credentials: ${setupResult.admin.username} / ${setupResult.admin.password}`);
console.log('📁 Configuration saved to .setup/ directory');
return {
setupRan: true,
result: setupResult,
integrationSuccess: true,
message: 'Silent setup completed successfully',
};
}
catch (error) {
return {
setupRan: false,
result: null,
integrationSuccess: false,
message: `Silent setup failed: ${error.message}`,
};
}
}
/**
* Reset setup (for development/testing)
*/
async resetSetup() {
console.log('🔄 Resetting setup...');
const fs = require('fs');
const path = require('path');
const setupDir = path.join(process.cwd(), '.setup');
const configDir = path.join(process.cwd(), 'config');
try {
// Remove setup files
const setupCompleteFile = path.join(setupDir, 'setup-complete.json');
const passwordFile = path.join(setupDir, 'initial-admin-password.txt');
const configFile = path.join(configDir, 'setup-config.json');
[setupCompleteFile, passwordFile, configFile].forEach(file => {
if (fs.existsSync(file)) {
fs.unlinkSync(file);
console.log(`✅ Removed: ${file}`);
}
});
console.log('🔄 Setup reset completed');
}
catch (error) {
console.error('❌ Setup reset failed:', error.message);
throw error;
}
}
/**
* Get setup status for health checks
*/
async getSetupStatus() {
const setupComplete = await this.wizard.isSetupComplete();
if (!setupComplete) {
return {
setupComplete: false,
configExists: false,
};
}
try {
const fs = require('fs');
const path = require('path');
const setupFile = path.join(process.cwd(), '.setup', 'setup-complete.json');
const configFile = path.join(process.cwd(), 'config', 'setup-config.json');
const setupData = JSON.parse(fs.readFileSync(setupFile, 'utf8'));
return {
setupComplete: true,
configExists: fs.existsSync(configFile),
timestamp: setupData.timestamp,
version: setupData.version,
};
}
catch (_a) {
return {
setupComplete: false,
configExists: false,
};
}
}
}
exports.SetupOrchestrator = SetupOrchestrator;