@aerocorp/cli
Version:
AeroCorp CLI 5.1.0 - Future-Proofed Enterprise Infrastructure with Live Preview, Tunneling & Advanced DevOps
454 lines โข 22 kB
JavaScript
;
/**
* AeroCorp CLI 5.0.0 - Windows Native Service
* Implements Windows-native deployment without WSL dependency
* Similar to how Vercel CLI works seamlessly on Windows
*/
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.WindowsNativeService = void 0;
const child_process_1 = require("child_process");
const chalk_1 = __importDefault(require("chalk"));
const ora_1 = __importDefault(require("ora"));
const config_1 = require("./config");
class WindowsNativeService {
constructor() {
this.configService = new config_1.ConfigService();
this.sshConfig = {
host: this.configService.get('server_ip') || '128.140.35.238',
user: 'root',
port: 22,
keyPath: '%USERPROFILE%\\.ssh\\id_ed25519',
useBuiltInSSH: true
};
}
/**
* Check Windows environment and available tools
*/
async checkWindowsEnvironment() {
const spinner = (0, ora_1.default)('Checking Windows environment...').start();
try {
const isWindows = process.platform === 'win32';
if (!isWindows) {
spinner.info('Not running on Windows - using standard Unix tools');
return {
isWindows: false,
hasOpenSSH: false,
hasPowerShell: false,
hasWSL: false,
nodeVersion: process.version
};
}
// Check for built-in OpenSSH
const sshCheck = await this.executePowerShell('Get-Command ssh -ErrorAction SilentlyContinue');
const hasOpenSSH = sshCheck.success;
// Check for PowerShell
const pwshCheck = await this.executePowerShell('$PSVersionTable.PSVersion.Major');
const hasPowerShell = pwshCheck.success;
// Check for WSL (optional)
const wslCheck = await this.executePowerShell('Get-Command wsl -ErrorAction SilentlyContinue');
const hasWSL = wslCheck.success;
spinner.succeed('Windows environment checked');
console.log(chalk_1.default.cyan('\n๐ช Windows Environment:'));
console.log(chalk_1.default.white(` OS: Windows ${process.arch}`));
console.log(chalk_1.default.white(` Node.js: ${process.version}`));
console.log(hasOpenSSH ? chalk_1.default.green(' โ
OpenSSH client available') : chalk_1.default.red(' โ OpenSSH client missing'));
console.log(hasPowerShell ? chalk_1.default.green(' โ
PowerShell available') : chalk_1.default.red(' โ PowerShell missing'));
console.log(hasWSL ? chalk_1.default.green(' โ
WSL available (optional)') : chalk_1.default.yellow(' โ ๏ธ WSL not available (optional)'));
return {
isWindows,
hasOpenSSH,
hasPowerShell,
hasWSL,
nodeVersion: process.version
};
}
catch (error) {
spinner.fail('Environment check failed');
throw error;
}
}
/**
* Setup SSH keys using Windows native OpenSSH
*/
async setupWindowsSSH() {
const spinner = (0, ora_1.default)('Setting up Windows SSH...').start();
try {
const env = await this.checkWindowsEnvironment();
if (!env.isWindows) {
spinner.info('Not on Windows - skipping Windows SSH setup');
return true;
}
if (!env.hasOpenSSH) {
spinner.fail('OpenSSH client not found');
console.log(chalk_1.default.red('โ OpenSSH client is required'));
console.log(chalk_1.default.yellow('๐ก Install OpenSSH:'));
console.log(chalk_1.default.blue(' 1. Open Settings โ Apps โ Optional Features'));
console.log(chalk_1.default.blue(' 2. Add "OpenSSH Client"'));
console.log(chalk_1.default.blue(' 3. Or run: Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0'));
return false;
}
spinner.text = 'Checking SSH key...';
// Check if SSH key exists
const keyExists = await this.executePowerShell(`Test-Path "${this.sshConfig.keyPath}"`);
if (!keyExists.success || keyExists.output.trim() === 'False') {
spinner.text = 'Generating SSH key...';
// Create .ssh directory
await this.executePowerShell(`New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\\.ssh"`);
// Generate SSH key using Windows OpenSSH
const keyGenResult = await this.executePowerShell(`ssh-keygen -t ed25519 -C "aerocorp-cli@windows" -f "${this.sshConfig.keyPath}" -N '""'`);
if (!keyGenResult.success) {
throw new Error('Failed to generate SSH key');
}
console.log(chalk_1.default.green('โ
SSH key generated'));
}
else {
console.log(chalk_1.default.blue('๐ SSH key already exists'));
}
spinner.text = 'Testing SSH connection...';
// Test SSH connection
const sshTest = await this.executePowerShell(`ssh -o ConnectTimeout=10 -o BatchMode=yes -o StrictHostKeyChecking=no ${this.sshConfig.user}@${this.sshConfig.host} "echo 'Connection successful'"`);
if (sshTest.success) {
spinner.succeed('Windows SSH setup completed');
console.log(chalk_1.default.green('โ
SSH connection to Coolify server works'));
return true;
}
else {
spinner.warn('SSH key generated but connection failed');
console.log(chalk_1.default.yellow('โ ๏ธ SSH key needs to be copied to server manually'));
// Show public key for manual copying
const pubKeyResult = await this.executePowerShell(`Get-Content "${this.sshConfig.keyPath}.pub"`);
if (pubKeyResult.success) {
console.log(chalk_1.default.cyan('\n๐ Copy this public key to your server:'));
console.log(chalk_1.default.gray('โ'.repeat(80)));
console.log(pubKeyResult.output);
console.log(chalk_1.default.gray('โ'.repeat(80)));
console.log(chalk_1.default.yellow('๐ก Add to server: echo "YOUR_KEY" >> ~/.ssh/authorized_keys'));
}
return false;
}
}
catch (error) {
spinner.fail('Windows SSH setup failed');
console.error(chalk_1.default.red('โ Error:'), error.message);
return false;
}
}
/**
* Execute PowerShell command (Windows native)
*/
async executePowerShell(command, options = {}) {
return new Promise((resolve) => {
const shell = options.shell || 'powershell';
const timeout = options.timeout || 30000;
const process = (0, child_process_1.spawn)(shell, ['-Command', command], {
stdio: ['pipe', 'pipe', 'pipe'],
shell: false
});
let output = '';
let error = '';
process.stdout?.on('data', (data) => {
output += data.toString();
});
process.stderr?.on('data', (data) => {
error += data.toString();
});
const timer = setTimeout(() => {
process.kill();
resolve({ success: false, output, error: 'Command timed out' });
}, timeout);
process.on('close', (code) => {
clearTimeout(timer);
resolve({
success: code === 0,
output: output.trim(),
error: error.trim()
});
});
process.on('error', (err) => {
clearTimeout(timer);
resolve({
success: false,
output,
error: err.message
});
});
});
}
/**
* Execute SSH command using Windows native SSH client
*/
async executeSSH(command, options = {}) {
const spinner = (0, ora_1.default)('Executing SSH command...').start();
try {
const sshCommand = `ssh -o ConnectTimeout=10 ${this.sshConfig.user}@${this.sshConfig.host} "${command}"`;
if (options.follow) {
spinner.stop();
console.log(chalk_1.default.cyan(`\n๐ SSH Command: ${command}`));
console.log(chalk_1.default.gray('โ'.repeat(80)));
// For following commands (like logs), use live output
const sshProcess = (0, child_process_1.spawn)('ssh', [
'-o', 'ConnectTimeout=10',
'-o', 'StrictHostKeyChecking=no',
`${this.sshConfig.user}@${this.sshConfig.host}`,
command
], {
stdio: 'inherit'
});
return new Promise((resolve, reject) => {
sshProcess.on('close', (code) => {
if (code === 0) {
resolve();
}
else {
reject(new Error(`SSH command failed with code ${code}`));
}
});
sshProcess.on('error', (error) => {
reject(new Error(`SSH process error: ${error.message}`));
});
});
}
else {
// For one-time commands, capture output
const result = await this.executePowerShell(sshCommand, { timeout: options.timeout });
spinner.stop();
if (result.success) {
console.log(chalk_1.default.green('โ
SSH command executed successfully'));
if (result.output) {
console.log(result.output);
}
}
else {
console.log(chalk_1.default.red('โ SSH command failed'));
if (result.error) {
console.error(chalk_1.default.red('Error:'), result.error);
}
throw new Error('SSH command execution failed');
}
}
}
catch (error) {
spinner.fail('SSH execution failed');
throw error;
}
}
/**
* Get Docker logs using Windows native SSH
*/
async getDockerLogsNative(applicationId, options = {}) {
const dockerCommand = `docker logs ${options.follow ? '-f' : ''} --tail ${options.lines || 100} $(docker ps --filter "label=coolify.applicationId=${applicationId}" --format "{{.ID}}" | head -1)`;
console.log(chalk_1.default.cyan(`\n๐ Docker Logs for Application: ${applicationId}`));
if (options.follow) {
console.log(chalk_1.default.gray('Press Ctrl+C to stop following logs'));
}
await this.executeSSH(dockerCommand, { follow: options.follow });
}
/**
* Install OpenSSH client on Windows (requires admin)
*/
async installOpenSSH() {
const spinner = (0, ora_1.default)('Installing OpenSSH client...').start();
try {
console.log(chalk_1.default.yellow('โ ๏ธ This requires Administrator privileges'));
const installResult = await this.executePowerShell('Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0', { timeout: 60000 });
if (installResult.success) {
spinner.succeed('OpenSSH client installed successfully');
console.log(chalk_1.default.green('โ
OpenSSH client is now available'));
console.log(chalk_1.default.blue('๐ก Restart your terminal to use SSH commands'));
return true;
}
else {
spinner.fail('OpenSSH installation failed');
console.log(chalk_1.default.red('โ Installation failed. Try manual installation:'));
console.log(chalk_1.default.blue(' Settings โ Apps โ Optional Features โ Add OpenSSH Client'));
return false;
}
}
catch (error) {
spinner.fail('OpenSSH installation error');
console.error(chalk_1.default.red('โ Error:'), error.message);
return false;
}
}
/**
* Show Windows-specific setup instructions
*/
showWindowsSetupInstructions() {
console.log(chalk_1.default.cyan.bold('\n๐ช Windows Native Setup Guide'));
console.log(chalk_1.default.gray('โ'.repeat(60)));
console.log(chalk_1.default.white('\n๐ Prerequisites:'));
console.log(chalk_1.default.blue(' 1. Windows 10 (1803+) or Windows 11'));
console.log(chalk_1.default.blue(' 2. Node.js 18+ installed'));
console.log(chalk_1.default.blue(' 3. PowerShell 5.1+ or PowerShell Core 7+'));
console.log(chalk_1.default.white('\n๐ง Setup Steps:'));
console.log(chalk_1.default.blue(' 1. aerocorp windows check # Check environment'));
console.log(chalk_1.default.blue(' 2. aerocorp windows setup-ssh # Setup SSH keys'));
console.log(chalk_1.default.blue(' 3. aerocorp coolify health # Test Coolify API'));
console.log(chalk_1.default.blue(' 4. aerocorp windows test # Test all functionality'));
console.log(chalk_1.default.white('\n๐ Usage Examples:'));
console.log(chalk_1.default.blue(' aerocorp coolify deploy <uuid> # Deploy via API'));
console.log(chalk_1.default.blue(' aerocorp preview up --pr 123 --app <uuid> # Create PR preview'));
console.log(chalk_1.default.blue(' aerocorp logs <uuid> # Get logs via API'));
console.log(chalk_1.default.blue(' aerocorp logs <uuid> --ssh # Get logs via SSH'));
console.log(chalk_1.default.white('\n๐ก Pro Tips:'));
console.log(chalk_1.default.gray(' โข Use API methods for automation (faster, more reliable)'));
console.log(chalk_1.default.gray(' โข Use SSH methods for debugging and live log streaming'));
console.log(chalk_1.default.gray(' โข Set COOLIFY_TOKEN environment variable for CI/CD'));
}
/**
* Test all Windows functionality
*/
async testWindowsFunctionality() {
console.log(chalk_1.default.cyan.bold('\n๐งช Testing Windows Native Functionality'));
console.log(chalk_1.default.gray('โ'.repeat(60)));
let allPassed = true;
// Test 1: Environment check
console.log(chalk_1.default.blue('\n๐ Test 1: Environment Check'));
try {
const env = await this.checkWindowsEnvironment();
console.log(chalk_1.default.green('โ
Environment check passed'));
}
catch (error) {
console.log(chalk_1.default.red('โ Environment check failed'));
allPassed = false;
}
// Test 2: PowerShell execution
console.log(chalk_1.default.blue('\n๐ Test 2: PowerShell Execution'));
try {
const result = await this.executePowerShell('echo "PowerShell test successful"');
if (result.success) {
console.log(chalk_1.default.green('โ
PowerShell execution works'));
}
else {
console.log(chalk_1.default.red('โ PowerShell execution failed'));
allPassed = false;
}
}
catch (error) {
console.log(chalk_1.default.red('โ PowerShell test failed'));
allPassed = false;
}
// Test 3: SSH availability
console.log(chalk_1.default.blue('\n๐ Test 3: SSH Client Availability'));
try {
const sshResult = await this.executePowerShell('ssh -V');
if (sshResult.success) {
console.log(chalk_1.default.green('โ
SSH client available'));
console.log(chalk_1.default.gray(` Version: ${sshResult.output.split('\n')[0]}`));
}
else {
console.log(chalk_1.default.yellow('โ ๏ธ SSH client not available'));
console.log(chalk_1.default.blue('๐ก Run: aerocorp windows install-ssh'));
}
}
catch (error) {
console.log(chalk_1.default.yellow('โ ๏ธ SSH test inconclusive'));
}
// Test 4: Coolify API connectivity
console.log(chalk_1.default.blue('\n๐ Test 4: Coolify API Connectivity'));
try {
const { CoolifyService } = await Promise.resolve().then(() => __importStar(require('./coolify')));
const coolifyService = new CoolifyService();
const healthCheck = await coolifyService.healthCheck();
if (healthCheck) {
console.log(chalk_1.default.green('โ
Coolify API connection works'));
}
else {
console.log(chalk_1.default.red('โ Coolify API connection failed'));
console.log(chalk_1.default.yellow('๐ก Check your COOLIFY_TOKEN and network connectivity'));
allPassed = false;
}
}
catch (error) {
console.log(chalk_1.default.red('โ Coolify API test failed'));
allPassed = false;
}
// Summary
console.log(chalk_1.default.cyan('\n๐ Test Summary:'));
console.log(chalk_1.default.gray('โ'.repeat(30)));
if (allPassed) {
console.log(chalk_1.default.green.bold('๐ All tests passed! Windows native functionality is ready.'));
console.log(chalk_1.default.white('\nYou can now use:'));
console.log(chalk_1.default.blue(' โข aerocorp coolify deploy <uuid>'));
console.log(chalk_1.default.blue(' โข aerocorp preview up --pr <num> --app <uuid> --branch <branch>'));
console.log(chalk_1.default.blue(' โข aerocorp logs <uuid> [--ssh]'));
}
else {
console.log(chalk_1.default.yellow.bold('โ ๏ธ Some tests failed. Check the issues above.'));
console.log(chalk_1.default.white('\nTroubleshooting:'));
console.log(chalk_1.default.blue(' โข aerocorp windows install-ssh # Install OpenSSH'));
console.log(chalk_1.default.blue(' โข aerocorp coolify login # Setup API authentication'));
}
return allPassed;
}
/**
* Get system information for troubleshooting
*/
async getSystemInfo() {
console.log(chalk_1.default.cyan.bold('\n๐ฅ๏ธ System Information'));
console.log(chalk_1.default.gray('โ'.repeat(50)));
try {
// Windows version
const winVersion = await this.executePowerShell('(Get-CimInstance Win32_OperatingSystem).Caption');
if (winVersion.success) {
console.log(chalk_1.default.white(`OS: ${winVersion.output}`));
}
// PowerShell version
const psVersion = await this.executePowerShell('$PSVersionTable.PSVersion.ToString()');
if (psVersion.success) {
console.log(chalk_1.default.white(`PowerShell: ${psVersion.output}`));
}
// Node.js info
console.log(chalk_1.default.white(`Node.js: ${process.version} (${process.arch})`));
// Network connectivity
const pingResult = await this.executePowerShell(`Test-NetConnection -ComputerName ${this.sshConfig.host} -Port 22 -InformationLevel Quiet`);
if (pingResult.success && pingResult.output.trim() === 'True') {
console.log(chalk_1.default.green('โ
Network connectivity to Coolify server'));
}
else {
console.log(chalk_1.default.red('โ Cannot reach Coolify server'));
}
}
catch (error) {
console.error(chalk_1.default.red('โ Failed to get system info:'), error.message);
}
}
}
exports.WindowsNativeService = WindowsNativeService;
//# sourceMappingURL=windows-native.js.map