@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
538 lines (537 loc) ⢠23 kB
JavaScript
;
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.manageWorkspaceDefinition = manageWorkspaceDefinition;
const chalk_1 = __importDefault(require("chalk"));
const prompts_1 = __importDefault(require("prompts"));
const path = __importStar(require("path"));
const fs = __importStar(require("fs-extra"));
const workspace_schema_1 = require("../utils/workspace-schema");
const error_handler_1 = require("../utils/error-handler");
const DEFAULT_WORKSPACE_FILE = 're-shell.workspaces.yaml';
async function manageWorkspaceDefinition(options = {}) {
const { spinner, verbose, json } = options;
try {
if (options.init) {
await initializeWorkspaceDefinition(options, spinner);
return;
}
if (options.validate) {
await validateWorkspaceDefinition(options, spinner);
return;
}
if (options.autoDetect) {
await autoDetectWorkspaces(options, spinner);
return;
}
if (options.structure) {
await validateWorkspaceStructure(options, spinner);
return;
}
if (options.fix) {
await fixWorkspaceDefinition(options, spinner);
return;
}
if (options.interactive) {
await interactiveWorkspaceManagement(options, spinner);
return;
}
// Default: show workspace definition status
await showWorkspaceDefinitionStatus(options, spinner);
}
catch (error) {
if (spinner)
spinner.fail(chalk_1.default.red('Workspace definition operation failed'));
throw error;
}
}
async function initializeWorkspaceDefinition(options, spinner) {
const outputFile = options.output || options.file || DEFAULT_WORKSPACE_FILE;
const outputPath = path.resolve(outputFile);
if (spinner)
spinner.setText(`Initializing workspace definition: ${outputFile}`);
// Check if file already exists
if (await fs.pathExists(outputPath) && !options.dryRun) {
if (spinner)
spinner.stop();
const response = await (0, prompts_1.default)([
{
type: 'confirm',
name: 'overwrite',
message: `Workspace definition already exists at ${outputFile}. Overwrite?`,
initial: false
}
]);
if (!response.overwrite) {
console.log(chalk_1.default.yellow('Initialization cancelled.'));
return;
}
}
try {
// Get project information
let projectName = path.basename(process.cwd());
let description = '';
if (!options.dryRun) {
if (spinner)
spinner.stop();
const response = await (0, prompts_1.default)([
{
type: 'text',
name: 'name',
message: 'Project name:',
initial: projectName,
validate: (value) => value.trim() ? true : 'Project name is required'
},
{
type: 'text',
name: 'description',
message: 'Project description (optional):',
}
]);
if (!response.name)
return;
projectName = response.name;
description = response.description || '';
}
// Create default workspace definition
const definition = (0, workspace_schema_1.createDefaultWorkspaceDefinition)(projectName, {
description: description || undefined
});
if (options.dryRun) {
if (spinner)
spinner.stop();
console.log(chalk_1.default.cyan('\\nš Workspace Definition Preview'));
console.log(chalk_1.default.gray('ā'.repeat(50)));
console.log(JSON.stringify(definition, null, 2));
return;
}
// Save the definition
await (0, workspace_schema_1.saveWorkspaceDefinition)(definition, outputPath);
if (spinner) {
spinner.succeed(chalk_1.default.green('Workspace definition initialized'));
}
console.log(chalk_1.default.green(`\\nā
Workspace definition created: ${outputFile}`));
console.log(chalk_1.default.cyan('\\nš Next steps:'));
console.log(` ⢠Run: re-shell workspace-def auto-detect --merge`);
console.log(` ⢠Edit: ${outputFile}`);
console.log(` ⢠Validate: re-shell workspace-def validate`);
}
catch (error) {
if (spinner)
spinner.fail(chalk_1.default.red('Failed to initialize workspace definition'));
throw error;
}
}
async function validateWorkspaceDefinition(options, spinner) {
const inputFile = options.file || DEFAULT_WORKSPACE_FILE;
const inputPath = path.resolve(inputFile);
if (spinner)
spinner.setText(`Validating workspace definition: ${inputFile}`);
try {
// Load and validate definition
const definition = await (0, workspace_schema_1.loadWorkspaceDefinition)(inputPath);
const validator = new workspace_schema_1.WorkspaceSchemaValidator(definition, path.dirname(inputPath));
const result = await validator.validateDefinition();
if (spinner)
spinner.stop();
if (options.json) {
console.log(JSON.stringify(result, null, 2));
return;
}
// Display results
displayValidationResults(result, inputFile, options.strict || false, options.ignoreWarnings || false);
if (!result.valid) {
process.exit(1);
}
}
catch (error) {
if (spinner)
spinner.fail(chalk_1.default.red('Validation failed'));
if (error instanceof error_handler_1.ValidationError) {
console.error(chalk_1.default.red(`ā ${error.message}`));
}
else {
console.error(chalk_1.default.red(`ā Unexpected error: ${error.message}`));
}
process.exit(1);
}
}
async function validateWorkspaceStructure(options, spinner) {
const inputFile = options.file || DEFAULT_WORKSPACE_FILE;
const inputPath = path.resolve(inputFile);
if (spinner)
spinner.setText(`Validating workspace structure: ${inputFile}`);
try {
const definition = await (0, workspace_schema_1.loadWorkspaceDefinition)(inputPath);
const validator = new workspace_schema_1.WorkspaceSchemaValidator(definition, path.dirname(inputPath));
const result = await validator.validateWorkspaceStructure();
if (spinner)
spinner.stop();
if (options.json) {
console.log(JSON.stringify(result, null, 2));
return;
}
console.log(chalk_1.default.cyan('\\nšļø Workspace Structure Validation'));
console.log(chalk_1.default.gray('ā'.repeat(60)));
displayValidationResults(result, inputFile, options.strict || false, options.ignoreWarnings || false);
if (!result.valid) {
process.exit(1);
}
}
catch (error) {
if (spinner)
spinner.fail(chalk_1.default.red('Structure validation failed'));
throw error;
}
}
async function autoDetectWorkspaces(options, spinner) {
const inputFile = options.file || DEFAULT_WORKSPACE_FILE;
const inputPath = path.resolve(inputFile);
if (spinner)
spinner.setText('Auto-detecting workspaces...');
try {
let definition;
// Load existing definition or create default
if (await fs.pathExists(inputPath)) {
definition = await (0, workspace_schema_1.loadWorkspaceDefinition)(inputPath);
}
else {
definition = (0, workspace_schema_1.createDefaultWorkspaceDefinition)(path.basename(process.cwd()));
}
const validator = new workspace_schema_1.WorkspaceSchemaValidator(definition, path.dirname(inputPath));
const detectedWorkspaces = await validator.autoDetectWorkspaces();
if (spinner)
spinner.stop();
if (detectedWorkspaces.length === 0) {
console.log(chalk_1.default.yellow('No workspaces detected based on current patterns and types.'));
console.log(chalk_1.default.gray('Consider updating workspace patterns or adding workspaces manually.'));
return;
}
console.log(chalk_1.default.cyan(`\\nš Auto-Detected Workspaces (${detectedWorkspaces.length})`));
console.log(chalk_1.default.gray('ā'.repeat(50)));
for (const workspace of detectedWorkspaces) {
const typeIcon = getWorkspaceTypeIcon(workspace.type);
console.log(`\\n${typeIcon} ${chalk_1.default.cyan(workspace.name)}`);
console.log(` Path: ${workspace.path}`);
console.log(` Type: ${workspace.type}`);
if (workspace.description) {
console.log(` Description: ${chalk_1.default.gray(workspace.description)}`);
}
if (workspace.tags && workspace.tags.length > 0) {
console.log(` Tags: ${workspace.tags.map(tag => chalk_1.default.blue(tag)).join(', ')}`);
}
}
if (options.dryRun) {
console.log(chalk_1.default.gray('\\n(Dry run - no changes made)'));
return;
}
// Merge with existing definition if requested
if (options.merge) {
const response = await (0, prompts_1.default)([
{
type: 'confirm',
name: 'merge',
message: `Merge ${detectedWorkspaces.length} detected workspaces with existing definition?`,
initial: true
}
]);
if (response.merge) {
// Add detected workspaces to definition
for (const workspace of detectedWorkspaces) {
definition.workspaces[workspace.name] = workspace;
}
await (0, workspace_schema_1.saveWorkspaceDefinition)(definition, inputPath);
console.log(chalk_1.default.green(`\\nā
Merged ${detectedWorkspaces.length} workspaces into ${inputFile}`));
}
}
else {
// Save as new file or replace
const outputFile = options.output || inputFile;
const newDefinition = {
...definition,
workspaces: Object.fromEntries(detectedWorkspaces.map(w => [w.name, w]))
};
await (0, workspace_schema_1.saveWorkspaceDefinition)(newDefinition, outputFile);
console.log(chalk_1.default.green(`\\nā
Saved detected workspaces to ${outputFile}`));
}
}
catch (error) {
if (spinner)
spinner.fail(chalk_1.default.red('Auto-detection failed'));
throw error;
}
}
async function fixWorkspaceDefinition(options, spinner) {
const inputFile = options.file || DEFAULT_WORKSPACE_FILE;
const inputPath = path.resolve(inputFile);
if (spinner)
spinner.setText(`Analyzing workspace definition for fixes: ${inputFile}`);
try {
const definition = await (0, workspace_schema_1.loadWorkspaceDefinition)(inputPath);
const validator = new workspace_schema_1.WorkspaceSchemaValidator(definition, path.dirname(inputPath));
const result = await validator.validateDefinition();
if (spinner)
spinner.stop();
if (result.valid && result.suggestions.length === 0) {
console.log(chalk_1.default.green('ā
No fixes needed - workspace definition is valid'));
return;
}
console.log(chalk_1.default.cyan('\\nš§ Available Fixes'));
console.log(chalk_1.default.gray('ā'.repeat(40)));
let hasApplicableFixes = false;
// Show suggestions that can be auto-fixed
for (const suggestion of result.suggestions) {
if (suggestion.fix) {
hasApplicableFixes = true;
console.log(`\\nš” ${suggestion.message}`);
console.log(` Path: ${chalk_1.default.gray(suggestion.path)}`);
console.log(` Fix: ${chalk_1.default.green(suggestion.fix)}`);
}
}
if (!hasApplicableFixes) {
console.log(chalk_1.default.yellow('No auto-fixable issues found.'));
console.log(chalk_1.default.gray('Manual fixes may be required - see validation output.'));
return;
}
if (options.dryRun) {
console.log(chalk_1.default.gray('\\n(Dry run - no changes would be made)'));
return;
}
const response = await (0, prompts_1.default)([
{
type: 'confirm',
name: 'apply',
message: 'Apply suggested fixes?',
initial: true
}
]);
if (response.apply) {
// TODO: Implement actual fix application
console.log(chalk_1.default.yellow('\\nā ļø Auto-fix implementation coming in next update'));
console.log(chalk_1.default.gray('For now, please apply fixes manually based on suggestions above.'));
}
}
catch (error) {
if (spinner)
spinner.fail(chalk_1.default.red('Fix analysis failed'));
throw error;
}
}
async function showWorkspaceDefinitionStatus(options, spinner) {
const inputFile = options.file || DEFAULT_WORKSPACE_FILE;
const inputPath = path.resolve(inputFile);
if (spinner)
spinner.setText('Checking workspace definition status...');
try {
if (!(await fs.pathExists(inputPath))) {
if (spinner)
spinner.stop();
console.log(chalk_1.default.yellow('\\nā ļø No workspace definition found'));
console.log(chalk_1.default.gray(`Expected: ${inputFile}`));
console.log(chalk_1.default.cyan('\\nš Quick start:'));
console.log(' re-shell workspace-def init');
console.log(' re-shell workspace-def auto-detect --merge');
return;
}
const definition = await (0, workspace_schema_1.loadWorkspaceDefinition)(inputPath);
const validator = new workspace_schema_1.WorkspaceSchemaValidator(definition, path.dirname(inputPath));
const [defResult, structResult] = await Promise.all([
validator.validateDefinition(),
validator.validateWorkspaceStructure()
]);
if (spinner)
spinner.stop();
if (options.json) {
console.log(JSON.stringify({
file: inputFile,
definition: defResult,
structure: structResult,
workspaces: Object.keys(definition.workspaces).length
}, null, 2));
return;
}
console.log(chalk_1.default.cyan('\\nš Workspace Definition Status'));
console.log(chalk_1.default.gray('ā'.repeat(50)));
console.log(`\\nFile: ${chalk_1.default.cyan(inputFile)}`);
console.log(`Version: ${definition.version}`);
console.log(`Name: ${definition.name}`);
if (definition.description) {
console.log(`Description: ${chalk_1.default.gray(definition.description)}`);
}
console.log(`\\nWorkspaces: ${Object.keys(definition.workspaces).length}`);
console.log(`Types: ${Object.keys(definition.types).length}`);
console.log(`Patterns: ${definition.patterns.length}`);
// Definition validation status
const defIcon = defResult.valid ? 'ā
' : 'ā';
const defStatus = defResult.valid ? chalk_1.default.green('Valid') : chalk_1.default.red('Invalid');
console.log(`\\nDefinition: ${defIcon} ${defStatus}`);
if (defResult.errors.length > 0) {
console.log(` Errors: ${chalk_1.default.red(defResult.errors.length)}`);
}
if (defResult.warnings.length > 0) {
console.log(` Warnings: ${chalk_1.default.yellow(defResult.warnings.length)}`);
}
// Structure validation status
const structIcon = structResult.valid ? 'ā
' : 'ā';
const structStatus = structResult.valid ? chalk_1.default.green('Valid') : chalk_1.default.red('Invalid');
console.log(`Structure: ${structIcon} ${structStatus}`);
if (structResult.errors.length > 0) {
console.log(` Errors: ${chalk_1.default.red(structResult.errors.length)}`);
}
if (structResult.warnings.length > 0) {
console.log(` Warnings: ${chalk_1.default.yellow(structResult.warnings.length)}`);
}
console.log(chalk_1.default.cyan('\\nš ļø Available Commands:'));
console.log(' ⢠re-shell workspace-def validate');
console.log(' ⢠re-shell workspace-def structure');
console.log(' ⢠re-shell workspace-def auto-detect');
console.log(' ⢠re-shell workspace-def interactive');
}
catch (error) {
if (spinner)
spinner.fail(chalk_1.default.red('Status check failed'));
throw error;
}
}
async function interactiveWorkspaceManagement(options, spinner) {
if (spinner)
spinner.stop();
const inputFile = options.file || DEFAULT_WORKSPACE_FILE;
const inputPath = path.resolve(inputFile);
const exists = await fs.pathExists(inputPath);
const response = await (0, prompts_1.default)([
{
type: 'select',
name: 'action',
message: 'What would you like to do?',
choices: [
...(!exists ? [{ title: 'š Initialize workspace definition', value: 'init' }] : []),
...(exists ? [
{ title: 'ā
Validate definition', value: 'validate' },
{ title: 'šļø Validate structure', value: 'structure' },
] : []),
{ title: 'š Auto-detect workspaces', value: 'auto-detect' },
...(exists ? [
{ title: 'š§ Fix issues', value: 'fix' },
{ title: 'š Show status', value: 'status' }
] : [])
]
}
]);
if (!response.action)
return;
switch (response.action) {
case 'init':
await initializeWorkspaceDefinition({ ...options, interactive: false });
break;
case 'validate':
await validateWorkspaceDefinition({ ...options, interactive: false });
break;
case 'structure':
await validateWorkspaceStructure({ ...options, interactive: false });
break;
case 'auto-detect':
await autoDetectWorkspaces({ ...options, interactive: false });
break;
case 'fix':
await fixWorkspaceDefinition({ ...options, interactive: false });
break;
case 'status':
await showWorkspaceDefinitionStatus({ ...options, interactive: false });
break;
}
}
// Utility functions
function displayValidationResults(result, fileName, strict, ignoreWarnings) {
const hasIssues = result.errors.length > 0 || (!ignoreWarnings && result.warnings.length > 0);
if (result.valid && !hasIssues) {
console.log(chalk_1.default.green(`\\nā
${fileName} is valid`));
if (result.suggestions.length > 0) {
console.log(chalk_1.default.cyan(`\\nš” Suggestions (${result.suggestions.length}):`));
for (const suggestion of result.suggestions) {
console.log(` ⢠${suggestion.message}`);
if (suggestion.fix) {
console.log(` ${chalk_1.default.green(suggestion.fix)}`);
}
}
}
return;
}
// Show errors
if (result.errors.length > 0) {
console.log(chalk_1.default.red(`\\nā Errors (${result.errors.length}):`));
for (const error of result.errors) {
console.log(` ⢠${error.message}`);
}
}
// Show warnings
if (result.warnings.length > 0 && !ignoreWarnings) {
console.log(chalk_1.default.yellow(`\\nā ļø Warnings (${result.warnings.length}):`));
for (const warning of result.warnings) {
const severityIcon = warning.severity === 'high' ? 'š“' : warning.severity === 'medium' ? 'š”' : 'šµ';
console.log(` ${severityIcon} ${warning.message}`);
if (warning.path) {
console.log(` Path: ${chalk_1.default.gray(warning.path)}`);
}
}
}
// Show suggestions
if (result.suggestions.length > 0) {
console.log(chalk_1.default.cyan(`\\nš” Suggestions (${result.suggestions.length}):`));
for (const suggestion of result.suggestions) {
console.log(` ⢠${suggestion.message}`);
if (suggestion.fix) {
console.log(` ${chalk_1.default.green(suggestion.fix)}`);
}
}
}
if (strict && result.warnings.length > 0) {
console.log(chalk_1.default.red('\\nā Validation failed (strict mode enabled)'));
}
}
function getWorkspaceTypeIcon(type) {
const icons = {
app: 'š±',
package: 'š¦',
lib: 'š',
tool: 'š§',
service: 'āļø',
website: 'š'
};
return icons[type] || 'š';
}