UNPKG

pame-core-cli

Version:

PAME.AI Core Operating System CLI - Open Source AI Platform for Agentic Commerce

592 lines โ€ข 26.6 kB
import { Command } from 'commander'; import { execSync } from 'child_process'; import * as path from 'path'; import * as fs from 'fs'; import { VercelDeploymentSDK } from '../services/vercel-deployment-sdk.js'; import { handleCalendarIntegration } from './deploy-calendar.js'; import chalk from 'chalk'; export const deployCommand = new Command('deploy') .description('Deployment operations for PAME.AI services') .addCommand(new Command('all') .description('Deploy all platforms (www, app, core, store, mcp)') .option('--production', 'Deploy to production environment') .option('--use-sdk', 'Use Vercel SDK for enhanced deployment (recommended)', false) .option('--schedule', 'Schedule deployment using calendar integration') .option('--check-team', 'Check team availability before deployment') .action(async (options) => { if (options.schedule || options.checkTeam) { await handleCalendarIntegration(options, 'all'); return; } console.log(chalk.blue('๐Ÿš€ Deploying all PAME.AI platforms...\n')); // Deploy in order await deployWWW(options.production); await deployApp(options.production); await deployCore(options.production); await deployStore(options.production); await deployMCP(options.production); console.log(chalk.green('\nโœ… All platforms deployed successfully!')); console.log(chalk.cyan('๐ŸŒ www.pame.ai - Marketing website')); console.log(chalk.cyan('๐Ÿ” app.pame.ai - Developer platform')); console.log(chalk.cyan('๐Ÿ›ก๏ธ core.pame.ai - Core team platform')); console.log(chalk.cyan('๐Ÿช store.pame.ai - App marketplace')); console.log(chalk.cyan('๐Ÿ”Œ mcp.pame.ai - MCP connector for ChatGPT')); })) .addCommand(new Command('www') .description('Deploy www.pame.ai marketing website') .option('--production', 'Deploy to production environment') .option('--use-sdk', 'Use Vercel SDK for enhanced deployment', false) .action(async (options) => { if (options.useSdk) { await deployPlatformWithSDK('www', 'pame-www', options.production); } else { await deployWWW(options.production); } })) .addCommand(new Command('app') .description('Deploy app.pame.ai developer platform') .option('--production', 'Deploy to production environment') .option('--use-sdk', 'Use Vercel SDK for enhanced deployment', false) .action(async (options) => { if (options.useSdk) { await deployPlatformWithSDK('app', 'pame-app', options.production); } else { await deployApp(options.production); } })) .addCommand(new Command('core') .description('Deploy core.pame.ai internal platform') .option('--production', 'Deploy to production environment') .option('--use-sdk', 'Use Vercel SDK for enhanced deployment', false) .action(async (options) => { if (options.useSdk) { await deployPlatformWithSDK('core', 'pame-core', options.production, { RESTRICTED_ACCESS: 'true' }); } else { await deployCore(options.production); } })) .addCommand(new Command('store') .description('Deploy store.pame.ai marketplace platform') .option('--production', 'Deploy to production environment') .option('--use-sdk', 'Use Vercel SDK for enhanced deployment', false) .action(async (options) => { if (options.useSdk) { await deployPlatformWithSDK('store', 'pame-store', options.production); } else { await deployStore(options.production); } })) .addCommand(new Command('mcp') .description('Deploy mcp.pame.ai MCP server for ChatGPT integration') .option('--production', 'Deploy to production environment') .option('--use-sdk', 'Use Vercel SDK for enhanced deployment', false) .action(async (options) => { if (options.useSdk) { await deployPlatformWithSDK('mcp', 'pame-mcp', options.production); } else { await deployMCP(options.production); } })); async function deployWWW(production = false) { console.log('๐ŸŒ Deploying www.pame.ai marketing website...'); const projectPath = process.cwd(); // Check if we're in the correct directory if (!fs.existsSync(path.join(projectPath, 'app')) || !fs.existsSync(path.join(projectPath, 'package.json'))) { console.error('โŒ Project directory not found. Please run from the root pame.ai directory'); process.exit(1); } try { console.log(`๐Ÿ“‚ Working in: ${projectPath}`); // Link to the pame-www project console.log('๐Ÿ”— Linking to pame-www project...'); execSync('vercel link --yes --project pame-www', { stdio: 'inherit' }); // Create www-specific vercel config const wwwVercelConfig = { version: 2, alias: production ? ['www.pame.ai', 'pame.ai'] : [], regions: ['iad1'], buildCommand: 'npm run build', outputDirectory: '.next', framework: 'nextjs', env: { NEXT_PUBLIC_PLATFORM: 'www', NEXT_PUBLIC_API_URL: 'https://api.pame.ai' }, rewrites: [ // Block access to app routes { source: '/saas/(.*)', destination: '/404' }, { source: '/core/(.*)', destination: '/404' }, { source: '/api/saas/(.*)', destination: '/404' }, { source: '/api/core/(.*)', destination: '/404' } ] }; // Write config file fs.writeFileSync('vercel-www.json', JSON.stringify(wwwVercelConfig, null, 2)); console.log('๐Ÿ“ฆ Installing dependencies...'); execSync('npm install', { stdio: 'inherit' }); console.log('๐Ÿ—๏ธ Building marketing website...'); execSync('npm run build', { stdio: 'inherit' }); console.log('โ˜๏ธ Deploying marketing website to www.pame.ai...'); // Deploy to the linked project const deployCmd = production ? 'vercel --prod --yes -A vercel-www.json' : 'vercel --yes -A vercel-www.json'; console.log(`๐Ÿ“‹ Using config: vercel-www.json`); console.log(`๐Ÿš€ Running: ${deployCmd}`); execSync(deployCmd, { stdio: 'inherit' }); if (production) { console.log('๐Ÿ”— Adding custom domains...'); try { execSync('vercel domains add www.pame.ai --scope=getaifactory', { stdio: 'inherit' }); execSync('vercel domains add pame.ai --scope=getaifactory', { stdio: 'inherit' }); } catch (error) { console.log('โ„น๏ธ Domains may already exist or need manual configuration in Vercel dashboard'); } } console.log('โœ… www.pame.ai marketing website deployed successfully!'); console.log('๐ŸŒ Visit: https://www.pame.ai'); // Clean up fs.unlinkSync('vercel-www.json'); console.log('๐Ÿงน Cleaned up temporary config file'); } catch (error) { console.error('โŒ WWW deployment failed:', error); process.exit(1); } } async function deployApp(production = false) { console.log('๐Ÿ” Deploying app.pame.ai developer platform...'); const projectPath = process.cwd(); // Check if we're in the correct directory if (!fs.existsSync(path.join(projectPath, 'app')) || !fs.existsSync(path.join(projectPath, 'package.json'))) { console.error('โŒ Project directory not found. Please run from the root pame.ai directory'); process.exit(1); } try { console.log(`๐Ÿ“‚ Working in: ${projectPath}`); // Link to the pame-app project console.log('๐Ÿ”— Linking to pame-app project...'); execSync('vercel link --yes --project pame-app', { stdio: 'inherit' }); // Create app-specific vercel config const appVercelConfig = { version: 2, alias: production ? ['app.pame.ai'] : [], regions: ['iad1'], buildCommand: 'npm run build', outputDirectory: '.next', framework: 'nextjs', env: { NEXT_PUBLIC_PLATFORM: 'app', NEXT_PUBLIC_API_URL: 'https://api.pame.ai', ENABLE_AUTH: 'true' }, rewrites: [ // Block access to other platforms { source: '/core/(.*)', destination: '/404' } ], functions: { 'app/api/**': { maxDuration: 60 } } }; // Write config file fs.writeFileSync('vercel-app.json', JSON.stringify(appVercelConfig, null, 2)); console.log('๐Ÿ“ฆ Installing dependencies...'); execSync('npm install', { stdio: 'inherit' }); console.log('๐Ÿ—๏ธ Building developer platform...'); execSync('npm run build', { stdio: 'inherit' }); console.log('โ˜๏ธ Deploying developer platform to app.pame.ai...'); // Deploy to the linked project const deployCmd = production ? 'vercel --prod --yes -A vercel-app.json' : 'vercel --yes -A vercel-app.json'; console.log(`๐Ÿ“‹ Using config: vercel-app.json`); console.log(`๐Ÿš€ Running: ${deployCmd}`); execSync(deployCmd, { stdio: 'inherit' }); if (production) { console.log('๐Ÿ”— Adding custom domain app.pame.ai...'); try { execSync('vercel domains add app.pame.ai --scope=getaifactory', { stdio: 'inherit' }); } catch (error) { console.log('โ„น๏ธ Domain may already exist or need manual configuration in Vercel dashboard'); } } console.log('โœ… app.pame.ai developer platform deployed successfully!'); console.log('๐ŸŒ Visit: https://app.pame.ai'); console.log('๐Ÿ” Login with Google OAuth or use pame login from CLI'); // Clean up fs.unlinkSync('vercel-app.json'); console.log('๐Ÿงน Cleaned up temporary config file'); } catch (error) { console.error('โŒ App deployment failed:', error); process.exit(1); } } async function deployCore(production = false) { console.log('๐Ÿ›ก๏ธ Deploying core.pame.ai internal platform...'); const projectPath = process.cwd(); // Check if we're in the correct directory if (!fs.existsSync(path.join(projectPath, 'app')) || !fs.existsSync(path.join(projectPath, 'package.json'))) { console.error('โŒ Project directory not found. Please run from the root pame.ai directory'); process.exit(1); } try { console.log(`๐Ÿ“‚ Working in: ${projectPath}`); // Link to the pame-core project console.log('๐Ÿ”— Linking to pame-core project...'); execSync('vercel link --yes --project pame-core', { stdio: 'inherit' }); // Create core-specific vercel config const coreVercelConfig = { version: 2, alias: production ? ['core.pame.ai'] : [], regions: ['iad1'], buildCommand: 'npm run build', outputDirectory: '.next', framework: 'nextjs', env: { NEXT_PUBLIC_PLATFORM: 'core', NEXT_PUBLIC_API_URL: 'https://api.pame.ai', ENABLE_AUTH: 'true', RESTRICTED_ACCESS: 'true' }, rewrites: [ // Core platform routes { source: '/', destination: '/core' }, { source: '/login', destination: '/core/login' }, { source: '/cli-auth', destination: '/core/cli-auth' }, { source: '/dashboard', destination: '/core/dashboard' }, // API routes { source: '/api/(.*)', destination: '/api/core/$1' }, // Block access to other platforms { source: '/saas/(.*)', destination: '/404' }, { source: '/app/(.*)', destination: '/404' } ], functions: { 'app/api/**': { maxDuration: 60 } }, headers: [ { source: '/(.*)', headers: [ { key: 'X-Content-Type-Options', value: 'nosniff' }, { key: 'X-Frame-Options', value: 'DENY' }, { key: 'X-XSS-Protection', value: '1; mode=block' } ] } ] }; // Write config file fs.writeFileSync('vercel-core.json', JSON.stringify(coreVercelConfig, null, 2)); console.log('๐Ÿ“ฆ Installing dependencies...'); execSync('npm install', { stdio: 'inherit' }); console.log('๐Ÿ—๏ธ Building core platform...'); execSync('npm run build', { stdio: 'inherit' }); console.log('โ˜๏ธ Deploying core platform to core.pame.ai...'); // Deploy to the linked project const deployCmd = production ? 'vercel --prod --yes -A vercel-core.json' : 'vercel --yes -A vercel-core.json'; console.log(`๐Ÿ“‹ Using config: vercel-core.json`); console.log(`๐Ÿš€ Running: ${deployCmd}`); execSync(deployCmd, { stdio: 'inherit' }); if (production) { console.log('๐Ÿ”— Adding custom domain core.pame.ai...'); try { execSync('vercel domains add core.pame.ai --scope=getaifactory', { stdio: 'inherit' }); } catch (error) { console.log('โ„น๏ธ Domain may already exist or need manual configuration in Vercel dashboard'); } } console.log('โœ… core.pame.ai platform deployed successfully!'); console.log('๐ŸŒ Visit: https://core.pame.ai'); console.log('๐Ÿ” Core team access only - Login with: alec@getaifactory.com / 1234'); console.log('๐Ÿ›ก๏ธ Secured with role-based access control'); // Clean up fs.unlinkSync('vercel-core.json'); console.log('๐Ÿงน Cleaned up temporary config file'); } catch (error) { console.error('โŒ Core deployment failed:', error); process.exit(1); } } async function deployStore(production = false) { console.log('๐Ÿช Deploying store.pame.ai marketplace platform...'); const projectPath = process.cwd(); // Check if we're in the correct directory if (!fs.existsSync(path.join(projectPath, 'app')) || !fs.existsSync(path.join(projectPath, 'package.json'))) { console.error('โŒ Project directory not found. Please run from the root pame.ai directory'); process.exit(1); } try { console.log(`๐Ÿ“‚ Working in: ${projectPath}`); // Link to the pame-store project console.log('๐Ÿ”— Linking to pame-store project...'); execSync('vercel link --yes --project pame-store', { stdio: 'inherit' }); // Create store-specific vercel config const storeVercelConfig = { version: 2, alias: production ? ['store.pame.ai'] : [], regions: ['iad1'], buildCommand: 'npm run build', outputDirectory: '.next', framework: 'nextjs', env: { NEXT_PUBLIC_PLATFORM: 'store', NEXT_PUBLIC_API_URL: 'https://api.pame.ai', ENABLE_AUTH: 'true' }, rewrites: [ // Store-specific rewrites { source: '/business/:path*', destination: '/store/:path*' }, { source: '/marketplace/:path*', destination: '/store/:path*' }, // Block other platform routes { source: '/saas/(.*)', destination: '/404' }, { source: '/core/(.*)', destination: '/404' }, { source: '/api/core/(.*)', destination: '/404' } ] }; // Write config file fs.writeFileSync('vercel-store.json', JSON.stringify(storeVercelConfig, null, 2)); console.log('๐Ÿ“ฆ Installing dependencies...'); execSync('npm install', { stdio: 'inherit' }); console.log('๐Ÿ—๏ธ Building marketplace platform...'); execSync('npm run build', { stdio: 'inherit' }); console.log('โ˜๏ธ Deploying marketplace to store.pame.ai...'); // Deploy to the linked project const deployCmd = production ? 'vercel --prod --yes -A vercel-store.json' : 'vercel --yes -A vercel-store.json'; console.log(`๐Ÿ“‹ Using config: vercel-store.json`); console.log(`๐Ÿš€ Running: ${deployCmd}`); execSync(deployCmd, { stdio: 'inherit' }); if (production) { console.log('๐Ÿ”— Adding custom domain store.pame.ai...'); try { execSync('vercel domains add store.pame.ai --scope=getaifactory', { stdio: 'inherit' }); } catch (error) { console.log('โ„น๏ธ Domain may already exist or need manual configuration in Vercel dashboard'); } } console.log('โœ… store.pame.ai marketplace deployed successfully!'); console.log('๐Ÿช Visit: https://store.pame.ai'); console.log('๐Ÿ“ฆ Features: AI app marketplace, discovery, vetting, and distribution'); console.log('๐Ÿ”’ Compliance: SOC2, ISO 27001, GDPR ready'); // Clean up fs.unlinkSync('vercel-store.json'); console.log('๐Ÿงน Cleaned up temporary config file'); } catch (error) { console.error('โŒ Store deployment failed:', error); process.exit(1); } } async function deployMCP(production = false) { const environment = production ? 'production' : 'staging'; console.log(chalk.blue(`๐Ÿ”Œ Deploying MCP server to ${environment}...`)); try { // Change to MCP project directory const mcpDir = path.join(process.cwd(), 'mcp-pame-ai'); if (!fs.existsSync(mcpDir)) { throw new Error('MCP project directory not found. Run this from the project root.'); } process.chdir(mcpDir); // Install dependencies console.log(chalk.gray('๐Ÿ“ฆ Installing dependencies...')); execSync('npm install', { stdio: 'inherit' }); // Build the project console.log(chalk.gray('๐Ÿ—๏ธ Building MCP server...')); execSync('npm run build', { stdio: 'inherit' }); // Deploy to Vercel const deployCommand = production ? 'vercel --prod' : 'vercel'; console.log(chalk.gray(`๐Ÿš€ Deploying to Vercel (${environment})...`)); execSync(deployCommand, { stdio: 'inherit' }); console.log(chalk.green(`โœ… MCP server deployed successfully to ${environment}!`)); console.log(chalk.cyan(`๐Ÿ”— URL: https://mcp.pame.ai${production ? '' : '-staging'}`)); console.log(chalk.gray('๐Ÿ“‹ MCP Connector URL: https://mcp.pame.ai/sse/')); } catch (error) { console.error(chalk.red(`โŒ MCP deployment failed: ${error.message}`)); process.exit(1); } finally { // Return to original directory process.chdir('..'); } } async function deploySubdomain(subdomain, production = false, skipDns = false) { console.log(`๐Ÿš€ Deploying ${subdomain}.pame.ai...`); const projectPath = process.cwd(); const projectName = `pame-${subdomain}`; // Check if we're in the correct directory if (!fs.existsSync(path.join(projectPath, 'app')) || !fs.existsSync(path.join(projectPath, 'package.json'))) { console.error('โŒ Project directory not found. Please run from the root pame.ai directory'); process.exit(1); } try { console.log(`๐Ÿ“‚ Working in: ${projectPath}`); // Link to the subdomain project console.log(`๐Ÿ”— Linking to ${projectName} project...`); try { execSync(`vercel link --yes --project ${projectName}`, { stdio: 'inherit' }); } catch (error) { console.error(`โŒ Failed to link to project ${projectName}. Make sure it exists.`); console.log(`๐Ÿ’ก Create the project first with: pame-core subdomain create ${subdomain}`); process.exit(1); } // Create subdomain-specific vercel config const subdomainVercelConfig = { version: 2, alias: production ? [`${subdomain}.pame.ai`] : [], regions: ['iad1'], buildCommand: 'npm run build', outputDirectory: '.next', framework: 'nextjs', env: { NEXT_PUBLIC_PLATFORM: subdomain, NEXT_PUBLIC_API_URL: 'https://api.pame.ai', ENABLE_AUTH: 'true' }, rewrites: [ // Block access to other platform routes { source: '/core/(.*)', destination: '/404' }, { source: '/saas/(.*)', destination: '/404' } ], functions: { 'app/api/**': { maxDuration: 60 } } }; // Write config file const configFile = `vercel-${subdomain}.json`; fs.writeFileSync(configFile, JSON.stringify(subdomainVercelConfig, null, 2)); console.log('๐Ÿ“ฆ Installing dependencies...'); execSync('npm install', { stdio: 'inherit' }); console.log(`๐Ÿ—๏ธ Building ${subdomain} platform...`); execSync('npm run build', { stdio: 'inherit' }); console.log(`โ˜๏ธ Deploying to ${subdomain}.pame.ai...`); // Deploy to the linked project const deployCmd = production ? `vercel --prod --yes -A ${configFile}` : `vercel --yes -A ${configFile}`; console.log(`๐Ÿ“‹ Using config: ${configFile}`); console.log(`๐Ÿš€ Running: ${deployCmd}`); execSync(deployCmd, { stdio: 'inherit' }); if (production) { console.log(`๐Ÿ”— Adding custom domain ${subdomain}.pame.ai...`); try { execSync(`vercel domains add ${subdomain}.pame.ai --scope=getaifactory`, { stdio: 'inherit' }); } catch (error) { console.log('โ„น๏ธ Domain may already exist or need manual configuration in Vercel dashboard'); } // Verify DNS if not skipped if (!skipDns) { console.log('๐Ÿ” Verifying DNS configuration...'); try { const { GoDaddyManager } = await import('../services/godaddy-manager.js'); const godaddyManager = new GoDaddyManager(); // Get current DNS records const cnameRecords = await godaddyManager.getRecords('CNAME', subdomain); const txtRecords = await godaddyManager.getRecords('TXT', '_vercel'); if (cnameRecords.length === 0) { console.log(`โš ๏ธ No CNAME record found for ${subdomain}.pame.ai`); console.log(`๐Ÿ’ก Set up DNS with: pame-core subdomain create ${subdomain}`); } const relevantTxtRecords = txtRecords.filter(record => record.data.includes(`${subdomain}.pame.ai`)); if (relevantTxtRecords.length === 0) { console.log(`โš ๏ธ No TXT verification record found for ${subdomain}.pame.ai`); console.log(`๐Ÿ’ก Set up DNS with: pame-core subdomain create ${subdomain}`); } if (cnameRecords.length > 0 && relevantTxtRecords.length > 0) { console.log('โœ… DNS configuration looks good'); } } catch (error) { console.log('โš ๏ธ Could not verify DNS configuration:', error instanceof Error ? error.message : String(error)); } } } console.log(`โœ… ${subdomain}.pame.ai deployed successfully!`); console.log(`๐ŸŒ Visit: https://${subdomain}.pame.ai`); console.log(`๐Ÿ”ง Project: ${projectName}`); // Clean up fs.unlinkSync(configFile); console.log('๐Ÿงน Cleaned up temporary config file'); } catch (error) { console.error(`โŒ ${subdomain} deployment failed:`, error instanceof Error ? error.message : String(error)); process.exit(1); } } // New SDK-based deployment functions async function deployAllWithSDK(production = false) { try { const deploymentSDK = new VercelDeploymentSDK(); const results = await deploymentSDK.deployAllPlatforms(production); // Enhanced testing after deployment console.log(chalk.blue('\n๐Ÿ” Testing deployed endpoints...\n')); for (const result of results) { if (result.success && result.deployment.url) { await deploymentSDK.testEndpoint(result.deployment.url); } } const successCount = results.filter(r => r.success).length; console.log(chalk.green(`\n๐ŸŽ‰ SDK deployment completed: ${successCount}/${results.length} successful`)); } catch (error) { console.error(chalk.red('โŒ SDK deployment failed:'), error instanceof Error ? error.message : String(error)); process.exit(1); } } async function deployPlatformWithSDK(platform, projectName, production = false, envVars = {}) { const sdk = new VercelDeploymentSDK(); const config = { platform, projectName, production, envVars: { NEXT_PUBLIC_PLATFORM: platform, NEXT_PUBLIC_API_URL: 'https://api.pame.ai', ...envVars } }; console.log(chalk.blue(`๐Ÿš€ Deploying ${platform}.pame.ai using Vercel SDK...`)); try { const result = await sdk.deploy(config); console.log(chalk.green(`โœ… ${platform}.pame.ai deployed successfully!`)); console.log(chalk.cyan(`๐Ÿ”— URL: ${result.url}`)); if (platform === 'mcp') { console.log(chalk.gray('๐Ÿ“‹ MCP Connector URL: https://mcp.pame.ai/sse/')); } } catch (error) { console.error(chalk.red(`โŒ ${platform} deployment failed: ${error.message}`)); throw error; } } // Calendar integration function //# sourceMappingURL=deploy.js.map