UNPKG

selah-cli

Version:

Zero-setup AWS deployment for Bolt.new apps. Build in Bolt, deploy to production in 3 minutes with AI guidance.

290 lines (245 loc) • 9.62 kB
#!/usr/bin/env node import { spawn } from 'cross-spawn'; import { promises as fs } from 'fs'; import path from 'path'; import os from 'os'; import which from 'which'; import { fileURLToPath } from 'url'; /** * Cross-platform AWS CLI installer for Selah * Automatically installs AWS CLI when users run: npm install selah-cli */ const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); // Check if running in WebContainers (Bolt.new, StackBlitz, etc.) - DO THIS FIRST! function isWebContainer() { // More comprehensive WebContainer detection const webContainerIndicators = [ process.env.SHELL === '/bin/jsh', process.env.TERM === 'xterm-color', process.env.STACKBLITZ, process.env.WEBCONTAINER, process.env.BOLT_NEW, process.env.CODESANDBOX_SSE, process.cwd().includes('/home/project'), process.cwd().includes('/tmp/'), // Bolt.new specific indicators process.env.HOME === '/home/project', process.env.PWD?.includes('/tmp/'), // Check if we're running in a sandboxed environment !process.env.SUDO_UID && process.getuid && process.getuid() !== 0 && process.cwd().includes('/tmp'), // Additional browser environment checks typeof window !== 'undefined' || process.title === 'browser' ]; return webContainerIndicators.some(indicator => indicator); } // Exit immediately if in WebContainer environment if (isWebContainer()) { console.log(`🌐 WebContainer environment detected (Bolt.new/StackBlitz)`); console.log(`ā­ļø Skipping AWS CLI installation - not needed in browser environment`); console.log(`āœ… Selah CLI ready to use with serverless backend!`); console.log(`\nšŸš€ Selah works in Bolt.new without AWS CLI:`); console.log(` - Uses Supabase Edge Functions for backend`); console.log(` - Generates infrastructure files locally`); console.log(` - No native binaries required`); console.log(`\nšŸ’” Commands available:`); console.log(` npm run bolt:init # Initialize Selah project`); console.log(` npm run bolt:analyze # Analyze with AI Cloud Engineer`); console.log(` npm run bolt:deploy # Generate AWS infrastructure`); process.exit(0); } const platform = os.platform(); const arch = os.arch(); console.log(`šŸ”§ Selah AWS CLI Auto-Installer`); console.log(`šŸ“± Platform: ${platform} (${arch})`); async function checkAwsCliExists() { try { const awsPath = await which('aws'); console.log(`āœ… AWS CLI already installed at: ${awsPath}`); // Check version const result = spawn.sync('aws', ['--version'], { encoding: 'utf8' }); if (result.stdout) { console.log(`šŸ“„ Version: ${result.stdout.trim()}`); return true; } } catch (error) { console.log(`āŒ AWS CLI not found in PATH`); return false; } } async function downloadFile(url, outputPath) { console.log(`ā¬‡ļø Downloading: ${url}`); try { const fetch = (await import('node-fetch')).default; const response = await fetch(url); if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } const arrayBuffer = await response.arrayBuffer(); const buffer = Buffer.from(arrayBuffer); await fs.writeFile(outputPath, buffer); console.log(`āœ… Downloaded to: ${outputPath}`); return true; } catch (error) { console.error(`āŒ Download failed: ${error.message}`); return false; } } async function installAwsCliWindows() { console.log(`🪟 Installing AWS CLI for Windows...`); const tempDir = os.tmpdir(); const installerPath = path.join(tempDir, 'AWSCLIV2.msi'); const downloadUrl = 'https://awscli.amazonaws.com/AWSCLIV2.msi'; try { // Download MSI installer const downloaded = await downloadFile(downloadUrl, installerPath); if (!downloaded) return false; // Run MSI installer silently console.log(`šŸ”§ Installing AWS CLI...`); const result = spawn.sync('msiexec', ['/i', installerPath, '/qn'], { stdio: 'inherit', timeout: 300000 // 5 minutes }); if (result.status === 0) { console.log(`āœ… AWS CLI installed successfully!`); // Clean up await fs.unlink(installerPath).catch(() => {}); return true; } else { console.error(`āŒ Installation failed with exit code: ${result.status}`); return false; } } catch (error) { console.error(`āŒ Installation error: ${error.message}`); return false; } } async function installAwsCliMacOS() { console.log(`šŸŽ Installing AWS CLI for macOS...`); const tempDir = os.tmpdir(); const installerPath = path.join(tempDir, 'AWSCLIV2.pkg'); const downloadUrl = 'https://awscli.amazonaws.com/AWSCLIV2.pkg'; try { // Download PKG installer const downloaded = await downloadFile(downloadUrl, installerPath); if (!downloaded) return false; // Run PKG installer with sudo console.log(`šŸ”§ Installing AWS CLI (may require admin password)...`); const result = spawn.sync('sudo', ['installer', '-pkg', installerPath, '-target', '/'], { stdio: 'inherit', timeout: 300000 // 5 minutes }); if (result.status === 0) { console.log(`āœ… AWS CLI installed successfully!`); // Clean up await fs.unlink(installerPath).catch(() => {}); return true; } else { console.error(`āŒ Installation failed with exit code: ${result.status}`); return false; } } catch (error) { console.error(`āŒ Installation error: ${error.message}`); return false; } } async function installAwsCliLinux() { console.log(`🐧 Installing AWS CLI for Linux...`); const tempDir = os.tmpdir(); const zipPath = path.join(tempDir, 'awscliv2.zip'); const extractDir = path.join(tempDir, 'aws-cli-install'); // Determine download URL based on architecture const downloadUrl = arch === 'arm64' || arch === 'aarch64' ? 'https://awscli.amazonaws.com/awscli-exe-linux-aarch64.zip' : 'https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip'; try { // Download ZIP file const downloaded = await downloadFile(downloadUrl, zipPath); if (!downloaded) return false; // Create extraction directory await fs.mkdir(extractDir, { recursive: true }); // Extract ZIP file console.log(`šŸ“¦ Extracting AWS CLI...`); const unzipResult = spawn.sync('unzip', ['-q', zipPath, '-d', extractDir], { stdio: 'inherit' }); if (unzipResult.status !== 0) { console.error(`āŒ Failed to extract AWS CLI`); return false; } // Run installer console.log(`šŸ”§ Installing AWS CLI (may require admin password)...`); const installResult = spawn.sync('sudo', [path.join(extractDir, 'aws', 'install')], { stdio: 'inherit', timeout: 300000 // 5 minutes }); if (installResult.status === 0) { console.log(`āœ… AWS CLI installed successfully!`); // Clean up await fs.rmdir(extractDir, { recursive: true }).catch(() => {}); await fs.unlink(zipPath).catch(() => {}); return true; } else { console.error(`āŒ Installation failed with exit code: ${installResult.status}`); return false; } } catch (error) { console.error(`āŒ Installation error: ${error.message}`); return false; } } async function showFallbackInstructions() { console.log(`\nāš ļø Automatic installation failed. Please install AWS CLI manually:`); console.log(`\nšŸ“– Installation Instructions:`); if (platform === 'win32') { console.log(`🪟 Windows:`); console.log(` 1. Download: https://awscli.amazonaws.com/AWSCLIV2.msi`); console.log(` 2. Run the installer`); } else if (platform === 'darwin') { console.log(`šŸŽ macOS:`); console.log(` 1. Download: https://awscli.amazonaws.com/AWSCLIV2.pkg`); console.log(` 2. Run: sudo installer -pkg AWSCLIV2.pkg -target /`); } else { console.log(`🐧 Linux:`); console.log(` 1. curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"`); console.log(` 2. unzip awscliv2.zip`); console.log(` 3. sudo ./aws/install`); } console.log(`\nšŸ”— Official Guide: https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html`); } async function main() { try { // Skip installation if AWS CLI already exists const exists = await checkAwsCliExists(); if (exists) { console.log(`\nšŸŽ‰ Selah is ready to use with existing AWS CLI!`); return; } console.log(`\nšŸš€ Installing AWS CLI automatically...`); let success = false; if (platform === 'win32') { success = await installAwsCliWindows(); } else if (platform === 'darwin') { success = await installAwsCliMacOS(); } else if (platform === 'linux') { success = await installAwsCliLinux(); } else { console.log(`āŒ Unsupported platform: ${platform}`); } if (success) { console.log(`\nšŸŽ‰ AWS CLI installation complete!`); console.log(`✨ Selah is now ready to deploy your infrastructure to AWS!`); console.log(`\nšŸ“š Next steps:`); console.log(` 1. Configure AWS credentials: aws configure`); console.log(` 2. Run: npx selah analyze`); } else { await showFallbackInstructions(); } } catch (error) { console.error(`āŒ Installation failed: ${error.message}`); await showFallbackInstructions(); } } // Run main function main().catch(console.error); export { main as installAwsCli };