@versatil/sdlc-framework
Version:
š AI-Native SDLC framework with 11-MCP ecosystem, RAG memory, OPERA orchestration, and 6 specialized agents achieving ZERO CONTEXT LOSS. Features complete CI/CD pipeline with 7 GitHub workflows (MCP testing, security scanning, performance benchmarking),
293 lines ⢠14 kB
JavaScript
/**
* VERSATIL SDLC Framework - Configuration Wizard
* Interactive setup wizard for first-time users
*/
import * as readline from 'readline';
import { PreferenceManager } from './preference-manager.js';
import { ConfigProfileManager } from './config-profiles.js';
export class ConfigWizard {
constructor() {
this.rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
this.preferenceManager = new PreferenceManager();
this.profileManager = new ConfigProfileManager();
}
/**
* Run the setup wizard
*/
async run() {
console.log('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
console.log('ā š VERSATIL SDLC Framework - First-Time Setup š ā');
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n');
console.log('Welcome! Let\'s configure your framework preferences.\n');
console.log('You can change these settings anytime using: versatil config\n');
// Ask if user wants quick setup or custom
const setupType = await this.askChoice('Choose setup type:', [
{ key: '1', label: 'Quick Setup (use recommended defaults)', value: 'quick' },
{ key: '2', label: 'Custom Setup (choose your preferences)', value: 'custom' },
{ key: '3', label: 'Use Profile (conservative/balanced/aggressive)', value: 'profile' }
], '1');
let preferences;
if (setupType === 'quick') {
preferences = await this.quickSetup();
}
else if (setupType === 'profile') {
preferences = await this.profileSetup();
}
else {
preferences = await this.customSetup();
}
// Save preferences
await this.preferenceManager.savePreferences(preferences);
console.log('\nā
Setup complete! Your preferences have been saved.\n');
console.log('To view your preferences: versatil config show');
console.log('To modify preferences: versatil config set <key> <value>\n');
this.rl.close();
return preferences;
}
/**
* Quick setup with recommended defaults
*/
async quickSetup() {
console.log('\nš¦ Quick Setup - Using Recommended Defaults\n');
const preferences = this.preferenceManager.getDefaultPreferences();
console.log('Your configuration:');
console.log(' ⢠Update Behavior: Notify (you approve updates)');
console.log(' ⢠Update Channel: Stable (production-ready only)');
console.log(' ⢠Safety Level: Balanced (good balance of safety and speed)');
console.log(' ⢠Auto-install Security Updates: Yes');
console.log(' ⢠Backup Before Update: Yes');
console.log(' ⢠Auto-rollback on Failure: Yes');
console.log(' ⢠Telemetry: Yes (helps improve the framework)');
const confirm = await this.askYesNo('\nContinue with these settings?', true);
if (!confirm) {
console.log('\nLet\'s try custom setup instead...\n');
return await this.customSetup();
}
return preferences;
}
/**
* Profile-based setup
*/
async profileSetup() {
console.log('\nš Profile-Based Setup\n');
const profiles = this.profileManager.getAvailableProfiles();
console.log('Available profiles:\n');
profiles.forEach(profile => {
console.log(`${profile.emoji} ${profile.name}:`);
console.log(` ${profile.description}`);
console.log(` Best for: ${profile.bestFor}`);
console.log('');
});
const profileChoice = await this.askChoice('Choose a profile:', [
{ key: '1', label: 'Conservative (maximum safety)', value: 'conservative' },
{ key: '2', label: 'Balanced (recommended)', value: 'balanced' },
{ key: '3', label: 'Aggressive (latest features)', value: 'aggressive' }
], '2');
const profile = this.profileManager.getProfile(profileChoice);
if (!profile) {
throw new Error('Invalid profile');
}
console.log(`\nā
Using ${profile.name} profile\n`);
return profile.preferences;
}
/**
* Custom setup with user choices
*/
async customSetup() {
console.log('\nāļø Custom Setup\n');
const preferences = this.preferenceManager.getDefaultPreferences();
// Update behavior
console.log('āāā Update Behavior āāā\n');
preferences.updateBehavior = await this.askChoice('How should updates be handled?', [
{ key: '1', label: 'Auto - Install updates automatically', value: 'auto' },
{ key: '2', label: 'Notify - Notify me, I approve (recommended)', value: 'notify' },
{ key: '3', label: 'Manual - I check for updates manually', value: 'manual' }
], '2');
// Update channel
console.log('\nāāā Update Channel āāā\n');
preferences.updateChannel = await this.askChoice('Which update channel?', [
{ key: '1', label: 'Stable - Production-ready releases only (recommended)', value: 'stable' },
{ key: '2', label: 'Beta - Early access to new features', value: 'beta' },
{ key: '3', label: 'Alpha - Bleeding edge (may be unstable)', value: 'alpha' }
], '1');
// Safety level
console.log('\nāāā Safety Level āāā\n');
preferences.safetyLevel = await this.askChoice('Choose safety level:', [
{ key: '1', label: 'Conservative - Maximum safety, slower updates', value: 'conservative' },
{ key: '2', label: 'Balanced - Good balance (recommended)', value: 'balanced' },
{ key: '3', label: 'Fast - Faster updates, less validation', value: 'fast' }
], '2');
// Security updates
console.log('\nāāā Security Updates āāā\n');
preferences.autoInstallSecurity = await this.askYesNo('Auto-install security updates? (recommended: yes)', true);
// Backup
console.log('\nāāā Backup āāā\n');
preferences.backupBeforeUpdate = await this.askYesNo('Create backup before each update? (recommended: yes)', true);
if (preferences.backupBeforeUpdate) {
const maxBackupsStr = await this.askInput('Maximum number of backups to keep:', '5');
preferences.maxRollbackPoints = parseInt(maxBackupsStr, 10) || 5;
}
// Rollback
console.log('\nāāā Rollback āāā\n');
preferences.rollbackOnFailure = await this.askYesNo('Auto-rollback if update fails? (recommended: yes)', true);
// Notifications
console.log('\nāāā Notifications āāā\n');
preferences.notificationLevel = await this.askChoice('Notification level:', [
{ key: '1', label: 'All - Show all notifications', value: 'all' },
{ key: '2', label: 'Important - Important updates only (recommended)', value: 'important' },
{ key: '3', label: 'Critical - Critical updates only', value: 'critical' },
{ key: '4', label: 'None - No notifications', value: 'none' }
], '2');
// Telemetry
console.log('\nāāā Telemetry āāā\n');
console.log('Telemetry helps us improve the framework by collecting anonymous usage data.');
console.log('No personal information is collected.\n');
preferences.enableTelemetry = await this.askYesNo('Enable telemetry?', true);
if (preferences.enableTelemetry) {
preferences.shareErrorReports = await this.askYesNo('Share error reports?', true);
preferences.shareUsageStatistics = await this.askYesNo('Share usage statistics?', false);
}
console.log('\n');
return preferences;
}
/**
* Ask yes/no question
*/
async askYesNo(question, defaultValue) {
const defaultStr = defaultValue ? 'Y/n' : 'y/N';
const answer = await this.askInput(`${question} (${defaultStr}):`, defaultValue ? 'y' : 'n');
const normalized = answer.toLowerCase().trim();
if (normalized === '') {
return defaultValue;
}
return normalized === 'y' || normalized === 'yes';
}
/**
* Ask input question
*/
async askInput(question, defaultValue = '') {
return new Promise(resolve => {
this.rl.question(`${question} ${defaultValue ? `[${defaultValue}]` : ''} `, answer => {
resolve(answer.trim() || defaultValue);
});
});
}
/**
* Ask choice question
*/
async askChoice(question, choices, defaultKey = '1') {
console.log(question);
choices.forEach(choice => {
console.log(` ${choice.key}. ${choice.label}`);
});
const answer = await this.askInput('\nYour choice:', defaultKey);
const choice = choices.find(c => c.key === answer);
if (!choice) {
console.log(`Invalid choice. Using default: ${choices.find(c => c.key === defaultKey)?.label}`);
return choices.find(c => c.key === defaultKey)?.value;
}
return choice.value;
}
/**
* Run minimal wizard (for CI/automated installs)
*/
async runMinimal() {
console.log('š Running automated setup with defaults...');
const preferences = this.preferenceManager.getDefaultPreferences();
// Disable interactive features for CI
preferences.updateBehavior = 'manual';
preferences.notificationLevel = 'none';
preferences.enableTelemetry = false;
await this.preferenceManager.savePreferences(preferences);
console.log('ā
Automated setup complete');
return preferences;
}
/**
* Update preferences interactively
*/
async updatePreferences() {
console.log('\nāļø Update Preferences\n');
const preferences = await this.preferenceManager.getPreferences();
console.log('Current preferences:');
console.log(await this.preferenceManager.getSummary());
console.log('');
const category = await this.askChoice('What would you like to change?', [
{ key: '1', label: 'Update settings', value: 'update' },
{ key: '2', label: 'Rollback settings', value: 'rollback' },
{ key: '3', label: 'Notification settings', value: 'notification' },
{ key: '4', label: 'Telemetry settings', value: 'telemetry' },
{ key: '5', label: 'View all settings', value: 'view' },
{ key: '6', label: 'Reset to defaults', value: 'reset' }
], '1');
switch (category) {
case 'update':
await this.updateUpdateSettings(preferences);
break;
case 'rollback':
await this.updateRollbackSettings(preferences);
break;
case 'notification':
await this.updateNotificationSettings(preferences);
break;
case 'telemetry':
await this.updateTelemetrySettings(preferences);
break;
case 'view':
console.log(await this.preferenceManager.getSummary());
break;
case 'reset':
const confirm = await this.askYesNo('Reset all preferences to defaults?', false);
if (confirm) {
await this.preferenceManager.resetToDefaults();
}
break;
}
this.rl.close();
}
async updateUpdateSettings(preferences) {
preferences.updateBehavior = await this.askChoice('Update behavior:', [
{ key: '1', label: 'Auto', value: 'auto' },
{ key: '2', label: 'Notify', value: 'notify' },
{ key: '3', label: 'Manual', value: 'manual' }
], preferences.updateBehavior === 'auto' ? '1' : preferences.updateBehavior === 'notify' ? '2' : '3');
await this.preferenceManager.savePreferences(preferences);
}
async updateRollbackSettings(preferences) {
preferences.rollbackOnFailure = await this.askYesNo('Auto-rollback on failure?', preferences.rollbackOnFailure);
await this.preferenceManager.savePreferences(preferences);
}
async updateNotificationSettings(preferences) {
preferences.notificationLevel = await this.askChoice('Notification level:', [
{ key: '1', label: 'All', value: 'all' },
{ key: '2', label: 'Important', value: 'important' },
{ key: '3', label: 'Critical', value: 'critical' },
{ key: '4', label: 'None', value: 'none' }
], preferences.notificationLevel === 'all'
? '1'
: preferences.notificationLevel === 'important'
? '2'
: preferences.notificationLevel === 'critical'
? '3'
: '4');
await this.preferenceManager.savePreferences(preferences);
}
async updateTelemetrySettings(preferences) {
preferences.enableTelemetry = await this.askYesNo('Enable telemetry?', preferences.enableTelemetry);
await this.preferenceManager.savePreferences(preferences);
}
}
/**
* Default config wizard instance (singleton)
* Lazy-loaded to avoid stdin issues in test environments
*/
let _defaultConfigWizard = null;
export function getDefaultConfigWizard() {
if (!_defaultConfigWizard) {
_defaultConfigWizard = new ConfigWizard();
}
return _defaultConfigWizard;
}
//# sourceMappingURL=config-wizard.js.map