UNPKG

aios-fullstack

Version:

AIOS-FULLSTACK: AI-Orchestrated System for Full Stack Development - Modern cross-platform CLI with interactive wizard

391 lines (340 loc) 15.3 kB
#!/usr/bin/env node /** * AIOS-FullStack Installation Wizard v4 * Based on the original beautiful visual design with ASCII art * Version: 1.1.5 */ const path = require('path'); const fs = require('fs'); const fse = require('fs-extra'); const yaml = require('yaml'); const { execSync } = require('child_process'); const inquirer = require('inquirer'); const chalk = require('chalk'); // ASCII Art Banner (3D style like the original) const BANNER = chalk.cyan(` ▄████████ ▄█ ▄██████▄ ▄████████ ▄████████ ███ █▄ ▄█ ▄█ ▄████████ ███ ▄████████ ▄████████ ▄█ ▄█▄ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ▀█████████▄ ███ ███ ███ ███ ███ ▄███▀ ███ ███ ███▌ ███ ███ ███ █▀ ███ █▀ ███ ███ ███ ███ ███ █▀ ▀███▀▀██ ███ ███ ███ █▀ ███▐██▀ ███ ███ ███▌ ███ ███ ███ ▄███▄▄▄ ███ ███ ███ ███ ███ ███ ▀ ███ ███ ███ ▄█████▀ ▀███████████ ███▌ ███ ███ ▀███████████ ▀▀███▀▀▀ ███ ███ ███ ███ ▀███████████ ███ ▀███████████ ███ ▀▀█████▄ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ █▄ ███▐██▄ ███ ███ ███ ███ ███ ▄█ ███ ███ ███ ███ ███▌ ▄ ███▌ ▄ ▄█ ███ ███ ███ ███ ███ ███ ███ ▀███▄ ███ █▀ █▀ ▀██████▀ ▄████████▀ ███ ████████▀ █████▄▄██ █████▄▄██ ▄████████▀ ▄████▀ ███ █▀ ████████▀ ███ ▀█▀ ▀ ▀ ▀ `); const SUBTITLE = chalk.magenta('🚀 Universal AI Agent Framework for Any Domain'); const VERSION = chalk.yellow('✨ Installer v4.31.0'); /** * Smart path resolution for AIOS Core modules */ function resolveAiosCoreModule(modulePath) { const aiosCoreModule = path.join(__dirname, '..', '.aios-core', modulePath); const moduleExists = fs.existsSync(aiosCoreModule + '.js') || fs.existsSync(aiosCoreModule + '/index.js') || fs.existsSync(aiosCoreModule); if (!moduleExists) { throw new Error( `Cannot find AIOS Core module: ${modulePath}\n` + `Searched: ${aiosCoreModule}\n` + `Please ensure aios-fullstack is installed correctly.` ); } return require(aiosCoreModule); } // Load AIOS Core modules const { detectRepositoryContext } = resolveAiosCoreModule('utils/repository-detector'); const { ClickUpAdapter } = resolveAiosCoreModule('utils/pm-adapters/clickup-adapter'); const { GitHubProjectsAdapter } = resolveAiosCoreModule('utils/pm-adapters/github-adapter'); const { JiraAdapter } = resolveAiosCoreModule('utils/pm-adapters/jira-adapter'); async function main() { console.clear(); // Display beautiful banner console.log(BANNER); console.log(SUBTITLE); console.log(VERSION); console.log(''); console.log(chalk.gray('═'.repeat(80))); console.log(''); const projectRoot = process.cwd(); let context = detectRepositoryContext(); // Setup prerequisites if needed if (!context) { console.log(chalk.blue('⚙️ Setting up project prerequisites...\n')); // Check for git repository let hasGit = false; try { execSync('git rev-parse --git-dir', { cwd: projectRoot, stdio: 'ignore' }); hasGit = true; } catch (err) { // Not a git repo } if (!hasGit) { try { execSync('git init', { cwd: projectRoot, stdio: 'ignore' }); console.log(chalk.green('✓') + ' Git repository initialized'); } catch (err) { console.error(chalk.red('✗') + ' Failed to initialize git repository'); process.exit(1); } } // Check for package.json const packageJsonPath = path.join(projectRoot, 'package.json'); if (!fs.existsSync(packageJsonPath)) { const dirName = path.basename(projectRoot); const defaultPackage = { name: dirName.toLowerCase().replace(/\s+/g, '-'), version: '1.0.0', description: 'AIOS-FullStack project', main: 'index.js', scripts: { test: 'echo "Error: no test specified" && exit 1' }, keywords: [], author: '', license: 'ISC' }; fs.writeFileSync(packageJsonPath, JSON.stringify(defaultPackage, null, 2)); console.log(chalk.green('✓') + ' package.json created'); } console.log(chalk.green('✓') + ' Prerequisites ready\n'); // Try to detect context again context = detectRepositoryContext(); // If still no context, create minimal one if (!context) { const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')); context = { projectRoot, packageName: packageJson.name, packageVersion: packageJson.version, repositoryUrl: 'local-repository', frameworkLocation: path.join(__dirname, '..') }; } } console.log(chalk.cyan('📦 Package:') + ` ${context.packageName}`); console.log(''); // Step 1: Installation Mode console.log(chalk.gray('─'.repeat(80))); const { installMode } = await inquirer.prompt([ { type: 'list', name: 'installMode', message: chalk.white('How are you using AIOS-FullStack?'), choices: [ { name: ' Using AIOS in a project ' + chalk.gray('(Framework files added to .gitignore)'), value: 'project-development' }, { name: ' Developing AIOS framework itself ' + chalk.gray('(Framework files are source code)'), value: 'framework-development' } ] } ]); // Save installation config const config = { installation: { mode: installMode, detected_at: new Date().toISOString() }, repository: { url: context.repositoryUrl, auto_detect: true }, framework: { source: installMode === 'framework-development' ? 'local' : 'npm', version: context.packageVersion, location: context.frameworkLocation }, git_ignore_rules: { mode: installMode, ignore_framework_files: installMode === 'project-development' } }; const configPath = path.join(context.projectRoot, '.aios-installation-config.yaml'); fs.writeFileSync(configPath, yaml.stringify(config)); // Update .gitignore updateGitIgnore(installMode, context.projectRoot); // Step 2: PM Tool console.log(''); const { pmTool } = await inquirer.prompt([ { type: 'list', name: 'pmTool', message: chalk.white('Do you use a project management tool?'), choices: [ { name: ' None (local YAML files only) ' + chalk.gray('- Recommended'), value: 'local' }, { name: ' ClickUp ' + chalk.gray('- Requires API token'), value: 'clickup' }, { name: ' GitHub Projects ' + chalk.gray('- Uses gh auth'), value: 'github-projects' }, { name: ' Jira ' + chalk.gray('- Requires API token'), value: 'jira' } ] } ]); // Save PM config savePMConfig(pmTool, {}, context.projectRoot); // Step 3: IDE Selection (CHECKBOX with instructions) console.log(''); console.log(chalk.gray('─'.repeat(80))); console.log(chalk.dim(' Press <space> to select, <a> to toggle all, <i> to invert selection, and <enter> to proceed')); console.log(''); const { ides } = await inquirer.prompt([ { type: 'checkbox', name: 'ides', message: chalk.white('Which IDE(s) will you use?'), choices: [ { name: ' Claude Code ' + chalk.blue('(v1.0)') + chalk.gray(' - Recommended'), value: 'claude' }, { name: ' Windsurf ' + chalk.blue('(v1.0)'), value: 'windsurf' }, { name: ' Cursor ' + chalk.blue('(v0.43)'), value: 'cursor' }, { name: ' Skip IDE setup', value: 'none' } ], validate: function(answer) { if (answer.length < 1) { return 'You must choose at least one option.'; } return true; } } ]); // Step 4: Copy AIOS Core files console.log(''); console.log(chalk.blue('📦 Installing AIOS Core files...')); const sourceCoreDir = path.join(context.frameworkLocation, '.aios-core'); const targetCoreDir = path.join(context.projectRoot, '.aios-core'); if (fs.existsSync(sourceCoreDir)) { await fse.copy(sourceCoreDir, targetCoreDir); console.log(chalk.green('✓') + ' AIOS Core files installed ' + chalk.gray('(11 agents, 68 tasks, 23 templates)')); } else { console.error(chalk.red('✗') + ' AIOS Core files not found'); process.exit(1); } // Copy IDE rules if IDE was selected if (!ides.includes('none')) { const ideRulesMap = { 'claude': { source: 'claude-rules.md', target: '.claude/CLAUDE.md' }, 'windsurf': { source: 'windsurf-rules.md', target: '.windsurf/rules.md' }, 'cursor': { source: 'cursor-rules.md', target: '.cursor/rules.md' } }; for (const ide of ides) { if (ide !== 'none' && ideRulesMap[ide]) { const ideConfig = ideRulesMap[ide]; const sourceRules = path.join(targetCoreDir, 'templates', 'ide-rules', ideConfig.source); const targetRules = path.join(context.projectRoot, ideConfig.target); if (fs.existsSync(sourceRules)) { await fse.ensureDir(path.dirname(targetRules)); await fse.copy(sourceRules, targetRules); console.log(chalk.green('✓') + ` ${ide.charAt(0).toUpperCase() + ide.slice(1)} rules installed`); } } } } // Step 5: Expansion Packs (CHECKBOX with visual) const sourceExpansionDir = path.join(context.frameworkLocation, 'expansion-packs'); const availablePacks = []; if (fs.existsSync(sourceExpansionDir)) { const packs = fs.readdirSync(sourceExpansionDir).filter(f => fs.statSync(path.join(sourceExpansionDir, f)).isDirectory() ); availablePacks.push(...packs); } if (availablePacks.length > 0) { console.log(''); console.log(chalk.gray('─'.repeat(80))); console.log(chalk.dim(' Press <space> to select, <a> to toggle all, <i> to invert selection, and <enter> to proceed')); console.log(''); const { expansionPacks } = await inquirer.prompt([ { type: 'checkbox', name: 'expansionPacks', message: chalk.white('Select expansion packs to install (optional)'), choices: availablePacks.map(pack => ({ name: ' ' + pack, value: pack })) } ]); if (expansionPacks.length > 0) { console.log(''); console.log(chalk.blue('📦 Installing expansion packs...')); const targetExpansionDir = path.join(context.projectRoot, 'expansion-packs'); for (const pack of expansionPacks) { const sourcePack = path.join(sourceExpansionDir, pack); const targetPack = path.join(targetExpansionDir, pack); await fse.copy(sourcePack, targetPack); console.log(chalk.green('✓') + ` Installed: ${pack}`); } } } // Summary console.log(''); console.log(chalk.gray('═'.repeat(80))); console.log(''); console.log(chalk.green.bold('✓ AIOS-FullStack installation complete! 🎉')); console.log(''); console.log(chalk.cyan('📋 Configuration Summary:')); console.log(' ' + chalk.dim('Mode: ') + installMode); console.log(' ' + chalk.dim('Repository: ') + context.repositoryUrl); console.log(' ' + chalk.dim('IDE(s): ') + (ides.includes('none') ? 'none' : ides.join(', '))); console.log(' ' + chalk.dim('PM Tool: ') + pmTool); console.log(''); console.log(chalk.cyan('📚 Next steps:')); console.log(' • Activate agents using @agent-name (e.g., @dev, @github-devops)'); console.log(' • Run ' + chalk.yellow('"aios --help"') + ' to see available commands'); console.log(' • Check documentation in ' + chalk.yellow('docs/') + ' directory'); console.log(''); console.log(chalk.gray('═'.repeat(80))); console.log(''); } /** * Updates .gitignore file based on installation mode */ function updateGitIgnore(mode, projectRoot) { const gitignorePath = path.join(projectRoot, '.gitignore'); let gitignore = ''; if (fs.existsSync(gitignorePath)) { gitignore = fs.readFileSync(gitignorePath, 'utf8'); } if (mode === 'project-development') { const frameworkRules = [ '', '# AIOS-FullStack Framework Files (auto-managed - do not edit)', '.aios-core/', 'node_modules/@aios/', 'outputs/minds/', '.aios-installation-config.yaml', '# End AIOS-FullStack auto-managed section', '' ]; const hasFrameworkSection = gitignore.includes('# AIOS-FullStack Framework Files'); if (!hasFrameworkSection) { gitignore += frameworkRules.join('\n'); fs.writeFileSync(gitignorePath, gitignore); } } } /** * Save PM configuration */ function savePMConfig(pmTool, config, projectRoot) { const pmConfigData = { pm_tool: { type: pmTool, configured_at: new Date().toISOString(), config: config }, sync_behavior: { auto_sync_on_status_change: true, create_tasks_on_story_creation: false, bidirectional_sync: false } }; const configPath = path.join(projectRoot, '.aios-pm-config.yaml'); fs.writeFileSync(configPath, yaml.stringify(pmConfigData)); } // Run installer with error handling main().catch((error) => { console.error(''); console.error(chalk.red('✗ Installation failed: ') + error.message); console.error(''); process.exit(1); });