156 lines
5.0 KiB
JavaScript
156 lines
5.0 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
import { program } from 'commander';
|
|
import chalk from 'chalk';
|
|
import prompts from 'prompts';
|
|
import ora from 'ora';
|
|
import fs from 'fs-extra';
|
|
import path from 'path';
|
|
import { fileURLToPath } from 'url';
|
|
import { execSync } from 'child_process';
|
|
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __dirname = path.dirname(__filename);
|
|
|
|
const TEMPLATE_DIR = path.join(__dirname, 'template');
|
|
|
|
async function main() {
|
|
console.log(chalk.bold.cyan('\n🤖 Create Agentic App\n'));
|
|
|
|
program
|
|
.name('create-agentic-app')
|
|
.description('Scaffold a new agentic AI application')
|
|
.argument('[project-directory]', 'Project directory name (use "." for current directory)')
|
|
.parse(process.argv);
|
|
|
|
const args = program.args;
|
|
let projectDir = args[0] || '.';
|
|
|
|
// Resolve the target directory
|
|
const targetDir = path.resolve(process.cwd(), projectDir);
|
|
const projectName = projectDir === '.' ? path.basename(targetDir) : projectDir;
|
|
|
|
// Check if directory exists and is not empty
|
|
if (fs.existsSync(targetDir)) {
|
|
const files = fs.readdirSync(targetDir);
|
|
if (files.length > 0 && projectDir !== '.') {
|
|
const { proceed } = await prompts({
|
|
type: 'confirm',
|
|
name: 'proceed',
|
|
message: `Directory "${projectDir}" is not empty. Continue anyway?`,
|
|
initial: false
|
|
});
|
|
|
|
if (!proceed) {
|
|
console.log(chalk.yellow('Cancelled.'));
|
|
process.exit(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Prompt for package manager
|
|
const { packageManager } = await prompts({
|
|
type: 'select',
|
|
name: 'packageManager',
|
|
message: 'Which package manager do you want to use?',
|
|
choices: [
|
|
{ title: 'pnpm (recommended)', value: 'pnpm' },
|
|
{ title: 'npm', value: 'npm' },
|
|
{ title: 'yarn', value: 'yarn' }
|
|
],
|
|
initial: 0
|
|
});
|
|
|
|
if (!packageManager) {
|
|
console.log(chalk.yellow('Cancelled.'));
|
|
process.exit(0);
|
|
}
|
|
|
|
console.log();
|
|
const spinner = ora('Creating project...').start();
|
|
|
|
try {
|
|
// Create target directory if it doesn't exist
|
|
fs.ensureDirSync(targetDir);
|
|
|
|
// Copy template files
|
|
spinner.text = 'Copying template files...';
|
|
await fs.copy(TEMPLATE_DIR, targetDir, {
|
|
overwrite: false,
|
|
errorOnExist: false,
|
|
filter: (src) => {
|
|
// Skip node_modules, .next, and other build artifacts
|
|
const relativePath = path.relative(TEMPLATE_DIR, src);
|
|
return !relativePath.includes('node_modules') &&
|
|
!relativePath.includes('.next') &&
|
|
!relativePath.includes('.git') &&
|
|
!relativePath.includes('pnpm-lock.yaml') &&
|
|
!relativePath.includes('package-lock.json') &&
|
|
!relativePath.includes('yarn.lock') &&
|
|
!relativePath.includes('tsconfig.tsbuildinfo');
|
|
}
|
|
});
|
|
|
|
// Copy .env.example to .env if it doesn't exist
|
|
const envExamplePath = path.join(targetDir, 'env.example');
|
|
const envPath = path.join(targetDir, '.env');
|
|
|
|
if (fs.existsSync(envExamplePath) && !fs.existsSync(envPath)) {
|
|
spinner.text = 'Setting up environment file...';
|
|
await fs.copy(envExamplePath, envPath);
|
|
}
|
|
|
|
// Update package.json name if not current directory
|
|
if (projectDir !== '.') {
|
|
const packageJsonPath = path.join(targetDir, 'package.json');
|
|
if (fs.existsSync(packageJsonPath)) {
|
|
const packageJson = await fs.readJson(packageJsonPath);
|
|
packageJson.name = projectName;
|
|
await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
|
|
}
|
|
}
|
|
|
|
spinner.succeed(chalk.green('Project created successfully!'));
|
|
|
|
// Install dependencies
|
|
console.log();
|
|
const installSpinner = ora(`Installing dependencies with ${packageManager}...`).start();
|
|
|
|
try {
|
|
const installCmd = packageManager === 'yarn' ? 'yarn install' : `${packageManager} install`;
|
|
execSync(installCmd, {
|
|
cwd: targetDir,
|
|
stdio: 'pipe'
|
|
});
|
|
installSpinner.succeed(chalk.green('Dependencies installed!'));
|
|
} catch (error) {
|
|
installSpinner.fail(chalk.red('Failed to install dependencies'));
|
|
console.log(chalk.yellow(`\nPlease run "${packageManager} install" manually.\n`));
|
|
}
|
|
|
|
// Display next steps
|
|
console.log();
|
|
console.log(chalk.bold.green('✨ Your agentic app is ready!\n'));
|
|
console.log(chalk.bold('Next steps:\n'));
|
|
|
|
if (projectDir !== '.') {
|
|
console.log(chalk.cyan(` cd ${projectDir}`));
|
|
}
|
|
|
|
console.log(chalk.cyan(' 1. Update the .env file with your API keys and database credentials'));
|
|
console.log(chalk.cyan(` 2. Start the database: docker compose up -d`));
|
|
console.log(chalk.cyan(` 3. Run database migrations: ${packageManager} run db:migrate`));
|
|
console.log(chalk.cyan(` 4. Start the development server: ${packageManager} run dev`));
|
|
|
|
console.log();
|
|
console.log(chalk.gray('For more information, check out the README.md file.\n'));
|
|
|
|
} catch (error) {
|
|
spinner.fail(chalk.red('Failed to create project'));
|
|
console.error(error);
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
main().catch(console.error);
|