mak3r-hub
Version:
Universal Claude Code force multiplier for website development
465 lines (396 loc) • 13.2 kB
JavaScript
const fs = require('fs-extra');
const path = require('path');
const os = require('os');
const chalk = require('chalk');
class ConfigManager {
constructor(projectPath = process.cwd()) {
this.projectPath = projectPath;
this.configDir = path.join(projectPath, '.mak3r');
this.configFile = path.join(this.configDir, 'config.json');
this.rulesFile = path.join(this.configDir, 'claude-rules.json');
this.mcpFile = path.join(this.configDir, 'mcp-settings.json');
this.version = require('../package.json').version;
this.config = null;
}
async initialize() {
try {
await this.ensureConfigDirectory();
await this.loadConfiguration();
return true;
} catch (error) {
console.error(chalk.red(`❌ Failed to initialize configuration: ${error.message}`));
return false;
}
}
async ensureConfigDirectory() {
await fs.ensureDir(this.configDir);
await fs.ensureDir(path.join(this.configDir, 'logs'));
await fs.ensureDir(path.join(this.configDir, 'cache'));
await fs.ensureDir(path.join(this.configDir, 'templates'));
}
async loadConfiguration() {
if (fs.existsSync(this.configFile)) {
try {
this.config = JSON.parse(fs.readFileSync(this.configFile, 'utf8'));
return this.config;
} catch (error) {
console.warn(chalk.yellow('⚠️ Failed to parse existing config, creating new one'));
}
}
this.config = await this.createDefaultConfiguration();
return this.config;
}
async createDefaultConfiguration() {
const osType = os.platform();
const isWindows = osType === 'win32';
const projectName = path.basename(this.projectPath);
const config = {
project: {
name: projectName,
safe_name: this.sanitizeName(projectName),
type: 'unknown',
version: '1.0.0',
created: new Date().toISOString(),
mak3r_version: this.version
},
framework: {
primary: 'unknown',
version: 'unknown',
meta_framework: null,
features: []
},
environment: {
os: osType,
is_windows: isWindows,
is_unix: !isWindows,
node_version: process.version,
package_manager: await this.detectPackageManager(),
shell: process.env.SHELL || process.env.COMSPEC || 'unknown'
},
structure: {
active_dir: await this.detectActiveDirectory(),
scripts_dir: isWindows ? 'batch-ops' : 'scripts',
docs_dir: 'domain',
assets_dir: 'visual-input',
config_dir: '.mak3r'
},
files: {
main: await this.detectMainFile(),
config: await this.detectConfigFile(),
launch_script: null,
cleanup_script: null
},
ports: {
dev_server: 3000,
mcp_service: 3001,
api_server: 3002,
websocket: 3003
},
build: {
output_dir: 'dist',
source_dir: 'src',
assets_dir: 'assets',
public_dir: 'public'
},
development: {
auto_reload: true,
source_maps: true,
hot_reload: true,
error_overlay: true
},
deployment: {
target: 'vercel',
build_command: 'npm run build',
output_directory: 'dist',
environment_variables: {}
},
mak3r: {
abstractions_enabled: true,
os_validation_enabled: true,
token_optimization_enabled: true,
auto_documentation_enabled: true,
mcp_integration_enabled: true,
config_version: '1.0.0'
}
};
await this.saveConfiguration(config);
return config;
}
async detectActiveDirectory() {
const commonDirs = [
'vue-nuxt', 'react-next', 'svelte-kit', 'angular',
'src', 'app', 'client', 'frontend', 'web'
];
for (const dir of commonDirs) {
if (fs.existsSync(path.join(this.projectPath, dir))) {
return dir;
}
}
return 'src'; // default
}
async detectMainFile() {
const commonFiles = [
'app.vue', 'App.vue', 'app.tsx', 'App.tsx', 'app.js', 'App.js',
'pages/index.vue', 'app/page.tsx', 'src/App.vue', 'src/App.tsx',
'index.html', 'index.js', 'index.ts', 'main.js', 'main.ts'
];
for (const file of commonFiles) {
if (fs.existsSync(path.join(this.projectPath, file))) {
return file;
}
}
return 'index.html'; // default
}
async detectConfigFile() {
const configFiles = [
'nuxt.config.ts', 'nuxt.config.js',
'next.config.js', 'next.config.ts',
'vite.config.js', 'vite.config.ts',
'svelte.config.js', 'webpack.config.js',
'angular.json', 'vue.config.js'
];
for (const file of configFiles) {
if (fs.existsSync(path.join(this.projectPath, file))) {
return file;
}
}
return 'package.json'; // fallback
}
async detectPackageManager() {
if (fs.existsSync(path.join(this.projectPath, 'yarn.lock'))) {
return 'yarn';
} else if (fs.existsSync(path.join(this.projectPath, 'pnpm-lock.yaml'))) {
return 'pnpm';
} else if (fs.existsSync(path.join(this.projectPath, 'bun.lockb'))) {
return 'bun';
}
return 'npm'; // default
}
sanitizeName(name) {
return name.toLowerCase().replace(/[^a-z0-9-]/g, '-').replace(/^-+|-+$/g, '');
}
async saveConfiguration(config = this.config) {
try {
await fs.writeFile(this.configFile, JSON.stringify(config, null, 2));
this.config = config;
return true;
} catch (error) {
console.error(chalk.red(`❌ Failed to save configuration: ${error.message}`));
return false;
}
}
async updateConfiguration(updates) {
if (!this.config) {
await this.loadConfiguration();
}
// Deep merge updates
this.config = this.deepMerge(this.config, updates);
this.config.project.modified = new Date().toISOString();
return await this.saveConfiguration();
}
deepMerge(target, source) {
const result = { ...target };
for (const key in source) {
if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) {
result[key] = this.deepMerge(target[key] || {}, source[key]);
} else {
result[key] = source[key];
}
}
return result;
}
getConfiguration() {
return this.config;
}
getProjectInfo() {
return this.config?.project || null;
}
getFrameworkInfo() {
return this.config?.framework || null;
}
getEnvironmentInfo() {
return this.config?.environment || null;
}
getPortConfiguration() {
return this.config?.ports || { dev_server: 3000, mcp_service: 3001 };
}
async createCustomConfiguration(template = 'default') {
const templates = {
default: await this.createDefaultConfiguration(),
minimal: await this.createMinimalConfiguration(),
advanced: await this.createAdvancedConfiguration()
};
const config = templates[template] || templates.default;
await this.saveConfiguration(config);
return config;
}
async createMinimalConfiguration() {
const minimal = {
project: {
name: path.basename(this.projectPath),
version: '1.0.0',
mak3r_version: this.version
},
environment: {
os: os.platform(),
node_version: process.version
},
ports: {
dev_server: 3000,
mcp_service: 3001
},
mak3r: {
config_version: '1.0.0'
}
};
return minimal;
}
async createAdvancedConfiguration() {
const advanced = await this.createDefaultConfiguration();
// Add advanced features
advanced.features = {
hot_reload: true,
source_maps: true,
code_splitting: true,
tree_shaking: true,
bundle_analyzer: true,
performance_monitoring: true
};
advanced.optimization = {
minify: true,
compress: true,
cache: true,
parallel: true
};
advanced.security = {
cors_enabled: true,
helmet_enabled: true,
rate_limiting: true,
input_validation: true
};
advanced.monitoring = {
error_tracking: true,
performance_metrics: true,
user_analytics: false,
logging_level: 'info'
};
return advanced;
}
async generateConfigurationReport() {
if (!this.config) {
await this.loadConfiguration();
}
const report = {
generated: new Date().toISOString(),
project: this.config.project,
environment: this.config.environment,
structure: this.config.structure,
ports: this.config.ports,
features_enabled: Object.entries(this.config.mak3r)
.filter(([key, value]) => value === true)
.map(([key]) => key),
recommendations: []
};
// Add recommendations based on configuration
if (!this.config.mak3r.mcp_integration_enabled) {
report.recommendations.push('Enable MCP integration for Claude Code optimization');
}
if (!this.config.mak3r.os_validation_enabled) {
report.recommendations.push('Enable OS validation to prevent command errors');
}
if (this.config.framework.primary === 'unknown') {
report.recommendations.push('Specify framework for better tooling integration');
}
return report;
}
async exportConfiguration(format = 'json') {
if (!this.config) {
await this.loadConfiguration();
}
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
const filename = `mak3r-config-${timestamp}.${format}`;
const exportPath = path.join(this.configDir, 'exports', filename);
await fs.ensureDir(path.dirname(exportPath));
switch (format) {
case 'json':
await fs.writeFile(exportPath, JSON.stringify(this.config, null, 2));
break;
case 'yaml':
// Would need yaml library
throw new Error('YAML export not implemented yet');
default:
throw new Error(`Unsupported export format: ${format}`);
}
return exportPath;
}
async importConfiguration(configPath) {
try {
const importedConfig = JSON.parse(fs.readFileSync(configPath, 'utf8'));
// Validate imported config
if (!importedConfig.project || !importedConfig.mak3r) {
throw new Error('Invalid MAK3R-HUB configuration file');
}
// Update version and timestamps
importedConfig.project.mak3r_version = this.version;
importedConfig.project.imported = new Date().toISOString();
await this.saveConfiguration(importedConfig);
return true;
} catch (error) {
console.error(chalk.red(`❌ Failed to import configuration: ${error.message}`));
return false;
}
}
async validateConfiguration() {
if (!this.config) {
await this.loadConfiguration();
}
const validation = {
valid: true,
errors: [],
warnings: [],
suggestions: []
};
// Required fields validation
const requiredFields = [
'project.name',
'project.mak3r_version',
'environment.os',
'mak3r.config_version'
];
for (const field of requiredFields) {
if (!this.getNestedValue(this.config, field)) {
validation.errors.push(`Missing required field: ${field}`);
validation.valid = false;
}
}
// Port conflicts
const ports = Object.values(this.config.ports || {});
const uniquePorts = new Set(ports);
if (ports.length !== uniquePorts.size) {
validation.warnings.push('Port conflicts detected in configuration');
}
// Version compatibility
if (this.config.project.mak3r_version !== this.version) {
validation.warnings.push(`Configuration version mismatch: ${this.config.project.mak3r_version} vs ${this.version}`);
validation.suggestions.push('Update configuration: MAK3R-HUB config update');
}
return validation;
}
getNestedValue(obj, path) {
return path.split('.').reduce((current, key) => current && current[key], obj);
}
async resetConfiguration(type = 'default') {
const backupPath = path.join(this.configDir, 'backups', `config-backup-${Date.now()}.json`);
// Backup existing config
if (this.config) {
await fs.ensureDir(path.dirname(backupPath));
await fs.writeFile(backupPath, JSON.stringify(this.config, null, 2));
console.log(chalk.yellow(`📋 Configuration backed up to: ${backupPath}`));
}
// Create new configuration
this.config = await this.createCustomConfiguration(type);
console.log(chalk.green(`✅ Configuration reset to ${type} template`));
return this.config;
}
}
module.exports = ConfigManager;