UNPKG

@re-shell/cli

Version:

Full-stack development platform uniting microservices and microfrontends. Build complete applications with .NET (ASP.NET Core Web API, Minimal API), Java (Spring Boot, Quarkus, Micronaut, Vert.x), Rust (Actix-Web, Warp, Rocket, Axum), Python (FastAPI, Dja

647 lines (646 loc) • 26.8 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.manageWorkspaceConflict = manageWorkspaceConflict; const chalk_1 = __importDefault(require("chalk")); const prompts_1 = __importDefault(require("prompts")); const fs = __importStar(require("fs-extra")); const workspace_conflict_1 = require("../utils/workspace-conflict"); const error_handler_1 = require("../utils/error-handler"); const DEFAULT_WORKSPACE_FILE = 're-shell.workspaces.yaml'; async function manageWorkspaceConflict(options = {}) { const { spinner, verbose, json } = options; try { if (options.detect) { await detectConflicts(options, spinner); return; } if (options.resolve) { await resolveConflicts(options, spinner); return; } if (options.preview) { await previewResolution(options, spinner); return; } if (options.autoResolve) { await autoResolveAllConflicts(options, spinner); return; } if (options.interactive) { await interactiveConflictManagement(options, spinner); return; } // Default: detect conflicts await detectConflicts(options, spinner); } catch (error) { if (spinner) spinner.fail(chalk_1.default.red('Conflict management failed')); throw error; } } async function detectConflicts(options, spinner) { const workspaceFile = options.workspaceFile || DEFAULT_WORKSPACE_FILE; if (!(await fs.pathExists(workspaceFile))) { throw new error_handler_1.ValidationError(`Workspace file not found: ${workspaceFile}`); } if (spinner) spinner.setText('Detecting workspace conflicts...'); try { const detectionOptions = { includeWarnings: options.includeWarnings ?? true, checkDependencies: options.checkDependencies ?? true, checkPorts: options.checkPorts ?? true, checkPaths: options.checkPaths ?? true, checkTypes: options.checkTypes ?? true, enableResolution: true }; const conflicts = await (0, workspace_conflict_1.detectWorkspaceConflicts)(workspaceFile, detectionOptions); if (spinner) spinner.stop(); if (options.json) { console.log(JSON.stringify(conflicts, null, 2)); return; } if (conflicts.length === 0) { console.log(chalk_1.default.green('\\nāœ… No conflicts detected!')); console.log(chalk_1.default.gray('Your workspace definition is conflict-free.')); return; } console.log(chalk_1.default.cyan('\\nšŸ” Workspace Conflict Analysis')); console.log(chalk_1.default.gray('═'.repeat(50))); const errorCount = conflicts.filter(c => c.severity === 'error').length; const warningCount = conflicts.filter(c => c.severity === 'warning').length; const infoCount = conflicts.filter(c => c.severity === 'info').length; console.log(`Found ${chalk_1.default.red(errorCount)} errors, ${chalk_1.default.yellow(warningCount)} warnings, ${chalk_1.default.blue(infoCount)} info`); if (options.groupBy === 'type') { displayConflictsByType(conflicts, options); } else if (options.groupBy === 'severity') { displayConflictsBySeverity(conflicts, options); } else if (options.groupBy === 'workspace') { displayConflictsByWorkspace(conflicts, options); } else { displayConflictsList(conflicts, options); } if (errorCount > 0) { console.log(chalk_1.default.cyan('\\nšŸ› ļø Resolution Commands:')); console.log(' • Auto-resolve: re-shell workspace-conflict auto-resolve'); console.log(' • Interactive: re-shell workspace-conflict interactive'); console.log(' • Manual resolve: re-shell workspace-conflict resolve --conflict-id <id>'); } } catch (error) { if (spinner) spinner.fail(chalk_1.default.red('Failed to detect conflicts')); throw error; } } async function resolveConflicts(options, spinner) { const workspaceFile = options.workspaceFile || DEFAULT_WORKSPACE_FILE; if (!options.conflictId) { throw new error_handler_1.ValidationError('Conflict ID is required for manual resolution'); } if (spinner) spinner.setText('Resolving workspace conflicts...'); try { const manager = await (0, workspace_conflict_1.createWorkspaceConflictManager)(); const definition = await manager['loadWorkspaceDefinition'](workspaceFile); const conflicts = await manager.detectConflicts(definition); const conflict = conflicts.find(c => c.id === options.conflictId); if (!conflict) { throw new error_handler_1.ValidationError(`Conflict not found: ${options.conflictId}`); } let resolutionId = options.resolutionId; // If no resolution specified, prompt user if (!resolutionId && !options.force) { if (spinner) spinner.stop(); const response = await (0, prompts_1.default)([ { type: 'select', name: 'resolution', message: `Choose resolution for: ${conflict.description}`, choices: conflict.suggestions.map(r => ({ title: `${r.description} (${r.riskLevel} risk)`, value: r.id, description: r.preview })) } ]); if (!response.resolution) return; resolutionId = response.resolution; } else if (!resolutionId) { // Auto-select first automatic resolution const autoResolution = conflict.suggestions.find(r => r.automatic); if (autoResolution) { resolutionId = autoResolution.id; } else { throw new error_handler_1.ValidationError('No automatic resolution available. Please specify --resolution-id'); } } if (spinner) spinner.setText('Applying resolution...'); const result = await manager.resolveConflicts(definition, [conflict], true); await manager['saveWorkspaceDefinition'](workspaceFile, definition); if (spinner) spinner.stop(); if (options.json) { console.log(JSON.stringify(result, null, 2)); return; } if (result.resolved.length > 0) { console.log(chalk_1.default.green('\\nāœ… Conflict resolved successfully!')); console.log(chalk_1.default.cyan('\\nšŸ“ Changes made:')); for (const change of result.changes) { console.log(` • ${change.target}.${change.property}: ${chalk_1.default.red(String(change.oldValue))} → ${chalk_1.default.green(String(change.newValue))}`); console.log(` ${chalk_1.default.gray(change.reason)}`); } } else { console.log(chalk_1.default.red('\\nāŒ Failed to resolve conflict')); if (result.warnings.length > 0) { console.log(chalk_1.default.yellow('\\nWarnings:')); for (const warning of result.warnings) { console.log(` āš ļø ${warning}`); } } } } catch (error) { if (spinner) spinner.fail(chalk_1.default.red('Failed to resolve conflict')); throw error; } } async function previewResolution(options, spinner) { const workspaceFile = options.workspaceFile || DEFAULT_WORKSPACE_FILE; if (!options.conflictId || !options.resolutionId) { throw new error_handler_1.ValidationError('Both conflict ID and resolution ID are required for preview'); } if (spinner) spinner.setText('Previewing resolution...'); try { const manager = await (0, workspace_conflict_1.createWorkspaceConflictManager)(); const definition = await manager['loadWorkspaceDefinition'](workspaceFile); const conflicts = await manager.detectConflicts(definition); const conflict = conflicts.find(c => c.id === options.conflictId); if (!conflict) { throw new error_handler_1.ValidationError(`Conflict not found: ${options.conflictId}`); } const preview = await manager.previewResolution(definition, conflict, options.resolutionId); if (spinner) spinner.stop(); if (options.json) { console.log(JSON.stringify(preview, null, 2)); return; } console.log(chalk_1.default.cyan('\\nšŸ” Resolution Preview')); console.log(chalk_1.default.gray('═'.repeat(50))); console.log(`Conflict: ${chalk_1.default.yellow(conflict.description)}`); console.log(`Resolution: ${chalk_1.default.blue(conflict.suggestions.find(r => r.id === options.resolutionId)?.description)}`); if (preview.success) { console.log(chalk_1.default.green('\\nāœ… Preview successful')); console.log(chalk_1.default.cyan('\\nšŸ“ Proposed changes:')); for (const change of preview.changes) { console.log(` • ${change.target}.${change.property}: ${chalk_1.default.red(String(change.oldValue))} → ${chalk_1.default.green(String(change.newValue))}`); console.log(` ${chalk_1.default.gray(change.reason)}`); } } else { console.log(chalk_1.default.red('\\nāŒ Preview failed')); if (preview.warnings.length > 0) { console.log(chalk_1.default.yellow('\\nWarnings:')); for (const warning of preview.warnings) { console.log(` āš ļø ${warning}`); } } } console.log(chalk_1.default.cyan('\\nšŸš€ Apply resolution:')); console.log(` re-shell workspace-conflict resolve --conflict-id ${options.conflictId} --resolution-id ${options.resolutionId}`); } catch (error) { if (spinner) spinner.fail(chalk_1.default.red('Failed to preview resolution')); throw error; } } async function autoResolveAllConflicts(options, spinner) { const workspaceFile = options.workspaceFile || DEFAULT_WORKSPACE_FILE; if (spinner) spinner.setText('Auto-resolving all conflicts...'); try { const result = await (0, workspace_conflict_1.autoResolveConflicts)(workspaceFile); if (spinner) spinner.stop(); if (options.json) { console.log(JSON.stringify(result, null, 2)); return; } console.log(chalk_1.default.cyan('\\nšŸ¤– Auto-Resolution Results')); console.log(chalk_1.default.gray('═'.repeat(50))); console.log(`Resolved: ${chalk_1.default.green(result.resolved.length)} conflicts`); console.log(`Unresolved: ${chalk_1.default.red(result.unresolved.length)} conflicts`); if (result.resolved.length > 0) { console.log(chalk_1.default.cyan('\\nāœ… Resolved conflicts:')); for (const conflict of result.resolved) { console.log(` • ${conflict.description}`); } console.log(chalk_1.default.cyan('\\nšŸ“ Changes made:')); for (const change of result.changes) { console.log(` • ${change.target}.${change.property}: ${chalk_1.default.red(String(change.oldValue))} → ${chalk_1.default.green(String(change.newValue))}`); } } if (result.unresolved.length > 0) { console.log(chalk_1.default.yellow('\\nāš ļø Unresolved conflicts (require manual intervention):')); for (const conflict of result.unresolved) { console.log(` • ${conflict.description}`); } console.log(chalk_1.default.cyan('\\nšŸ› ļø Manual resolution:')); console.log(' re-shell workspace-conflict interactive'); } if (result.warnings.length > 0) { console.log(chalk_1.default.yellow('\\nāš ļø Warnings:')); for (const warning of result.warnings) { console.log(` ${warning}`); } } } catch (error) { if (spinner) spinner.fail(chalk_1.default.red('Auto-resolution failed')); throw error; } } async function interactiveConflictManagement(options, spinner) { if (spinner) spinner.stop(); const response = await (0, prompts_1.default)([ { type: 'select', name: 'action', message: 'What would you like to do?', choices: [ { title: 'šŸ” Detect conflicts', value: 'detect' }, { title: 'šŸ¤– Auto-resolve all conflicts', value: 'auto-resolve' }, { title: 'šŸ› ļø Manual conflict resolution', value: 'manual' }, { title: 'šŸ‘€ Preview resolution', value: 'preview' }, { title: 'šŸ“Š Conflict analysis', value: 'analysis' } ] } ]); if (!response.action) return; switch (response.action) { case 'detect': await detectConflictsInteractive(options); break; case 'auto-resolve': await autoResolveAllConflicts({ ...options, interactive: false }); break; case 'manual': await manualResolutionInteractive(options); break; case 'preview': await previewResolutionInteractive(options); break; case 'analysis': await conflictAnalysisInteractive(options); break; } } async function detectConflictsInteractive(options) { const response = await (0, prompts_1.default)([ { type: 'text', name: 'workspaceFile', message: 'Workspace file:', initial: 're-shell.workspaces.yaml' }, { type: 'multiselect', name: 'checks', message: 'Select checks to perform:', choices: [ { title: 'Dependencies', value: 'dependencies', selected: true }, { title: 'Ports', value: 'ports', selected: true }, { title: 'Paths', value: 'paths', selected: true }, { title: 'Types', value: 'types', selected: true } ] }, { type: 'confirm', name: 'includeWarnings', message: 'Include warnings?', initial: true }, { type: 'select', name: 'groupBy', message: 'Group results by:', choices: [ { title: 'Conflict type', value: 'type' }, { title: 'Severity', value: 'severity' }, { title: 'Workspace', value: 'workspace' }, { title: 'None (list)', value: 'none' } ] } ]); if (!response.workspaceFile) return; await detectConflicts({ ...options, ...response, checkDependencies: response.checks.includes('dependencies'), checkPorts: response.checks.includes('ports'), checkPaths: response.checks.includes('paths'), checkTypes: response.checks.includes('types'), groupBy: response.groupBy === 'none' ? undefined : response.groupBy, interactive: false }); } async function manualResolutionInteractive(options) { const workspaceFile = options.workspaceFile || DEFAULT_WORKSPACE_FILE; // First detect conflicts const conflicts = await (0, workspace_conflict_1.detectWorkspaceConflicts)(workspaceFile); if (conflicts.length === 0) { console.log(chalk_1.default.green('\\nāœ… No conflicts to resolve!')); return; } const response = await (0, prompts_1.default)([ { type: 'select', name: 'conflictId', message: 'Select conflict to resolve:', choices: conflicts.map(c => ({ title: `${getSeverityIcon(c.severity)} ${c.description}`, value: c.id, description: c.details })) } ]); if (!response.conflictId) return; const conflict = conflicts.find(c => c.id === response.conflictId); if (!conflict) return; const resolutionResponse = await (0, prompts_1.default)([ { type: 'select', name: 'resolutionId', message: 'Choose resolution:', choices: conflict.suggestions.map(r => ({ title: `${r.description} (${r.riskLevel} risk)`, value: r.id, description: r.preview })) }, { type: 'confirm', name: 'preview', message: 'Preview changes before applying?', initial: true } ]); if (!resolutionResponse.resolutionId) return; if (resolutionResponse.preview) { await previewResolution({ ...options, conflictId: response.conflictId, resolutionId: resolutionResponse.resolutionId, interactive: false }); const confirmResponse = await (0, prompts_1.default)([ { type: 'confirm', name: 'apply', message: 'Apply this resolution?', initial: false } ]); if (!confirmResponse.apply) return; } await resolveConflicts({ ...options, conflictId: response.conflictId, resolutionId: resolutionResponse.resolutionId, interactive: false }); } async function previewResolutionInteractive(options) { const workspaceFile = options.workspaceFile || DEFAULT_WORKSPACE_FILE; const conflicts = await (0, workspace_conflict_1.detectWorkspaceConflicts)(workspaceFile); if (conflicts.length === 0) { console.log(chalk_1.default.green('\\nāœ… No conflicts to preview!')); return; } const response = await (0, prompts_1.default)([ { type: 'select', name: 'conflictId', message: 'Select conflict:', choices: conflicts.map(c => ({ title: `${getSeverityIcon(c.severity)} ${c.description}`, value: c.id })) } ]); if (!response.conflictId) return; const conflict = conflicts.find(c => c.id === response.conflictId); if (!conflict) return; const resolutionResponse = await (0, prompts_1.default)([ { type: 'select', name: 'resolutionId', message: 'Select resolution to preview:', choices: conflict.suggestions.map(r => ({ title: r.description, value: r.id })) } ]); if (!resolutionResponse.resolutionId) return; await previewResolution({ ...options, conflictId: response.conflictId, resolutionId: resolutionResponse.resolutionId, interactive: false }); } async function conflictAnalysisInteractive(options) { const workspaceFile = options.workspaceFile || DEFAULT_WORKSPACE_FILE; const conflicts = await (0, workspace_conflict_1.detectWorkspaceConflicts)(workspaceFile); console.log(chalk_1.default.cyan('\\nšŸ“Š Conflict Analysis Dashboard')); console.log(chalk_1.default.gray('═'.repeat(50))); if (conflicts.length === 0) { console.log(chalk_1.default.green('āœ… No conflicts detected - workspace is healthy!')); return; } // Analysis by severity const severityStats = { error: conflicts.filter(c => c.severity === 'error').length, warning: conflicts.filter(c => c.severity === 'warning').length, info: conflicts.filter(c => c.severity === 'info').length }; console.log(chalk_1.default.cyan('\\nBy Severity:')); console.log(` ${chalk_1.default.red('ā—')} Errors: ${severityStats.error}`); console.log(` ${chalk_1.default.yellow('ā—')} Warnings: ${severityStats.warning}`); console.log(` ${chalk_1.default.blue('ā—')} Info: ${severityStats.info}`); // Analysis by type const typeStats = {}; for (const conflict of conflicts) { typeStats[conflict.type] = (typeStats[conflict.type] || 0) + 1; } console.log(chalk_1.default.cyan('\\nBy Type:')); for (const [type, count] of Object.entries(typeStats)) { console.log(` • ${type}: ${count}`); } // Most affected workspaces const workspaceStats = {}; for (const conflict of conflicts) { for (const workspace of conflict.affectedWorkspaces) { workspaceStats[workspace] = (workspaceStats[workspace] || 0) + 1; } } const topAffected = Object.entries(workspaceStats) .sort(([, a], [, b]) => b - a) .slice(0, 5); if (topAffected.length > 0) { console.log(chalk_1.default.cyan('\\nMost Affected Workspaces:')); for (const [workspace, count] of topAffected) { console.log(` • ${workspace}: ${count} conflicts`); } } // Automatic resolution potential const autoResolvable = conflicts.filter(c => c.suggestions.some(s => s.automatic && s.riskLevel === 'low')).length; console.log(chalk_1.default.cyan('\\nResolution Summary:')); console.log(` • Auto-resolvable (low risk): ${chalk_1.default.green(autoResolvable)}`); console.log(` • Requires manual intervention: ${chalk_1.default.yellow(conflicts.length - autoResolvable)}`); if (autoResolvable > 0) { console.log(chalk_1.default.cyan('\\nšŸ¤– Quick fix:')); console.log(' re-shell workspace-conflict auto-resolve'); } } // Display helper functions function displayConflictsList(conflicts, options) { console.log(chalk_1.default.cyan('\\nšŸ“‹ Conflicts:')); for (let i = 0; i < conflicts.length; i++) { const conflict = conflicts[i]; const icon = getSeverityIcon(conflict.severity); console.log(`\\n${i + 1}. ${icon} ${chalk_1.default.bold(conflict.description)}`); console.log(` ID: ${chalk_1.default.gray(conflict.id)}`); console.log(` Type: ${chalk_1.default.blue(conflict.type)}`); console.log(` Affected: ${conflict.affectedWorkspaces.join(', ')}`); if (options.verbose) { console.log(` Details: ${chalk_1.default.gray(conflict.details)}`); console.log(` Resolutions: ${conflict.suggestions.length} available`); } } } function displayConflictsByType(conflicts, options) { const byType = {}; for (const conflict of conflicts) { if (!byType[conflict.type]) { byType[conflict.type] = []; } byType[conflict.type].push(conflict); } for (const [type, typeConflicts] of Object.entries(byType)) { console.log(chalk_1.default.cyan(`\\nšŸ“‚ ${type.toUpperCase()} (${typeConflicts.length})`)); for (const conflict of typeConflicts) { const icon = getSeverityIcon(conflict.severity); console.log(` ${icon} ${conflict.description}`); if (options.verbose) { console.log(` ${chalk_1.default.gray(conflict.details)}`); } } } } function displayConflictsBySeverity(conflicts, options) { const severityOrder = ['error', 'warning', 'info']; for (const severity of severityOrder) { const severityConflicts = conflicts.filter(c => c.severity === severity); if (severityConflicts.length === 0) continue; const icon = getSeverityIcon(severity); console.log(chalk_1.default.cyan(`\\n${icon} ${severity.toUpperCase()} (${severityConflicts.length})`)); for (const conflict of severityConflicts) { console.log(` • ${conflict.description}`); if (options.verbose) { console.log(` ${chalk_1.default.gray(conflict.details)}`); } } } } function displayConflictsByWorkspace(conflicts, options) { const byWorkspace = {}; for (const conflict of conflicts) { for (const workspace of conflict.affectedWorkspaces) { if (!byWorkspace[workspace]) { byWorkspace[workspace] = []; } byWorkspace[workspace].push(conflict); } } for (const [workspace, workspaceConflicts] of Object.entries(byWorkspace)) { console.log(chalk_1.default.cyan(`\\nšŸ—ļø ${workspace} (${workspaceConflicts.length})`)); for (const conflict of workspaceConflicts) { const icon = getSeverityIcon(conflict.severity); console.log(` ${icon} ${conflict.description}`); } } } function getSeverityIcon(severity) { switch (severity) { case 'error': return 'āŒ'; case 'warning': return 'āš ļø'; case 'info': return 'ā„¹ļø'; default: return '•'; } }