@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
648 lines (647 loc) • 25.7 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;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.PluginMarketplace = exports.PluginCategory = void 0;
exports.createMarketplace = createMarketplace;
exports.isValidPluginId = isValidPluginId;
exports.formatFileSize = formatFileSize;
exports.formatDownloadCount = formatDownloadCount;
const fs = __importStar(require("fs-extra"));
const path = __importStar(require("path"));
const events_1 = require("events");
const error_handler_1 = require("./error-handler");
// Plugin categories
var PluginCategory;
(function (PluginCategory) {
PluginCategory["DEVELOPMENT"] = "development";
PluginCategory["PRODUCTIVITY"] = "productivity";
PluginCategory["AUTOMATION"] = "automation";
PluginCategory["INTEGRATION"] = "integration";
PluginCategory["TESTING"] = "testing";
PluginCategory["DEPLOYMENT"] = "deployment";
PluginCategory["MONITORING"] = "monitoring";
PluginCategory["SECURITY"] = "security";
PluginCategory["UTILITY"] = "utility";
PluginCategory["THEME"] = "theme";
PluginCategory["EXTENSION"] = "extension";
})(PluginCategory || (exports.PluginCategory = PluginCategory = {}));
// Plugin marketplace client
class PluginMarketplace extends events_1.EventEmitter {
constructor(config = {}) {
super();
this.cache = new Map();
this.downloadQueue = new Map();
this.config = {
apiUrl: 'https://marketplace.re-shell.dev/api/v1',
cacheTimeout: 300000, // 5 minutes
downloadTimeout: 30000, // 30 seconds
verifySignatures: true,
allowPrerelease: false,
autoUpdate: false,
telemetry: true,
...config
};
}
// Search plugins in marketplace
async searchPlugins(filters = {}) {
const cacheKey = `search_${JSON.stringify(filters)}`;
// Check cache
const cached = this.getCachedData(cacheKey);
if (cached) {
this.emit('search-cache-hit', filters);
return cached;
}
this.emit('search-started', filters);
const startTime = Date.now();
try {
// In a real implementation, this would make HTTP requests to marketplace API
const mockResult = await this.mockSearchRequest(filters);
// Cache result
this.setCachedData(cacheKey, mockResult);
const duration = Date.now() - startTime;
this.emit('search-completed', {
filters,
total: mockResult.total,
duration
});
return mockResult;
}
catch (error) {
const duration = Date.now() - startTime;
this.emit('search-failed', {
filters,
error,
duration
});
throw error;
}
}
// Get plugin details
async getPlugin(pluginId) {
const cacheKey = `plugin_${pluginId}`;
// Check cache
const cached = this.getCachedData(cacheKey);
if (cached) {
this.emit('plugin-cache-hit', pluginId);
return cached;
}
this.emit('plugin-fetch-started', pluginId);
try {
// Mock plugin data - in real implementation would fetch from API
const plugin = await this.mockGetPlugin(pluginId);
if (plugin) {
this.setCachedData(cacheKey, plugin);
}
this.emit('plugin-fetch-completed', { pluginId, found: !!plugin });
return plugin;
}
catch (error) {
this.emit('plugin-fetch-failed', { pluginId, error });
throw error;
}
}
// Install plugin from marketplace
async installPlugin(pluginId, version, options = {}) {
const installKey = `${pluginId}@${version || 'latest'}`;
// Prevent concurrent installations
if (this.downloadQueue.has(installKey)) {
return await this.downloadQueue.get(installKey);
}
const installPromise = this.performInstallation(pluginId, version, options);
this.downloadQueue.set(installKey, installPromise);
try {
const result = await installPromise;
return result;
}
finally {
this.downloadQueue.delete(installKey);
}
}
// Perform plugin installation
async performInstallation(pluginId, version, options = {}) {
const startTime = Date.now();
this.emit('installation-started', { pluginId, version, options });
try {
// Get plugin information
const plugin = await this.getPlugin(pluginId);
if (!plugin) {
throw new error_handler_1.ValidationError(`Plugin '${pluginId}' not found in marketplace`);
}
const targetVersion = version || plugin.latestVersion;
// Check compatibility
await this.checkCompatibility(plugin, targetVersion);
// Download plugin
const downloadPath = await this.downloadPlugin(plugin, targetVersion);
// Verify plugin
if (this.config.verifySignatures) {
await this.verifyPluginSignature(downloadPath);
}
// Install plugin
const installPath = await this.installPluginFiles(downloadPath, options);
// Install dependencies
const dependencies = await this.installDependencies(plugin);
const result = {
success: true,
plugin,
installedVersion: targetVersion,
installPath,
dependencies,
warnings: [],
errors: [],
duration: Date.now() - startTime
};
this.emit('installation-completed', result);
return result;
}
catch (error) {
const result = {
success: false,
plugin: {},
installedVersion: '',
installPath: '',
dependencies: [],
warnings: [],
errors: [error instanceof Error ? error.message : String(error)],
duration: Date.now() - startTime
};
this.emit('installation-failed', result);
return result;
}
}
// Check plugin compatibility
async checkCompatibility(plugin, version) {
const semver = require('semver');
// Check CLI version compatibility
if (plugin.compatibility.cliVersion) {
const currentCliVersion = '0.7.0'; // Would get from package.json
if (!semver.satisfies(currentCliVersion, plugin.compatibility.cliVersion)) {
throw new error_handler_1.ValidationError(`Plugin requires CLI version ${plugin.compatibility.cliVersion}, current: ${currentCliVersion}`);
}
}
// Check Node.js version compatibility
if (plugin.compatibility.nodeVersion) {
const currentNodeVersion = process.version;
if (!semver.satisfies(currentNodeVersion, plugin.compatibility.nodeVersion)) {
throw new error_handler_1.ValidationError(`Plugin requires Node.js version ${plugin.compatibility.nodeVersion}, current: ${currentNodeVersion}`);
}
}
// Check platform compatibility
if (plugin.compatibility.platforms.length > 0) {
const currentPlatform = process.platform;
if (!plugin.compatibility.platforms.includes(currentPlatform)) {
throw new error_handler_1.ValidationError(`Plugin not compatible with platform ${currentPlatform}. Supported: ${plugin.compatibility.platforms.join(', ')}`);
}
}
}
// Download plugin from marketplace
async downloadPlugin(plugin, version) {
const downloadUrl = `${this.config.apiUrl}/plugins/${plugin.id}/download/${version}`;
const downloadPath = path.join(process.cwd(), '.re-shell', 'downloads', `${plugin.id}-${version}.tgz`);
await fs.ensureDir(path.dirname(downloadPath));
this.emit('download-started', { plugin: plugin.id, version, url: downloadUrl });
try {
// Mock download - in real implementation would use HTTP client
await this.mockDownloadFile(downloadUrl, downloadPath);
this.emit('download-completed', { plugin: plugin.id, version, path: downloadPath });
return downloadPath;
}
catch (error) {
this.emit('download-failed', { plugin: plugin.id, version, error });
throw error;
}
}
// Verify plugin signature
async verifyPluginSignature(downloadPath) {
// Mock signature verification
this.emit('signature-verification', { path: downloadPath, verified: true });
}
// Install plugin files
async installPluginFiles(downloadPath, options) {
const installDir = options.global
? path.join(require('os').homedir(), '.re-shell', 'plugins')
: path.join(process.cwd(), '.re-shell', 'plugins');
await fs.ensureDir(installDir);
// Mock extraction and installation
const pluginName = path.basename(downloadPath, '.tgz').split('-')[0];
const installPath = path.join(installDir, pluginName);
await fs.ensureDir(installPath);
// Create mock plugin structure
await fs.writeJSON(path.join(installPath, 'package.json'), {
name: pluginName,
version: '1.0.0',
description: 'Marketplace plugin',
main: 'index.js'
});
await fs.writeFile(path.join(installPath, 'index.js'), `
module.exports = {
activate: (context) => {
console.log('Plugin ${pluginName} activated');
}
};
`);
return installPath;
}
// Install plugin dependencies
async installDependencies(plugin) {
const dependencies = Object.keys(plugin.dependencies);
// Mock dependency installation
for (const dep of dependencies) {
this.emit('dependency-install', { dependency: dep, plugin: plugin.id });
}
return dependencies;
}
// Get plugin reviews
async getPluginReviews(pluginId, limit = 10, offset = 0) {
const cacheKey = `reviews_${pluginId}_${limit}_${offset}`;
const cached = this.getCachedData(cacheKey);
if (cached) {
return cached;
}
try {
const reviews = await this.mockGetReviews(pluginId, limit, offset);
this.setCachedData(cacheKey, reviews);
return reviews;
}
catch (error) {
this.emit('reviews-fetch-failed', { pluginId, error });
throw error;
}
}
// Submit plugin review
async submitReview(review) {
try {
// Mock review submission
const submittedReview = {
...review,
id: `review_${Date.now()}`,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString()
};
this.emit('review-submitted', submittedReview);
return submittedReview;
}
catch (error) {
this.emit('review-submission-failed', { review, error });
throw error;
}
}
// Get featured plugins
async getFeaturedPlugins(limit = 6) {
const cacheKey = `featured_${limit}`;
const cached = this.getCachedData(cacheKey);
if (cached) {
return cached;
}
try {
const featured = await this.mockGetFeatured(limit);
this.setCachedData(cacheKey, featured);
return featured;
}
catch (error) {
this.emit('featured-fetch-failed', { error });
throw error;
}
}
// Get popular plugins
async getPopularPlugins(category, limit = 10) {
const cacheKey = `popular_${category || 'all'}_${limit}`;
const cached = this.getCachedData(cacheKey);
if (cached) {
return cached;
}
try {
const popular = await this.mockGetPopular(category, limit);
this.setCachedData(cacheKey, popular);
return popular;
}
catch (error) {
this.emit('popular-fetch-failed', { category, error });
throw error;
}
}
// Get plugin categories
async getCategories() {
const cacheKey = 'categories';
const cached = this.getCachedData(cacheKey);
if (cached) {
return cached;
}
try {
const categories = [
{ name: PluginCategory.DEVELOPMENT, count: 45, description: 'Development tools and utilities' },
{ name: PluginCategory.PRODUCTIVITY, count: 32, description: 'Productivity and workflow enhancements' },
{ name: PluginCategory.AUTOMATION, count: 28, description: 'Automation and scripting tools' },
{ name: PluginCategory.INTEGRATION, count: 25, description: 'Third-party service integrations' },
{ name: PluginCategory.TESTING, count: 18, description: 'Testing frameworks and utilities' },
{ name: PluginCategory.DEPLOYMENT, count: 15, description: 'Deployment and CI/CD tools' },
{ name: PluginCategory.MONITORING, count: 12, description: 'Monitoring and observability' },
{ name: PluginCategory.SECURITY, count: 10, description: 'Security and vulnerability tools' },
{ name: PluginCategory.UTILITY, count: 22, description: 'General utilities and helpers' },
{ name: PluginCategory.THEME, count: 8, description: 'Visual themes and customizations' },
{ name: PluginCategory.EXTENSION, count: 35, description: 'CLI extensions and enhancements' }
];
this.setCachedData(cacheKey, categories);
return categories;
}
catch (error) {
this.emit('categories-fetch-failed', { error });
throw error;
}
}
// Clear marketplace cache
clearCache() {
this.cache.clear();
this.emit('cache-cleared');
}
// Get cached data
getCachedData(key) {
const cached = this.cache.get(key);
if (cached && Date.now() - cached.timestamp < this.config.cacheTimeout) {
return cached.data;
}
return null;
}
// Set cached data
setCachedData(key, data) {
this.cache.set(key, {
data,
timestamp: Date.now()
});
}
// Mock methods for development - would be replaced with actual API calls
async mockSearchRequest(filters) {
await new Promise(resolve => setTimeout(resolve, 500)); // Simulate network delay
const mockPlugins = [
{
id: 'eslint-plugin',
name: 'ESLint Integration',
version: '1.2.3',
latestVersion: '1.2.3',
description: 'Integrate ESLint with Re-Shell for code quality checks',
author: 'Re-Shell Team',
license: 'MIT',
keywords: ['linting', 'quality', 'javascript'],
category: PluginCategory.DEVELOPMENT,
downloads: 12450,
rating: 4.8,
reviewCount: 89,
featured: true,
verified: true,
createdAt: '2024-01-15T10:00:00Z',
updatedAt: '2024-06-15T14:30:00Z',
size: 2048576,
dependencies: { 'eslint': '^8.0.0' },
compatibility: {
cliVersion: '>=0.6.0',
nodeVersion: '>=16.0.0',
platforms: ['darwin', 'linux', 'win32']
},
pricing: { type: 'free' },
support: {
documentation: 'https://docs.re-shell.dev/plugins/eslint',
issues: 'https://github.com/re-shell/eslint-plugin/issues',
languages: ['en', 'es', 'fr']
},
metrics: {
weeklyDownloads: 1250,
monthlyDownloads: 5200,
totalDownloads: 12450,
stars: 456,
forks: 23,
issues: 3,
lastCommit: '2024-06-15T14:30:00Z',
contributors: 8
}
},
{
id: 'docker-helper',
name: 'Docker Helper',
version: '2.1.0',
latestVersion: '2.1.0',
description: 'Streamline Docker operations with enhanced commands',
author: 'DevOps Community',
license: 'Apache-2.0',
keywords: ['docker', 'containers', 'devops'],
category: PluginCategory.DEPLOYMENT,
downloads: 8230,
rating: 4.6,
reviewCount: 67,
featured: false,
verified: true,
createdAt: '2024-02-20T09:15:00Z',
updatedAt: '2024-06-10T11:45:00Z',
size: 1536000,
dependencies: {},
compatibility: {
cliVersion: '>=0.5.0',
nodeVersion: '>=14.0.0',
platforms: ['darwin', 'linux']
},
pricing: { type: 'free' },
support: {
documentation: 'https://docker-helper.dev',
community: 'https://discord.gg/docker-helper',
languages: ['en']
},
metrics: {
weeklyDownloads: 890,
monthlyDownloads: 3400,
totalDownloads: 8230,
stars: 234,
forks: 12,
issues: 5,
lastCommit: '2024-06-10T11:45:00Z',
contributors: 4
}
}
];
// Apply filters
let filteredPlugins = mockPlugins;
if (filters.query) {
const query = filters.query.toLowerCase();
filteredPlugins = filteredPlugins.filter(p => p.name.toLowerCase().includes(query) ||
p.description.toLowerCase().includes(query) ||
p.keywords.some(k => k.toLowerCase().includes(query)));
}
if (filters.category) {
filteredPlugins = filteredPlugins.filter(p => p.category === filters.category);
}
if (filters.featured !== undefined) {
filteredPlugins = filteredPlugins.filter(p => p.featured === filters.featured);
}
if (filters.verified !== undefined) {
filteredPlugins = filteredPlugins.filter(p => p.verified === filters.verified);
}
if (filters.free !== undefined) {
filteredPlugins = filteredPlugins.filter(p => p.pricing.type === 'free');
}
// Apply sorting
if (filters.sortBy) {
filteredPlugins.sort((a, b) => {
let comparison = 0;
switch (filters.sortBy) {
case 'downloads':
comparison = b.downloads - a.downloads;
break;
case 'rating':
comparison = b.rating - a.rating;
break;
case 'updated':
comparison = new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime();
break;
case 'created':
comparison = new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime();
break;
case 'name':
comparison = a.name.localeCompare(b.name);
break;
}
return filters.sortOrder === 'asc' ? -comparison : comparison;
});
}
// Apply pagination
const limit = filters.limit || 10;
const offset = filters.offset || 0;
const paginatedPlugins = filteredPlugins.slice(offset, offset + limit);
return {
plugins: paginatedPlugins,
total: filteredPlugins.length,
page: Math.floor(offset / limit) + 1,
pages: Math.ceil(filteredPlugins.length / limit),
filters
};
}
async mockGetPlugin(pluginId) {
await new Promise(resolve => setTimeout(resolve, 200));
// Return mock plugin data if found
const mockResult = await this.mockSearchRequest({ query: pluginId });
return mockResult.plugins.find(p => p.id === pluginId) || null;
}
async mockDownloadFile(url, downloadPath) {
await new Promise(resolve => setTimeout(resolve, 1000)); // Simulate download
await fs.writeFile(downloadPath, 'mock-plugin-archive');
}
async mockGetReviews(pluginId, limit, offset) {
await new Promise(resolve => setTimeout(resolve, 300));
return [
{
id: 'review_1',
pluginId,
userId: 'user_123',
username: 'developer1',
rating: 5,
title: 'Excellent plugin!',
content: 'This plugin has significantly improved my workflow. Highly recommended!',
pros: ['Easy to use', 'Well documented', 'Fast'],
cons: [],
version: '1.2.3',
helpful: 15,
verified: true,
createdAt: '2024-06-01T10:30:00Z',
updatedAt: '2024-06-01T10:30:00Z'
},
{
id: 'review_2',
pluginId,
userId: 'user_456',
username: 'coder_pro',
rating: 4,
title: 'Very useful',
content: 'Good plugin with room for improvement in configuration options.',
pros: ['Stable', 'Good performance'],
cons: ['Limited configuration'],
version: '1.2.0',
helpful: 8,
verified: false,
createdAt: '2024-05-15T14:20:00Z',
updatedAt: '2024-05-15T14:20:00Z'
}
];
}
async mockGetFeatured(limit) {
await new Promise(resolve => setTimeout(resolve, 300));
const result = await this.mockSearchRequest({ featured: true, limit });
return result.plugins;
}
async mockGetPopular(category, limit = 10) {
await new Promise(resolve => setTimeout(resolve, 300));
const result = await this.mockSearchRequest({
category,
sortBy: 'downloads',
sortOrder: 'desc',
limit
});
return result.plugins;
}
// Get marketplace statistics
getStats() {
return {
cacheSize: this.cache.size,
activeDownloads: this.downloadQueue.size,
config: {
cacheTimeout: this.config.cacheTimeout,
downloadTimeout: this.config.downloadTimeout,
verifySignatures: this.config.verifySignatures
}
};
}
}
exports.PluginMarketplace = PluginMarketplace;
// Utility functions
function createMarketplace(config) {
return new PluginMarketplace(config);
}
function isValidPluginId(id) {
return /^[a-z0-9][a-z0-9\-]*[a-z0-9]$/.test(id) && id.length >= 2 && id.length <= 50;
}
function formatFileSize(bytes) {
const units = ['B', 'KB', 'MB', 'GB'];
let size = bytes;
let unitIndex = 0;
while (size >= 1024 && unitIndex < units.length - 1) {
size /= 1024;
unitIndex++;
}
return `${size.toFixed(1)} ${units[unitIndex]}`;
}
function formatDownloadCount(count) {
if (count >= 1000000) {
return `${(count / 1000000).toFixed(1)}M`;
}
else if (count >= 1000) {
return `${(count / 1000).toFixed(1)}K`;
}
return count.toString();
}