@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
590 lines (589 loc) ⢠23.1 kB
JavaScript
"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.manageWorkspaceTemplate = manageWorkspaceTemplate;
const chalk_1 = __importDefault(require("chalk"));
const prompts_1 = __importDefault(require("prompts"));
const path = __importStar(require("path"));
const fs = __importStar(require("fs-extra"));
const yaml = __importStar(require("yaml"));
const workspace_template_1 = require("../utils/workspace-template");
const workspace_schema_1 = require("../utils/workspace-schema");
const spinner_1 = require("../utils/spinner");
const error_handler_1 = require("../utils/error-handler");
const DEFAULT_WORKSPACE_FILE = 're-shell.workspaces.yaml';
async function manageWorkspaceTemplate(options = {}) {
const { spinner, verbose, json } = options;
try {
if (options.list) {
await listTemplates(options, spinner);
return;
}
if (options.create) {
await createTemplateInteractive(options, spinner);
return;
}
if (options.apply) {
await applyTemplate(options, spinner);
return;
}
if (options.show) {
await showTemplate(options, spinner);
return;
}
if (options.delete) {
await deleteTemplate(options, spinner);
return;
}
if (options.export) {
await exportTemplate(options, spinner);
return;
}
if (options.interactive) {
await interactiveTemplateManagement(options, spinner);
return;
}
// Default: list templates
await listTemplates(options, spinner);
}
catch (error) {
if (spinner)
spinner.fail(chalk_1.default.red('Template operation failed'));
throw error;
}
}
async function listTemplates(options, spinner) {
if (spinner)
spinner.setText('Loading templates...');
try {
const manager = await (0, workspace_template_1.createWorkspaceTemplateManager)();
const templates = await manager.listTemplates();
if (spinner)
spinner.stop();
if (options.json) {
console.log(JSON.stringify(templates, null, 2));
return;
}
if (templates.length === 0) {
console.log(chalk_1.default.yellow('\nā ļø No templates found'));
console.log(chalk_1.default.gray('Create one with: re-shell workspace-template create'));
return;
}
console.log(chalk_1.default.cyan('\nš Available Workspace Templates'));
console.log(chalk_1.default.gray('ā'.repeat(50)));
for (const template of templates) {
console.log(`\n${chalk_1.default.bold(template.name)} v${template.version}`);
if (template.description) {
console.log(` ${chalk_1.default.gray(template.description)}`);
}
if (template.extends) {
console.log(` ${chalk_1.default.yellow('Extends:')} ${template.extends}`);
}
if (template.variables && template.variables.length > 0) {
console.log(` ${chalk_1.default.blue('Variables:')} ${template.variables.map(v => v.name).join(', ')}`);
}
if (options.verbose) {
if (template.patterns && template.patterns.length > 0) {
console.log(` ${chalk_1.default.green('Patterns:')} ${template.patterns.join(', ')}`);
}
if (template.scripts && Object.keys(template.scripts).length > 0) {
console.log(` ${chalk_1.default.magenta('Scripts:')} ${Object.keys(template.scripts).join(', ')}`);
}
}
}
console.log(chalk_1.default.cyan('\nš ļø Commands:'));
console.log(' ⢠re-shell workspace-template show <name>');
console.log(' ⢠re-shell workspace-template apply <name>');
console.log(' ⢠re-shell workspace-template create');
}
catch (error) {
if (spinner)
spinner.fail(chalk_1.default.red('Failed to load templates'));
throw error;
}
}
async function createTemplateInteractive(options, spinner) {
if (spinner)
spinner.stop();
console.log(chalk_1.default.cyan('\nšØ Create Workspace Template'));
console.log(chalk_1.default.gray('ā'.repeat(50)));
const response = await (0, prompts_1.default)([
{
type: 'text',
name: 'name',
message: 'Template name:',
validate: value => value.trim() ? true : 'Name is required'
},
{
type: 'text',
name: 'description',
message: 'Description (optional):'
},
{
type: 'text',
name: 'version',
message: 'Version:',
initial: '1.0.0'
},
{
type: 'text',
name: 'extends',
message: 'Extends template (optional):'
},
{
type: 'confirm',
name: 'addVariables',
message: 'Add template variables?',
initial: true
}
]);
if (!response.name)
return;
const template = {
name: response.name,
version: response.version,
description: response.description || undefined,
extends: response.extends || undefined,
variables: []
};
// Add variables
if (response.addVariables) {
while (true) {
const varResponse = await (0, prompts_1.default)([
{
type: 'text',
name: 'name',
message: 'Variable name (empty to finish):'
},
{
type: prev => prev ? 'select' : null,
name: 'type',
message: 'Variable type:',
choices: [
{ title: 'String', value: 'string' },
{ title: 'Number', value: 'number' },
{ title: 'Boolean', value: 'boolean' },
{ title: 'Array', value: 'array' },
{ title: 'Object', value: 'object' }
]
},
{
type: prev => prev ? 'text' : null,
name: 'description',
message: 'Description (optional):'
},
{
type: prev => prev ? 'confirm' : null,
name: 'required',
message: 'Required?',
initial: false
},
{
type: (prev, values) => values.type === 'string' || values.type === 'number' ? 'text' : null,
name: 'default',
message: 'Default value (optional):'
}
]);
if (!varResponse.name)
break;
const variable = {
name: varResponse.name,
type: varResponse.type,
description: varResponse.description || undefined,
required: varResponse.required
};
if (varResponse.default) {
variable.default = varResponse.type === 'number'
? Number(varResponse.default)
: varResponse.default;
}
template.variables.push(variable);
}
}
// Add template content
const contentResponse = await (0, prompts_1.default)([
{
type: 'confirm',
name: 'addPatterns',
message: 'Add workspace patterns?',
initial: false
},
{
type: prev => prev ? 'list' : null,
name: 'patterns',
message: 'Patterns (comma-separated):',
separator: ','
},
{
type: 'confirm',
name: 'addScripts',
message: 'Add default scripts?',
initial: false
}
]);
if (contentResponse.patterns) {
template.patterns = contentResponse.patterns.map((p) => p.trim());
}
if (contentResponse.addScripts) {
template.scripts = {};
const commonScripts = ['dev', 'build', 'test', 'lint'];
for (const scriptName of commonScripts) {
const scriptResponse = await (0, prompts_1.default)({
type: 'text',
name: 'command',
message: `${scriptName} script (optional):`
});
if (scriptResponse.command) {
template.scripts[scriptName] = scriptResponse.command;
}
}
}
// Save template
spinner = (0, spinner_1.createSpinner)('Creating template...').start();
try {
const manager = await (0, workspace_template_1.createWorkspaceTemplateManager)();
await manager.createTemplate(template);
if (spinner)
spinner.succeed(chalk_1.default.green(`Template '${template.name}' created successfully!`));
// Show next steps
console.log(chalk_1.default.cyan('\nš Next steps:'));
console.log(` ⢠Apply template: re-shell workspace-template apply ${template.name}`);
console.log(` ⢠View template: re-shell workspace-template show ${template.name}`);
}
catch (error) {
if (spinner)
spinner.fail(chalk_1.default.red('Failed to create template'));
throw error;
}
}
async function applyTemplate(options, spinner) {
if (!options.template) {
throw new error_handler_1.ValidationError('Template name is required');
}
if (spinner)
spinner.setText(`Loading template: ${options.template}`);
try {
const manager = await (0, workspace_template_1.createWorkspaceTemplateManager)();
const template = await manager.getTemplate(options.template);
if (!template) {
throw new error_handler_1.ValidationError(`Template '${options.template}' not found`);
}
if (spinner)
spinner.stop();
// Collect variables
const variables = {};
// Load from file if provided
if (options.varsFile) {
const varsPath = path.resolve(options.varsFile);
if (await fs.pathExists(varsPath)) {
const content = await fs.readFile(varsPath, 'utf8');
Object.assign(variables, yaml.parse(content));
}
}
// Parse command line variables
if (options.variables) {
try {
const parsed = JSON.parse(options.variables);
Object.assign(variables, parsed);
}
catch (error) {
throw new error_handler_1.ValidationError('Invalid variables JSON format');
}
}
// Prompt for missing required variables
if (template.variables) {
for (const varDef of template.variables) {
if (varDef.required && !(varDef.name in variables)) {
const response = await (0, prompts_1.default)({
type: varDef.type === 'number' ? 'number' :
varDef.type === 'boolean' ? 'confirm' : 'text',
name: 'value',
message: `${varDef.name}${varDef.description ? ` (${varDef.description})` : ''}:`,
initial: varDef.default
});
if (response.value !== undefined) {
variables[varDef.name] = response.value;
}
}
}
}
// Apply template
if (spinner)
spinner = (0, spinner_1.createSpinner)('Applying template...').start();
const context = { variables };
const result = await manager.applyTemplate(options.template, context);
if (spinner)
spinner.stop();
if (options.output) {
// Save to file
const outputPath = path.resolve(options.output);
await fs.ensureDir(path.dirname(outputPath));
await fs.writeFile(outputPath, yaml.stringify(result));
console.log(chalk_1.default.green(`ā
Template applied and saved to: ${options.output}`));
}
else if (options.json) {
// Output as JSON
console.log(JSON.stringify(result, null, 2));
}
else {
// Display result
console.log(chalk_1.default.cyan('\nš Applied Template Result'));
console.log(chalk_1.default.gray('ā'.repeat(50)));
console.log(yaml.stringify(result));
}
}
catch (error) {
if (spinner)
spinner.fail(chalk_1.default.red('Failed to apply template'));
throw error;
}
}
async function showTemplate(options, spinner) {
if (!options.template) {
throw new error_handler_1.ValidationError('Template name is required');
}
if (spinner)
spinner.setText(`Loading template: ${options.template}`);
try {
const manager = await (0, workspace_template_1.createWorkspaceTemplateManager)();
const template = await manager.getTemplate(options.template);
if (!template) {
throw new error_handler_1.ValidationError(`Template '${options.template}' not found`);
}
// Resolve inheritance chain
const chain = await manager.resolveInheritanceChain(options.template);
if (spinner)
spinner.stop();
if (options.json) {
console.log(JSON.stringify({
template,
inheritance: chain.templates.map(t => t.name),
mergedVariables: chain.variables
}, null, 2));
return;
}
console.log(chalk_1.default.cyan(`\nš Template: ${template.name}`));
console.log(chalk_1.default.gray('ā'.repeat(50)));
console.log(`Version: ${template.version}`);
if (template.description) {
console.log(`Description: ${template.description}`);
}
if (template.extends) {
console.log(`\n${chalk_1.default.yellow('Inheritance Chain:')}`);
for (let i = 0; i < chain.templates.length; i++) {
console.log(` ${i + 1}. ${chain.templates[i].name} v${chain.templates[i].version}`);
}
}
if (Object.keys(chain.variables).length > 0) {
console.log(`\n${chalk_1.default.blue('Variables:')}`);
for (const [name, varDef] of Object.entries(chain.variables)) {
console.log(` ${name}:`);
console.log(` Type: ${varDef.type}`);
if (varDef.description) {
console.log(` Description: ${varDef.description}`);
}
if (varDef.required) {
console.log(` Required: ${chalk_1.default.red('yes')}`);
}
if (varDef.default !== undefined) {
console.log(` Default: ${JSON.stringify(varDef.default)}`);
}
if (varDef.enum) {
console.log(` Values: ${varDef.enum.join(', ')}`);
}
if (varDef.pattern) {
console.log(` Pattern: ${varDef.pattern}`);
}
}
}
if (options.verbose) {
console.log(`\n${chalk_1.default.green('Template Content:')}`);
console.log(yaml.stringify(chain.merged));
}
console.log(chalk_1.default.cyan('\nš ļø Commands:'));
console.log(` ⢠Apply: re-shell workspace-template apply ${template.name}`);
console.log(` ⢠Delete: re-shell workspace-template delete ${template.name}`);
}
catch (error) {
if (spinner)
spinner.fail(chalk_1.default.red('Failed to load template'));
throw error;
}
}
async function deleteTemplate(options, spinner) {
if (!options.template) {
throw new error_handler_1.ValidationError('Template name is required');
}
if (spinner)
spinner.setText(`Deleting template: ${options.template}`);
try {
const manager = await (0, workspace_template_1.createWorkspaceTemplateManager)();
await manager.deleteTemplate(options.template);
if (spinner)
spinner.succeed(chalk_1.default.green(`Template '${options.template}' deleted successfully!`));
}
catch (error) {
if (spinner)
spinner.fail(chalk_1.default.red('Failed to delete template'));
throw error;
}
}
async function exportTemplate(options, spinner) {
const workspaceFile = options.workspaceFile || DEFAULT_WORKSPACE_FILE;
if (!options.name) {
throw new error_handler_1.ValidationError('Template name is required for export');
}
if (spinner)
spinner.setText('Exporting workspace as template...');
try {
const definition = await (0, workspace_schema_1.loadWorkspaceDefinition)(workspaceFile);
// Create variables for common fields
const variables = [
{
name: 'projectName',
type: 'string',
required: true,
description: 'Project name'
},
{
name: 'description',
type: 'string',
required: false,
description: 'Project description'
}
];
const template = await (0, workspace_template_1.exportWorkspaceAsTemplate)(definition, options.name, variables);
if (spinner)
spinner.stop();
if (options.output) {
// Save to file
const outputPath = path.resolve(options.output);
await fs.ensureDir(path.dirname(outputPath));
await fs.writeFile(outputPath, yaml.stringify(template));
console.log(chalk_1.default.green(`ā
Template exported to: ${options.output}`));
}
else {
// Create template
const manager = await (0, workspace_template_1.createWorkspaceTemplateManager)();
await manager.createTemplate(template);
console.log(chalk_1.default.green(`ā
Template '${options.name}' created from workspace`));
}
}
catch (error) {
if (spinner)
spinner.fail(chalk_1.default.red('Failed to export template'));
throw error;
}
}
async function interactiveTemplateManagement(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: 'š List templates', value: 'list' },
{ title: 'šØ Create new template', value: 'create' },
{ title: 'š§ Apply template', value: 'apply' },
{ title: 'šļø Show template details', value: 'show' },
{ title: 'š¤ Export workspace as template', value: 'export' },
{ title: 'šļø Delete template', value: 'delete' }
]
}
]);
if (!response.action)
return;
switch (response.action) {
case 'list':
await listTemplates({ ...options, interactive: false });
break;
case 'create':
await createTemplateInteractive({ ...options, interactive: false });
break;
case 'apply':
const applyResponse = await (0, prompts_1.default)({
type: 'text',
name: 'template',
message: 'Template name:'
});
if (applyResponse.template) {
await applyTemplate({ ...options, template: applyResponse.template, interactive: false });
}
break;
case 'show':
const showResponse = await (0, prompts_1.default)({
type: 'text',
name: 'template',
message: 'Template name:'
});
if (showResponse.template) {
await showTemplate({ ...options, template: showResponse.template, interactive: false });
}
break;
case 'export':
const exportResponse = await (0, prompts_1.default)({
type: 'text',
name: 'name',
message: 'Template name:'
});
if (exportResponse.name) {
await exportTemplate({ ...options, name: exportResponse.name, interactive: false });
}
break;
case 'delete':
const deleteResponse = await (0, prompts_1.default)({
type: 'text',
name: 'template',
message: 'Template name to delete:'
});
if (deleteResponse.template) {
const confirmResponse = await (0, prompts_1.default)({
type: 'confirm',
name: 'confirm',
message: `Are you sure you want to delete '${deleteResponse.template}'?`,
initial: false
});
if (confirmResponse.confirm) {
await deleteTemplate({ ...options, template: deleteResponse.template, interactive: false });
}
}
break;
}
}