Add CLI tool for CORRAD AF project setup, including environment configuration, dependency installation, and project initialization. Update repository URLs and enhance README with usage instructions.

This commit is contained in:
Zahirul Iman 2025-06-04 18:34:44 +08:00
parent 0a44bdde25
commit 14606f0ada
7 changed files with 868 additions and 6 deletions

6
.env.example Normal file
View File

@ -0,0 +1,6 @@
NUXT_ENV=
DATABASE_URL=
NUXT_ACCESS_TOKEN_SECRET=
NUXT_REFRESH_TOKEN_SECRET=
PORT=

View File

@ -56,7 +56,7 @@ Welcome to **corradAF**, a comprehensive Nuxt.js template designed for rapid app
## 📋 Prerequisites
- Node.js 18+
- Yarn or npm
- Yarn (preferred) or npm
- Database (PostgreSQL/MySQL recommended)
## 🚀 Quick Start
@ -64,7 +64,7 @@ Welcome to **corradAF**, a comprehensive Nuxt.js template designed for rapid app
### 1. Clone the Template
```bash
git clone <repository-url> your-project-name
git clone https://git.sena.my/corrad-software/corrad-af-2024.git your-project-name
cd your-project-name
```

11
cli-tool/.npmignore Normal file
View File

@ -0,0 +1,11 @@
# Development files
*.md
!README.md
# Logs
*.log
# Testing
test/
tests/
*.test.js

37
cli-tool/README.md Normal file
View File

@ -0,0 +1,37 @@
# CORRAD AF CLI Tool
🚀 **The fastest way to bootstrap your next project with CORRAD Application Framework**
## Quick Start
```bash
npx corradaf
```
## Features
- ✨ Beautiful ASCII welcome screen
- 🔐 Public/Internal project modes
- ⚙️ Automatic environment setup
- 🤖 Cursor AI rules integration
- 📦 Automatic dependency installation
- 🗄️ Prisma database setup
- 🎯 IDE auto-detection
## Usage
1. Run the CLI tool
2. Choose project type (Public/Internal)
3. Enter project name
4. Configure environment variables
5. Enjoy your new CORRAD AF project!
## Requirements
- Node.js 14+
- Git
- Internet connection
## License
MIT

768
cli-tool/index.js Normal file
View File

@ -0,0 +1,768 @@
#!/usr/bin/env node
console.log('🚀 Starting CORRAD AF CLI...');
const { execSync, spawn } = require('child_process');
const fs = require('fs');
const path = require('path');
const inquirer = require('inquirer');
const figlet = require('figlet');
const ora = require('ora');
const chalk = require('chalk');
const boxen = require('boxen');
const gradient = require('gradient-string');
const https = require('https');
const http = require('http');
// Configuration URLs - can be updated as needed
const ENV_CONFIG_URLS = {
internal: 'https://raw.githubusercontent.com/corradaf/env-configs/main/internal.env'
};
// Internal access token for secure env access
const INTERNAL_ACCESS_TOKEN = 'corrad_internal_2024_secure_token_af';
// Function to fetch content from URL with security
function fetchFromUrl(url, token = null) {
return new Promise((resolve, reject) => {
const client = url.startsWith('https') ? https : http;
const urlObj = new URL(url);
const options = {
hostname: urlObj.hostname,
port: urlObj.port,
path: urlObj.pathname + urlObj.search,
method: 'GET',
headers: {}
};
if (token) {
options.headers['Authorization'] = `Bearer ${token}`;
options.headers['X-Access-Token'] = token;
}
const req = client.request(options, (res) => {
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
if (res.statusCode === 200) {
resolve(data);
} else {
reject(new Error(`HTTP ${res.statusCode}: ${res.statusMessage}`));
}
});
});
req.on('error', (err) => {
reject(err);
});
req.end();
});
}
// Helper function to run shell commands with proper quoting
function runCommand(command, options = {}) {
try {
console.log(chalk.gray(`Running: ${command}`));
execSync(command, { stdio: 'inherit', ...options });
return true;
} catch (error) {
console.error(chalk.red(`Error: ${error.message}`));
return false;
}
}
// Helper function to properly quote project names with spaces
function escapeProjectName(projectName) {
// Use double quotes for Windows and Unix compatibility
return `"${projectName}"`;
}
// Helper function to run async commands
function runCommandAsync(command, args = [], options = {}) {
return new Promise((resolve, reject) => {
const child = spawn(command, args, { stdio: 'inherit', ...options });
child.on('close', (code) => {
if (code === 0) {
resolve(code);
} else {
reject(new Error(`Command failed with exit code ${code}`));
}
});
});
}
// Create progress bar animation
function createProgressBar(message, duration = 3000) {
return new Promise((resolve) => {
const spinner = ora({
text: message,
spinner: {
interval: 100,
frames: ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']
}
}).start();
let progress = 0;
const interval = setInterval(() => {
progress += 10;
spinner.text = `${message} ${progress}%`;
if (progress >= 100) {
clearInterval(interval);
spinner.succeed(chalk.green('✓ Setup complete!'));
resolve();
}
}, duration / 10);
});
}
// Clear screen and position cursor at top
function clearScreen() {
console.clear();
process.stdout.write('\x1b[H');
}
// Check if current directory has project files
function hasProjectFiles() {
const projectFiles = ['package.json', '.git', 'node_modules', 'src', 'pages', 'components'];
return projectFiles.some(file => fs.existsSync(file));
}
// Parse .env.example file and extract variables
function parseEnvExample(content) {
const lines = content.split('\n');
const envVars = [];
for (const line of lines) {
const trimmed = line.trim();
if (trimmed && !trimmed.startsWith('#') && trimmed.includes('=')) {
const [key, ...valueParts] = trimmed.split('=');
const value = valueParts.join('=').replace(/['"]/g, '');
const description = extractComment(line);
envVars.push({
key: key.trim(),
defaultValue: value.trim(),
description: description
});
}
}
return envVars;
}
// Extract comment from env line
function extractComment(line) {
const commentMatch = line.match(/#\s*(.+)$/);
return commentMatch ? commentMatch[1].trim() : '';
}
// Prompt for environment configurations
async function promptForEnvConfig(envVars, projectName) {
const envConfig = {};
console.log(chalk.cyan.bold('\n⚙ Environment Configuration'));
console.log(chalk.gray('Configure your project environment variables:\n'));
for (const envVar of envVars) {
let message = `${envVar.key}`;
if (envVar.description) {
message += chalk.gray(` (${envVar.description})`);
}
let defaultValue = envVar.defaultValue;
// Replace placeholder values
if (defaultValue.includes('${projectName}') || defaultValue.includes('your-project')) {
defaultValue = defaultValue.replace(/\${projectName}|your-project/g, projectName);
}
const { value } = await inquirer.prompt([
{
type: 'input',
name: 'value',
message: message + ':',
default: defaultValue,
validate: function(input) {
if (envVar.key.includes('SECRET') || envVar.key.includes('PASSWORD')) {
if (input.trim().length < 8) {
return 'Security values should be at least 8 characters long';
}
}
return true;
}
}
]);
envConfig[envVar.key] = value;
}
return envConfig;
}
// Main CLI function
async function main() {
try {
// Clear console and show welcome screen (only once)
clearScreen();
// Step 1: Show ASCII "CORRAD AF" with gradient (only once)
const asciiText = figlet.textSync('CORRAD AF', {
font: 'Big',
horizontalLayout: 'default',
verticalLayout: 'default'
});
console.log(gradient.rainbow(asciiText));
console.log(boxen(
chalk.white.bold('🚀 Welcome to CORRAD Application Framework CLI\n') +
chalk.gray('The fastest way to bootstrap your next project'),
{
padding: 1,
margin: 1,
borderStyle: 'round',
borderColor: 'cyan'
}
));
// Check for existing project files
const hasFiles = hasProjectFiles();
// Step 2: Ask about project setup
console.log(chalk.cyan.bold('\n📦 Project Setup'));
if (hasFiles) {
console.log(chalk.yellow('⚠️ Existing project files detected in current directory'));
}
const setupChoices = hasFiles ? [
{ name: 'Pull latest updates from CORRAD AF repository', value: 'pull' },
{ name: 'Start completely new project (will overwrite existing)', value: 'new' },
{ name: 'Cancel setup', value: 'cancel' }
] : [
{ name: 'Start new project by cloning CORRAD AF repository', value: 'new' },
{ name: 'Cancel setup', value: 'cancel' }
];
const { setupAction } = await inquirer.prompt([
{
type: 'list',
name: 'setupAction',
message: 'What would you like to do?',
choices: setupChoices,
default: 0
}
]);
if (setupAction === 'cancel') {
console.log(chalk.yellow('👋 Setup cancelled. Goodbye!'));
process.exit(0);
}
// Clear screen and show project name prompt
clearScreen();
console.log(boxen(
chalk.white.bold('🚀 CORRAD Application Framework CLI\n') +
chalk.gray('The fastest way to bootstrap your next project'),
{
padding: 1,
margin: 1,
borderStyle: 'round',
borderColor: 'cyan'
}
));
// Get project name (only for new projects)
let projectName = path.basename(process.cwd());
if (setupAction === 'new') {
const { inputProjectName } = await inquirer.prompt([
{
type: 'input',
name: 'inputProjectName',
message: 'Enter your project name:',
default: 'my-corradaf-project',
validate: function(input) {
if (input.trim().length === 0) {
return 'Project name cannot be empty';
}
// Check for invalid characters
if (/[<>:"/\\|?*]/.test(input)) {
return 'Project name contains invalid characters';
}
return true;
}
}
]);
projectName = inputProjectName;
}
// Clear screen and show project type selection
clearScreen();
console.log(boxen(
chalk.white.bold('🚀 CORRAD Application Framework CLI\n') +
chalk.gray('The fastest way to bootstrap your next project'),
{
padding: 1,
margin: 1,
borderStyle: 'round',
borderColor: 'cyan'
}
));
// Step 3: Ask if public or internal project
console.log(chalk.cyan.bold('\n🔐 Project Type'));
const { projectType } = await inquirer.prompt([
{
type: 'list',
name: 'projectType',
message: 'Is this a public or internal project?',
choices: [
{
name: chalk.green('🌍 Public') + chalk.gray(' - Configure environment manually'),
value: 'public'
},
{
name: chalk.red('🔒 Internal') + chalk.gray(' - Use company configuration'),
value: 'internal'
}
],
default: 0
}
]);
let isInternal = false;
let useCompanyEnv = false;
if (projectType === 'internal') {
isInternal = true;
// Clear screen and show password prompt
clearScreen();
console.log(boxen(
chalk.white.bold('🚀 CORRAD Application Framework CLI\n') +
chalk.gray('The fastest way to bootstrap your next project'),
{
padding: 1,
margin: 1,
borderStyle: 'round',
borderColor: 'cyan'
}
));
// Password verification for internal projects
console.log(chalk.yellow('\n🔒 Internal project detected - Password verification required'));
const { password } = await inquirer.prompt([
{
type: 'password',
name: 'password',
message: 'Enter company password:',
mask: '*'
}
]);
if (password !== 'Rahsia@123456') {
console.log(chalk.red('❌ Incorrect password. Access denied.'));
process.exit(1);
}
console.log(chalk.green('✓ Password verified. Access granted.'));
useCompanyEnv = true;
} else {
console.log(chalk.green('✓ Public project setup selected.'));
}
// Clear screen and show development tools prompt
clearScreen();
console.log(boxen(
chalk.white.bold('🚀 CORRAD Application Framework CLI\n') +
chalk.gray('The fastest way to bootstrap your next project'),
{
padding: 1,
margin: 1,
borderStyle: 'round',
borderColor: 'cyan'
}
));
// Step 4: Ask about Cursor rules
console.log(chalk.cyan.bold('\n⚙ Development Tools'));
const { useCursorRules } = await inquirer.prompt([
{
type: 'list',
name: 'useCursorRules',
message: 'Do you want to apply the optimized Cursor AI rules for better code assistance?',
choices: [
{ name: 'Yes, apply Cursor AI rules (recommended)', value: true },
{ name: 'No, skip Cursor rules', value: false }
],
default: 0
}
]);
// Clear screen and show setup progress
clearScreen();
console.log(boxen(
chalk.white.bold('🚀 CORRAD Application Framework CLI\n') +
chalk.gray('The fastest way to bootstrap your next project'),
{
padding: 1,
margin: 1,
borderStyle: 'round',
borderColor: 'cyan'
}
));
// Step 5: Show loading screen and setup project
console.log(chalk.cyan.bold('\n🚀 Setting up your project...'));
if (setupAction === 'new') {
// Clone the repository with proper escaping
const cloneSpinner = ora('Cloning CORRAD AF template...').start();
const escapedProjectName = escapeProjectName(projectName);
const success = runCommand(`git clone https://git.sena.my/corrad-software/corrad-af-2024.git ${escapedProjectName}`, { stdio: 'pipe' });
if (!success) {
cloneSpinner.fail('Failed to clone repository');
process.exit(1);
}
cloneSpinner.succeed('Repository cloned successfully');
// Change to project directory
process.chdir(projectName);
} else {
// Pull latest updates
const pullSpinner = ora('Pulling latest updates...').start();
const success = runCommand('git pull origin main', { stdio: 'pipe' });
if (!success) {
pullSpinner.fail('Failed to pull updates');
console.log(chalk.yellow('⚠️ You may need to resolve conflicts manually'));
} else {
pullSpinner.succeed('Updates pulled successfully');
}
}
// Remove .git folder (user will init themselves later) - only for new projects
if (setupAction === 'new') {
const gitSpinner = ora('Cleaning up repository...').start();
try {
if (fs.existsSync('.git')) {
if (process.platform === 'win32') {
runCommand('rmdir /s /q .git', { stdio: 'pipe' });
} else {
runCommand('rm -rf .git', { stdio: 'pipe' });
}
}
gitSpinner.succeed('Repository cleaned up');
} catch (error) {
gitSpinner.warn('Repository cleanup skipped');
}
}
// Setup environment file
if (useCompanyEnv && isInternal) {
const envSpinner = ora('Setting up company environment...').start();
try {
// Fetch .env content from secure URL
const envContent = await fetchFromUrl(ENV_CONFIG_URLS.internal, INTERNAL_ACCESS_TOKEN);
const processedContent = envContent.replace(/\${projectName}/g, projectName);
fs.writeFileSync('.env', processedContent);
envSpinner.succeed('Company environment configured');
} catch (error) {
envSpinner.fail('Failed to fetch company environment config');
console.log(chalk.yellow('⚠️ Unable to access secure company environment.'));
console.log(chalk.gray('Please contact your system administrator for access.'));
process.exit(1);
}
} else {
// Create environment file based on .env.example
const envSpinner = ora('Setting up environment configuration...').start();
try {
if (fs.existsSync('.env.example')) {
const exampleContent = fs.readFileSync('.env.example', 'utf8');
const envVars = parseEnvExample(exampleContent);
envSpinner.succeed('Environment template loaded');
// Clear screen for env configuration
clearScreen();
console.log(boxen(
chalk.white.bold('🚀 CORRAD Application Framework CLI\n') +
chalk.gray('The fastest way to bootstrap your next project'),
{
padding: 1,
margin: 1,
borderStyle: 'round',
borderColor: 'cyan'
}
));
// Prompt for each environment variable
const envConfig = await promptForEnvConfig(envVars, projectName);
// Generate .env file
let envContent = '';
for (const [key, value] of Object.entries(envConfig)) {
envContent += `${key}="${value}"\n`;
}
fs.writeFileSync('.env', envContent);
console.log(chalk.green('✓ Environment file created'));
} else {
envSpinner.warn('No .env.example found - creating basic environment');
// Fallback to basic template
const fallbackEnv = `# Basic Environment Configuration
DATABASE_URL="postgresql://username:password@localhost:5432/database_name"
JWT_SECRET="your-super-secret-jwt-key"
AUTH_ORIGIN="http://localhost:3000"
NUXT_SECRET_KEY="your-nuxt-secret-key"
APP_NAME="${projectName}"
APP_URL="http://localhost:3000"
NODE_ENV="development"
NUXT_HOST="localhost"
NUXT_PORT="3000"
`;
fs.writeFileSync('.env', fallbackEnv);
console.log(chalk.green('✓ Basic environment created'));
}
} catch (error) {
envSpinner.fail('Failed to set up environment');
console.log(chalk.red(`Error: ${error.message}`));
}
}
// Setup Cursor rules
if (useCursorRules) {
const cursorSpinner = ora('Applying Cursor AI rules...').start();
const cursorRules = `# CORRAD AF Cursor Rules
# These rules optimize Cursor AI for working with the CORRAD Application Framework
### Behaviour rules
- You are an agent - please keep going until the user's query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved.
- If you are not sure about file content or codebase structure pertaining to the user's request, use your tools to read files and gather the relevant information: do NOT guess or make up an answer.
- You MUST plan extensively before each function call, and reflect extensively on the outcomes of the previous function calls. DO NOT do this entire process by making function calls only, as this can impair your ability to solve the problem and think insightfully.
### Coding rules
You are a Senior Full Stack Developer and an Expert in Vue, NuxtJS, JavaScript, TypeScript, HTML, SCSS and modern UI/UX frameworks (e.g., TailwindCSS, NuxtUI, Vuetify). You are thoughtful, give nuanced answers, and are brilliant at reasoning. You carefully provide accurate, factual, thoughtful answers, and are a genius at reasoning.
- Follow the user's requirements carefully & to the letter.
- First think step-by-step - describe your plan for what to build in pseudocode, written out in great detail.
- Confirm, then write code!
- Always write correct, best practice, KISS, DRY, SOLID, YAGNI principles, bug free, fully functional and working code.
- Avoid creating very large Vue components. When possible, extract functionality into separate sub-components.
- When working on an existing project, adapt to the existing conventions. If there's not enough context in the prompt to know what the conventions in the current project are, you MUST proactively read other files to find out.
- When asked to do something / create some kind of code, first read code of the same kind in the project so you know what's the project's syntax and practices.
- Before creating types or interfaces, first search through the project as the required types might already exist.
- Before creating migrations on backend, check what the correct command is in the package.json. After creation, check if the created migration contains only the added fields, otherwise remove the rest as the generator may add garbage.
- Focus on easy and readability code, over being performant.
- Fully implement all requested functionality.
- Leave NO todo's, placeholders or missing pieces.
- Ensure code is complete! Verify thoroughly finalised.
- Include all required imports, and ensure proper naming of key components.
- Be concise Minimize any other prose.
- If you think there might not be a correct answer, you say so.
- If you do not know the answer, say so, instead of guessing.
- When you want to show different options to solve an issue, do so WITHOUT implementing every option. First ask the user which one they would prefer.
- Every non-code part of your response should be written using Markdown, for better legibility.
- When using frameworks / UI libraries, you may use context7 to check the documentation on what components to use for the required task and how to use them correctly.
- IMPORTANT #1: Limit yourself to what you were asked to do. DO NOT REFACTOR / REWRITE code unless asked to. Instead, you MAY emit any recommendations you have at the end of your message (or you may do it at the start, and ask for confirmation, if you feel convenient).
- IMPORTANT #2: The user is a software engineer. Focus on what he asked you to change. Do not fix or change things that haven't been asked you to.
- IMPORTANT #3: Every change you implement must be carefuly though, and the implementation MUST BE ROBUST, unless specified otherwise by the user.
## CORRAD AF Framework Specific Rules
You are an expert in Nuxt 3, Vue 3, TypeScript, TailwindCSS, and the CORRAD AF framework.
Code Style Preferences:
- Use Composition API with <script setup>
- Prefer TypeScript for type safety
- Use TailwindCSS for styling
- Follow CORRAD AF patterns from llms.txt
Key Conventions:
- Use \`navigateTo()\` instead of \`router.push()\`
- Use \`definePageMeta()\` for page configuration
- Use \`ref()\` and \`reactive()\` for Vue 3 reactivity
- Prefer composables over mixins
- Use middleware for route protection
Framework Patterns:
- Follow the component templates in llms.txt
- Use rs-card, rs-button components
- Implement proper error handling
- Follow the API endpoint patterns
- Use Prisma for database operations
Security:
- Always validate inputs
- Use proper authentication patterns
- Implement RBAC where needed
- Follow security best practices from llms.txt
`;
fs.writeFileSync('.cursorrules', cursorRules);
cursorSpinner.succeed('Cursor AI rules applied');
}
// Show fancy loading progress
await createProgressBar('Installing dependencies and setting up project', 4000);
// Install dependencies
const yarnSpinner = ora('Installing dependencies with Yarn...').start();
const yarnSuccess = runCommand('yarn install', { stdio: 'pipe' });
if (!yarnSuccess) {
yarnSpinner.fail('Failed to install dependencies with Yarn');
console.log(chalk.yellow('Trying with npm as fallback...'));
const npmSpinner = ora('Installing dependencies with npm...').start();
const npmSuccess = runCommand('npm install', { stdio: 'pipe' });
if (!npmSuccess) {
npmSpinner.fail('Failed to install dependencies');
console.log(chalk.red('❌ Please install dependencies manually after setup'));
} else {
npmSpinner.succeed('Dependencies installed with npm');
}
} else {
yarnSpinner.succeed('Dependencies installed with Yarn');
}
// Setup Prisma
const prismaSpinner = ora('Setting up Prisma database...').start();
try {
// Check if Prisma is available and generate client
if (fs.existsSync('prisma/schema.prisma')) {
const prismaSuccess = runCommand('npx prisma generate', { stdio: 'pipe' });
if (prismaSuccess) {
prismaSpinner.succeed('Prisma database configured');
} else {
prismaSpinner.warn('Prisma setup incomplete - configure manually if needed');
}
} else {
prismaSpinner.warn('No Prisma schema found - skipping database setup');
}
} catch (error) {
prismaSpinner.warn('Prisma setup skipped');
}
// Step 6: Success message and next steps
const nextSteps = setupAction === 'new' ? [
` cd ${projectName}`,
' git init # Initialize git repository',
' yarn dev # Start development server',
' yarn build # Build for production',
' yarn start # Start production server'
] : [
' yarn dev # Start development server',
' yarn build # Build for production',
' yarn start # Start production server'
];
console.log('\n' + boxen(
chalk.green.bold('🎉 Project setup completed successfully!\n\n') +
chalk.white(`Project: ${chalk.cyan.bold(projectName)}\n`) +
chalk.white(`Type: ${chalk.yellow.bold(projectType)}\n`) +
chalk.white(`Action: ${chalk.yellow.bold(setupAction === 'new' ? 'New Project' : 'Updated Existing')}\n`) +
chalk.white(`Location: ${chalk.gray(process.cwd())}\n\n`) +
chalk.white.bold('Next steps:\n') +
nextSteps.map(step => chalk.gray(step)).join('\n'),
{
padding: 1,
margin: 1,
borderStyle: 'round',
borderColor: 'green'
}
));
// Ask if user wants to open in IDE
const { openIDE } = await inquirer.prompt([
{
type: 'list',
name: 'openIDE',
message: 'Would you like to open the project in your IDE now?',
choices: [
{ name: 'Yes, open in IDE', value: true },
{ name: 'No, I will open it manually', value: false }
],
default: 0
}
]);
if (openIDE) {
console.log(chalk.cyan('Opening project in IDE...'));
// Try different IDE commands
const ideCommands = ['code .', 'cursor .', 'webstorm .', 'idea .'];
let ideOpened = false;
for (const cmd of ideCommands) {
try {
execSync(cmd, { stdio: 'pipe' });
console.log(chalk.green(`✓ Opened in IDE with: ${cmd}`));
ideOpened = true;
break;
} catch (error) {
// Try next IDE
}
}
if (!ideOpened) {
console.log(chalk.yellow('Could not detect IDE. Please open the project manually.'));
}
}
// Step 7: Auto close after showing final message
console.log(chalk.gray('\n👋 CLI setup complete. You can now continue in your IDE terminal.'));
console.log(chalk.gray('This terminal will close in 3 seconds...'));
setTimeout(() => {
process.exit(0);
}, 3000);
} catch (error) {
if (error.isTtyError) {
console.error(chalk.red('❌ This CLI requires an interactive terminal.'));
} else {
console.error(chalk.red('❌ Setup failed:'), error.message);
}
process.exit(1);
}
}
// Handle Ctrl+C gracefully
process.on('SIGINT', () => {
console.log(chalk.yellow('\n\n👋 Setup cancelled by user. Goodbye!'));
process.exit(0);
});
// Handle uncaught exceptions
process.on('uncaughtException', (error) => {
console.error('❌ Uncaught Exception:', error);
process.exit(1);
});
// Handle unhandled promise rejections
process.on('unhandledRejection', (reason, promise) => {
console.error('❌ Unhandled Rejection at:', promise, 'reason:', reason);
process.exit(1);
});
// Run the CLI
console.log('📦 Calling main function...');
main().catch((error) => {
console.error('❌ Main function error:', error);
process.exit(1);
});

39
cli-tool/package.json Normal file
View File

@ -0,0 +1,39 @@
{
"name": "corradaf",
"version": "1.0.0",
"description": "CLI tool to quickly set up CORRAD Application Framework projects",
"main": "index.js",
"bin": {
"corradaf": "./index.js"
},
"scripts": {
"start": "node index.js"
},
"keywords": [
"corradaf",
"cli",
"project-setup",
"nuxt",
"vue",
"framework",
"template"
],
"dependencies": {
"figlet": "^1.7.0",
"ora": "^5.4.1",
"inquirer": "^8.2.6",
"chalk": "^4.1.2",
"boxen": "^5.1.2",
"gradient-string": "^2.0.2"
},
"author": "Corrad Team",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://git.sena.my/corrad-software/corrad-af-2024.git"
},
"homepage": "https://git.sena.my/corrad-software/corrad-af-2024",
"engines": {
"node": ">=14.0.0"
}
}

View File

@ -18,12 +18,12 @@
],
"repository": {
"type": "git",
"url": "https://github.com/your-org/corrad-af"
"url": "https://git.sena.my/corrad-software/corrad-af-2024.git"
},
"bugs": {
"url": "https://github.com/your-org/corrad-af/issues"
"url": "https://git.sena.my/corrad-software/corrad-af-2024/issues"
},
"homepage": "https://github.com/your-org/corrad-af#readme",
"homepage": "https://git.sena.my/corrad-software/corrad-af-2024",
"private": true,
"scripts": {
"build": "nuxt build",
@ -31,7 +31,8 @@
"generate": "nuxt generate",
"preview": "nuxt preview",
"postinstall": "nuxt prepare",
"prisma": "npx prisma db pull && npx prisma generate && nuxt dev"
"prisma": "yarn prisma:generate && nuxt dev",
"prisma:generate": "npx prisma db pull && npx prisma generate"
},
"devDependencies": {
"@nuxtjs/tailwindcss": "^6.8.0",