Files
agentic-coding-starter-kit/create-agentic-app/index.js
Leon van Zyl ec929ab918 npx command
2025-11-02 08:45:37 +02:00

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);