novatec-cli 1.0.2 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/index.js CHANGED
@@ -4,89 +4,89 @@ import { program } from 'commander';
4
4
  import chalk from 'chalk';
5
5
  import figlet from 'figlet';
6
6
  import boxen from 'boxen';
7
+ import { execSync } from 'child_process';
8
+ import { createRequire } from 'module';
7
9
  import { checkRequirements } from '../lib/utils.js';
8
10
  import { runCreate } from '../lib/create.js';
9
11
 
12
+ const require = createRequire(import.meta.url);
13
+ const pkg = require('../package.json');
14
+
10
15
  function sleep(ms) {
11
16
  return new Promise(r => setTimeout(r, ms));
12
17
  }
13
18
 
19
+ // Verifica si hay una versión más nueva en npm (silencioso)
20
+ async function checkForUpdates() {
21
+ try {
22
+ const latest = execSync(`npm show ${pkg.name} version`, { encoding: 'utf8', timeout: 3000 }).trim();
23
+ if (latest && latest !== pkg.version) {
24
+ console.log(
25
+ boxen(
26
+ chalk.yellow(' Nueva versión disponible!\n\n') +
27
+ chalk.gray(' Actual : ') + chalk.white(pkg.version) + '\n' +
28
+ chalk.gray(' Nueva : ') + chalk.bold.white(latest) + '\n\n' +
29
+ chalk.white(' npm install -g novatec-cli'),
30
+ { padding: 1, margin: { left: 2 }, borderStyle: 'round', borderColor: 'yellow', dimBorder: true }
31
+ )
32
+ );
33
+ }
34
+ } catch { /* sin internet o error, ignorar */ }
35
+ }
36
+
14
37
  async function showBanner() {
15
38
  console.clear();
16
39
 
17
- // Logo en blanco puro con sombra gris (efecto profundidad)
18
- const logo = figlet.textSync('NOVATEC', { font: 'ANSI Shadow' });
40
+ const logo = figlet.textSync('NOVATEC', { font: 'Slant' });
19
41
  const lines = logo.split('\n').filter(l => l.trim());
20
42
 
21
43
  console.log();
22
- lines.forEach(line => {
23
- console.log(' ' + chalk.bold.white(line));
24
- });
25
-
44
+ lines.forEach(line => console.log(' ' + chalk.bold.white(line)));
26
45
  console.log();
27
46
 
28
- // Subtítulo elegante
29
- const sub = ' ◈ NOVATEC FULLSTACK CLI · Generador Profesional de Proyectos ◈';
30
- console.log(chalk.gray(sub));
47
+ // Versión + fecha
48
+ const now = new Date();
49
+ const fecha = now.toLocaleDateString('es-MX', { day: '2-digit', month: 'short', year: 'numeric' });
50
+ console.log(
51
+ ' ' + chalk.gray('v' + pkg.version) +
52
+ chalk.gray(' · ') +
53
+ chalk.gray('NOVATEC FULLSTACK CLI') +
54
+ chalk.gray(' · ') +
55
+ chalk.gray(fecha)
56
+ );
31
57
  console.log();
32
-
33
- // Separador
34
- console.log(' ' + chalk.white('─'.repeat(66)));
58
+ console.log(' ' + chalk.white('─'.repeat(60)));
35
59
  console.log();
36
60
 
37
- // Stats rápidos
61
+ // Stats
38
62
  console.log(
39
63
  ' ' +
40
- chalk.white.bold('10') + chalk.gray(' frontends ') +
41
- chalk.white('·') +
42
- chalk.white.bold(' 10') + chalk.gray(' backends ') +
43
- chalk.white('·') +
44
- chalk.white.bold(' 100%') + chalk.gray(' listo para producción')
64
+ chalk.bold.white('10') + chalk.gray(' frontends') +
65
+ chalk.gray(' · ') +
66
+ chalk.bold.white('10') + chalk.gray(' backends') +
67
+ chalk.gray(' · ') +
68
+ chalk.bold.white('TypeScript') + chalk.gray(' ready') +
69
+ chalk.gray(' · ') +
70
+ chalk.bold.white('Docker') + chalk.gray(' ready')
45
71
  );
46
72
  console.log();
47
73
 
48
- // Caja de tecnologías — blanco y negro elegante
74
+ // Caja tecnologías
49
75
  console.log(
50
76
  boxen(
51
- chalk.bold.white(' TECNOLOGÍAS DISPONIBLES') + '\n\n' +
52
-
77
+ chalk.bold.white(' TECNOLOGÍAS\n\n') +
53
78
  chalk.white.bold(' Frontend') + chalk.gray(' │ ') +
54
- [
55
- chalk.white('React'),
56
- chalk.white('Next.js'),
57
- chalk.white('Vue'),
58
- chalk.white('Nuxt'),
59
- chalk.white('Astro'),
60
- chalk.white('Svelte'),
61
- chalk.white('SolidJS'),
62
- chalk.white('Angular'),
63
- chalk.white('Remix'),
64
- chalk.white('Qwik'),
65
- ].join(chalk.gray(' · ')) + '\n\n' +
66
-
79
+ ['React', 'Next.js', 'Vue', 'Nuxt', 'Astro', 'Svelte', 'SolidJS', 'Angular', 'Remix', 'Qwik']
80
+ .map(f => chalk.white(f)).join(chalk.gray(' · ')) + '\n\n' +
67
81
  chalk.white.bold(' Backend ') + chalk.gray(' │ ') +
68
- [
69
- chalk.white('Express'),
70
- chalk.white('NestJS'),
71
- chalk.white('Fastify'),
72
- chalk.white('Hono'),
73
- chalk.white('FastAPI'),
74
- chalk.white('Django'),
75
- chalk.white('Flask'),
76
- chalk.white('Spring'),
77
- chalk.white('Deno'),
78
- chalk.white('Go/Gin'),
79
- ].join(chalk.gray(' · ')) + '\n\n' +
80
-
82
+ ['Express', 'NestJS', 'Fastify', 'Hono', 'FastAPI', 'Django', 'Flask', 'Spring', 'Deno', 'Go/Gin']
83
+ .map(b => chalk.white(b)).join(chalk.gray(' · ')) + '\n\n' +
84
+ chalk.white.bold(' Database') + chalk.gray(' │ ') +
85
+ ['PostgreSQL', 'MySQL', 'MongoDB', 'SQLite']
86
+ .map(d => chalk.white(d)).join(chalk.gray(' · ')) + '\n\n' +
81
87
  chalk.white.bold(' Extras ') + chalk.gray(' │ ') +
82
- [
83
- chalk.gray('Docker'),
84
- chalk.gray('ESLint + Prettier'),
85
- chalk.gray('Husky'),
86
- chalk.gray('Jest / Vitest'),
87
- chalk.gray('GitHub Actions'),
88
- chalk.gray('.env'),
89
- ].join(chalk.gray(' · ')),
88
+ ['Docker', 'JWT Auth', 'ESLint', 'Husky', 'Vitest', 'GitHub Actions', 'Tailwind']
89
+ .map(e => chalk.gray(e)).join(chalk.gray(' · ')),
90
90
  {
91
91
  padding: { top: 1, bottom: 1, left: 2, right: 4 },
92
92
  margin: { left: 2 },
@@ -97,14 +97,14 @@ async function showBanner() {
97
97
  )
98
98
  );
99
99
 
100
- console.log();
101
-
102
100
  // Uso rápido
103
101
  console.log(
104
102
  boxen(
105
103
  chalk.gray(' Uso rápido\n\n') +
106
- chalk.white(' $ novatec-cli create ') + chalk.gray('<nombre-proyecto>') + '\n\n' +
107
- chalk.white(' $ novatec-cli create my-app ') + chalk.gray('--frontend react --backend express'),
104
+ chalk.white(' $ novatec create ') + chalk.gray('<nombre>') + '\n' +
105
+ chalk.white(' $ novatec create my-app ') + chalk.gray('--frontend react --backend express --yes') + '\n' +
106
+ chalk.white(' $ novatec list') + chalk.gray(' # ver frameworks') + '\n' +
107
+ chalk.white(' $ novatec update') + chalk.gray(' # actualizar CLI'),
108
108
  {
109
109
  padding: { top: 0, bottom: 0, left: 1, right: 4 },
110
110
  margin: { left: 2 },
@@ -116,22 +116,30 @@ async function showBanner() {
116
116
  );
117
117
 
118
118
  console.log();
119
- console.log(' ' + chalk.white('─'.repeat(66)));
119
+ console.log(' ' + chalk.white('─'.repeat(60)));
120
120
  console.log();
121
121
  }
122
122
 
123
+ // ── COMANDOS ──────────────────────────────────────────────────────────────────
124
+
123
125
  program
124
126
  .name('novatec')
125
127
  .description('NOVATEC FULLSTACK CLI — Generador profesional de proyectos full stack')
126
- .version('1.0.2', '-v, --version', 'Mostrar versión');
128
+ .version(pkg.version, '-v, --version', 'Mostrar versión');
127
129
 
130
+ // CREATE
128
131
  program
129
132
  .command('create [name]')
130
133
  .description('Crear un nuevo proyecto full stack')
131
- .option('--frontend <type>', 'react | next | vue | nuxt | astro | svelte | solid | angular | remix | qwik')
132
- .option('--backend <type>', 'express | nestjs | fastify | hono | fastapi | django | flask | spring | deno | gin')
134
+ .option('--frontend <type>', 'Framework frontend')
135
+ .option('--backend <type>', 'Framework backend')
136
+ .option('--db <type>', 'Base de datos: postgres | mysql | mongo | sqlite')
137
+ .option('--typescript', 'Usar TypeScript en el proyecto')
138
+ .option('--yes', 'Saltar prompts y usar valores por defecto')
139
+ .option('--preset <name>', 'Usar preset guardado')
133
140
  .action(async (name, options) => {
134
141
  await showBanner();
142
+ await checkForUpdates();
135
143
  try {
136
144
  await checkRequirements();
137
145
  await runCreate(name, options);
@@ -146,9 +154,83 @@ program
146
154
  }
147
155
  });
148
156
 
157
+ // LIST
158
+ program
159
+ .command('list')
160
+ .description('Ver todos los frameworks y tecnologías disponibles')
161
+ .action(() => {
162
+ console.log();
163
+ console.log(
164
+ boxen(
165
+ chalk.bold.white(' FRAMEWORKS DISPONIBLES\n\n') +
166
+
167
+ chalk.bold.white(' Frontend\n') +
168
+ [
169
+ ' react — React 18 + Vite',
170
+ ' next — Next.js 14 (App Router)',
171
+ ' vue — Vue 3 + Vite',
172
+ ' nuxt — Nuxt 3',
173
+ ' astro — Astro 4',
174
+ ' svelte — SvelteKit',
175
+ ' solid — SolidJS + Vite',
176
+ ' angular — Angular 17',
177
+ ' remix — Remix 2',
178
+ ' qwik — Qwik City',
179
+ ].map(l => chalk.gray(l)).join('\n') + '\n\n' +
180
+
181
+ chalk.bold.white(' Backend\n') +
182
+ [
183
+ ' express — Express.js (Node)',
184
+ ' nestjs — NestJS (Node + TypeScript)',
185
+ ' fastify — Fastify (Node)',
186
+ ' hono — Hono (Edge-ready)',
187
+ ' fastapi — FastAPI (Python)',
188
+ ' django — Django (Python)',
189
+ ' flask — Flask (Python)',
190
+ ' spring — Spring Boot (Java)',
191
+ ' deno — Deno + Oak',
192
+ ' gin — Go + Gin',
193
+ ].map(l => chalk.gray(l)).join('\n') + '\n\n' +
194
+
195
+ chalk.bold.white(' Bases de datos\n') +
196
+ [
197
+ ' postgres — PostgreSQL',
198
+ ' mysql — MySQL',
199
+ ' mongo — MongoDB',
200
+ ' sqlite — SQLite',
201
+ ].map(l => chalk.gray(l)).join('\n'),
202
+ {
203
+ padding: { top: 1, bottom: 1, left: 2, right: 6 },
204
+ margin: { left: 2 },
205
+ borderStyle: 'round',
206
+ borderColor: 'white',
207
+ dimBorder: true,
208
+ }
209
+ )
210
+ );
211
+ console.log();
212
+ });
213
+
214
+ // UPDATE
215
+ program
216
+ .command('update')
217
+ .description('Actualizar novatec-cli a la última versión')
218
+ .action(async () => {
219
+ const ora = (await import('ora')).default;
220
+ const spinner = ora({ text: chalk.white('Actualizando novatec-cli...'), spinner: 'dots', color: 'white' }).start();
221
+ try {
222
+ execSync('npm install -g novatec-cli@latest', { stdio: 'pipe', encoding: 'utf8' });
223
+ const newVer = execSync('npm show novatec-cli version', { encoding: 'utf8' }).trim();
224
+ spinner.succeed(chalk.white('Actualizado a v' + newVer));
225
+ } catch (e) {
226
+ spinner.fail(chalk.red('Error al actualizar: ' + e.message));
227
+ }
228
+ });
229
+
149
230
  if (!process.argv.slice(2).length) {
150
231
  (async () => {
151
232
  await showBanner();
233
+ await checkForUpdates();
152
234
  program.outputHelp();
153
235
  })();
154
236
  } else {