agentic-kdd 2.0.7 → 2.1.1

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/src/init.js CHANGED
@@ -10,80 +10,224 @@ const inquirer = require('inquirer');
10
10
  const GITHUB_REPO = 'Adrianlpz211/Agentic-KDD';
11
11
  const TEMP_DIR = path.join(require('os').tmpdir(), 'agentic-kdd-download');
12
12
 
13
- // ── Detectar stack ─────────────────────────────────────────────
13
+ // ── Plantillas por stack ────────────────────────────────────────
14
+ const TEMPLATES = {
15
+ nextjs: {
16
+ nombre: 'Next.js App',
17
+ tipo: 'NUEVO',
18
+ modulos_impl: [
19
+ '| 1 | Auth y middleware | /login, /registro, middleware.ts |',
20
+ '| 2 | Layout y navegación | app/layout.tsx, componentes nav |',
21
+ ],
22
+ modulos_pend: [
23
+ '- [ ] Dashboard principal',
24
+ '- [ ] Módulo de usuarios',
25
+ '- [ ] API routes principales',
26
+ ],
27
+ reglas: [
28
+ '- App Router (no Pages Router)',
29
+ '- Server Components por defecto, Client Components solo cuando necesario',
30
+ '- Queries de base de datos solo en lib/queries/',
31
+ '- Tailwind CSS para estilos',
32
+ '- TypeScript estricto',
33
+ ],
34
+ descripcion: 'Aplicación web con Next.js 14 App Router, TypeScript y Tailwind CSS.',
35
+ },
36
+ laravel: {
37
+ nombre: 'Laravel App',
38
+ tipo: 'NUEVO',
39
+ modulos_impl: [
40
+ '| 1 | Auth y roles | routes/auth.php, AuthController |',
41
+ '| 2 | Modelos base | app/Models/, migraciones |',
42
+ ],
43
+ modulos_pend: [
44
+ '- [ ] Panel de administración',
45
+ '- [ ] API REST principal',
46
+ '- [ ] Jobs y queues',
47
+ ],
48
+ reglas: [
49
+ '- Lógica de negocio en Services, no en Controllers',
50
+ '- Queries complejas en Repositories',
51
+ '- Form Requests para validación',
52
+ '- Resources para transformar respuestas API',
53
+ '- Jobs para procesos en background',
54
+ ],
55
+ descripcion: 'Aplicación web con Laravel, MySQL y arquitectura MVC.',
56
+ },
57
+ node: {
58
+ nombre: 'Node.js API',
59
+ tipo: 'NUEVO',
60
+ modulos_impl: [
61
+ '| 1 | Servidor y configuración | index.js, config/, middleware |',
62
+ '| 2 | Auth JWT | routes/auth.js, middleware/auth.js |',
63
+ ],
64
+ modulos_pend: [
65
+ '- [ ] Endpoints principales',
66
+ '- [ ] Base de datos y modelos',
67
+ '- [ ] Tests de integración',
68
+ ],
69
+ reglas: [
70
+ '- Express con middleware centralizado',
71
+ '- Lógica en services/, no en routes',
72
+ '- Variables de entorno en .env, nunca hardcoded',
73
+ '- Manejo de errores centralizado',
74
+ ],
75
+ descripcion: 'API REST con Node.js, Express y base de datos.',
76
+ },
77
+ react: {
78
+ nombre: 'React App',
79
+ tipo: 'NUEVO',
80
+ modulos_impl: [
81
+ '| 1 | Estructura base | App.tsx, router, layout |',
82
+ '| 2 | Estado global | context o zustand |',
83
+ ],
84
+ modulos_pend: [
85
+ '- [ ] Componentes principales',
86
+ '- [ ] Integración con API',
87
+ '- [ ] Tests de componentes',
88
+ ],
89
+ reglas: [
90
+ '- Componentes funcionales con hooks',
91
+ '- Estado local con useState, global con Context/Zustand',
92
+ '- Llamadas API centralizadas en services/',
93
+ '- CSS Modules o Tailwind, no inline styles',
94
+ ],
95
+ descripcion: 'Aplicación React con TypeScript y gestión de estado.',
96
+ },
97
+ php: {
98
+ nombre: 'PHP App',
99
+ tipo: 'NUEVO',
100
+ modulos_impl: [
101
+ '| 1 | Configuración base | config.php, conexión DB |',
102
+ '| 2 | Auth | login.php, session |',
103
+ ],
104
+ modulos_pend: [
105
+ '- [ ] Módulo principal',
106
+ '- [ ] Panel de administración',
107
+ ],
108
+ reglas: [
109
+ '- Queries preparadas siempre (PDO)',
110
+ '- Validación en el servidor',
111
+ '- Sin lógica en las vistas',
112
+ ],
113
+ descripcion: 'Aplicación PHP con MySQL.',
114
+ },
115
+ python: {
116
+ nombre: 'Python App',
117
+ tipo: 'NUEVO',
118
+ modulos_impl: [
119
+ '| 1 | Estructura base | main.py, config.py |',
120
+ '| 2 | Auth | auth/, middleware |',
121
+ ],
122
+ modulos_pend: [
123
+ '- [ ] Endpoints principales',
124
+ '- [ ] Base de datos',
125
+ '- [ ] Tests',
126
+ ],
127
+ reglas: [
128
+ '- FastAPI o Django según el proyecto',
129
+ '- Pydantic para validación',
130
+ '- SQLAlchemy para queries',
131
+ '- pytest para tests',
132
+ ],
133
+ descripcion: 'Aplicación Python con FastAPI/Django.',
134
+ },
135
+ };
136
+
137
+ // ── Detectar stack ──────────────────────────────────────────────
14
138
  function detectStack(projectPath) {
15
139
  const stack = {
16
- framework: '—',
17
- language: '—',
18
- packageManager: 'npm',
19
- commands: {
20
- install: 'npm install',
21
- dev: 'npm run dev',
22
- build: 'npm run build',
23
- test: 'npm test',
24
- lint: 'npm run lint'
25
- }
140
+ framework: '—', language: '—', runtime: '—',
141
+ base_datos: '—', packageManager: 'npm',
142
+ templateKey: null,
143
+ commands: { install: 'npm install', dev: 'npm run dev', build: 'npm run build', test: 'npm test', lint: 'npm run lint' }
26
144
  };
27
145
 
28
146
  if (fs.existsSync(path.join(projectPath, 'package.json'))) {
29
147
  const pkg = fs.readJsonSync(path.join(projectPath, 'package.json'), { throws: false }) || {};
30
148
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
31
- stack.language = 'TypeScript/JavaScript';
149
+ stack.language = deps['typescript'] ? 'TypeScript' : 'JavaScript';
150
+ stack.runtime = 'Node.js';
32
151
 
33
152
  if (fs.existsSync(path.join(projectPath, 'pnpm-lock.yaml'))) {
34
153
  stack.packageManager = 'pnpm';
35
154
  stack.commands = { install: 'pnpm install', dev: 'pnpm dev', build: 'pnpm build', test: 'pnpm test', lint: 'pnpm lint' };
36
155
  } else if (fs.existsSync(path.join(projectPath, 'yarn.lock'))) {
37
156
  stack.packageManager = 'yarn';
38
- stack.commands = { install: 'yarn install', dev: 'yarn dev', build: 'yarn build', test: 'yarn test', lint: 'yarn lint' };
157
+ stack.commands = { install: 'yarn', dev: 'yarn dev', build: 'yarn build', test: 'yarn test', lint: 'yarn lint' };
39
158
  }
40
159
 
41
- if (deps['next']) stack.framework = `Next.js ${deps['next'].replace('^','')}`;
42
- else if (deps['vue']) stack.framework = `Vue ${deps['vue'].replace('^','')}`;
43
- else if (deps['react']) stack.framework = `React`;
44
- else if (deps['express']) stack.framework = `Express`;
45
- else if (deps['@nestjs/core']) stack.framework = `NestJS`;
160
+ if (deps['next']) {
161
+ stack.framework = `Next.js ${(deps['next']||'').replace(/[\^~]/,'')}`;
162
+ stack.templateKey = 'nextjs';
163
+ if (deps['@supabase/supabase-js']) stack.base_datos = 'Supabase PostgreSQL';
164
+ else if (deps['prisma'] || deps['@prisma/client']) stack.base_datos = 'Prisma';
165
+ else if (deps['mongoose']) stack.base_datos = 'MongoDB';
166
+ } else if (deps['vue']) {
167
+ stack.framework = `Vue ${(deps['vue']||'').replace(/[\^~]/,'')}`;
168
+ } else if (deps['react'] && !deps['next']) {
169
+ stack.framework = 'React';
170
+ stack.templateKey = 'react';
171
+ } else if (deps['express']) {
172
+ stack.framework = 'Express';
173
+ stack.templateKey = 'node';
174
+ stack.commands.dev = pkg.scripts?.dev || 'node index.js';
175
+ } else if (deps['fastify']) {
176
+ stack.framework = 'Fastify';
177
+ stack.templateKey = 'node';
178
+ } else if (deps['@nestjs/core']) {
179
+ stack.framework = 'NestJS';
180
+ stack.templateKey = 'node';
181
+ stack.commands.dev = 'npm run start:dev';
182
+ }
46
183
  }
47
184
 
48
185
  if (fs.existsSync(path.join(projectPath, 'composer.json'))) {
49
- stack.language = 'PHP';
186
+ const composer = fs.readJsonSync(path.join(projectPath, 'composer.json'), { throws: false }) || {};
187
+ stack.language = 'PHP'; stack.runtime = 'PHP';
50
188
  stack.packageManager = 'composer';
51
189
  stack.commands = { install: 'composer install', dev: 'php artisan serve', build: 'composer build', test: './vendor/bin/phpunit', lint: 'composer lint' };
52
- const composer = fs.readJsonSync(path.join(projectPath, 'composer.json'), { throws: false }) || {};
53
- if ((composer.require || {})['laravel/framework']) stack.framework = 'Laravel';
54
- else stack.framework = 'PHP';
190
+ if ((composer.require || {})['laravel/framework']) {
191
+ stack.framework = `Laravel ${((composer.require||{})['laravel/framework']||'').replace(/[\^~]/,'')}`;
192
+ stack.templateKey = 'laravel';
193
+ } else {
194
+ stack.framework = 'PHP';
195
+ stack.templateKey = 'php';
196
+ }
55
197
  }
56
198
 
57
199
  if (fs.existsSync(path.join(projectPath, 'pyproject.toml')) ||
58
200
  fs.existsSync(path.join(projectPath, 'requirements.txt'))) {
59
- stack.language = 'Python';
201
+ stack.language = 'Python'; stack.runtime = 'Python';
60
202
  stack.packageManager = 'pip';
203
+ stack.templateKey = 'python';
61
204
  stack.commands = { install: 'pip install -r requirements.txt', dev: 'uvicorn main:app --reload', build: 'pip install -e .', test: 'pytest', lint: 'flake8' };
62
- stack.framework = 'Python';
205
+ if (fs.existsSync(path.join(projectPath, 'pyproject.toml'))) {
206
+ const toml = fs.readFileSync(path.join(projectPath, 'pyproject.toml'), 'utf8');
207
+ if (toml.includes('fastapi')) { stack.framework = 'FastAPI'; }
208
+ else if (toml.includes('django')) { stack.framework = 'Django'; }
209
+ else { stack.framework = 'Python'; }
210
+ }
63
211
  }
64
212
 
65
213
  return stack;
66
214
  }
67
215
 
68
- // ── Detectar si el proyecto tiene contenido ────────────────────
216
+ // ── Detectar si el proyecto tiene contenido ─────────────────────
69
217
  function detectProjectState(projectPath) {
70
218
  const hasCode = fs.existsSync(path.join(projectPath, 'src')) ||
71
219
  fs.existsSync(path.join(projectPath, 'app')) ||
72
220
  fs.existsSync(path.join(projectPath, 'pages')) ||
73
221
  fs.existsSync(path.join(projectPath, 'api'));
74
-
75
222
  const hasKnowledge = fs.existsSync(path.join(projectPath, '.agentic', 'conocimiento')) &&
76
- fs.readdirSync(path.join(projectPath, '.agentic', 'conocimiento'))
77
- .filter(f => f !== 'README.md').length > 0;
78
-
223
+ fs.readdirSync(path.join(projectPath, '.agentic', 'conocimiento')).filter(f => f !== 'README.md').length > 0;
79
224
  const hasPackageFile = fs.existsSync(path.join(projectPath, 'package.json')) ||
80
225
  fs.existsSync(path.join(projectPath, 'composer.json')) ||
81
226
  fs.existsSync(path.join(projectPath, 'pyproject.toml'));
82
-
83
227
  return { hasCode, hasKnowledge, hasPackageFile };
84
228
  }
85
229
 
86
- // ── Descargar desde GitHub ─────────────────────────────────────
230
+ // ── Descargar desde GitHub ──────────────────────────────────────
87
231
  async function downloadFromGitHub(spinner) {
88
232
  const tmpFile = path.join(require('os').tmpdir(), 'agentic-kdd.tar.gz');
89
233
  try {
@@ -97,41 +241,31 @@ async function downloadFromGitHub(spinner) {
97
241
  }
98
242
  }
99
243
 
100
- // ── Copiar archivos al proyecto ────────────────────────────────
244
+ // ── Copiar archivos al proyecto ─────────────────────────────────
101
245
  function copyAgenticFiles(sourcePath, projectPath) {
102
- const files = ['CLAUDE.md', '_LOCKS.md', '_output', 'docs', '.cursor'];
103
-
246
+ const files = ['CLAUDE.md', '_LOCKS.md', '.cursorrules', 'dashboard.cjs', 'docs', '.cursor', '.audit'];
104
247
  for (const file of files) {
105
248
  const src = path.join(sourcePath, file);
106
249
  const dest = path.join(projectPath, file);
107
250
  if (fs.existsSync(src)) fs.copySync(src, dest, { overwrite: true });
108
251
  }
109
252
 
110
- // .agentic — copiar agentes y estructura pero NO sobreescribir memoria si existe
111
253
  const agSrc = path.join(sourcePath, '.agentic');
112
254
  const agDest = path.join(projectPath, '.agentic');
113
255
 
114
256
  if (fs.existsSync(agSrc)) {
115
- // Agentes siempre se actualizan
116
257
  fs.copySync(path.join(agSrc, 'agentes'), path.join(agDest, 'agentes'), { overwrite: true });
258
+ fs.copySync(path.join(agSrc, 'grafo'), path.join(agDest, 'grafo'), { overwrite: true });
259
+ fs.ensureDirSync(path.join(agDest, 'specs'));
260
+ fs.ensureDirSync(path.join(projectPath, '_output'));
117
261
 
118
- // Memoria y config solo si no existen
119
262
  const memorySrc = path.join(agSrc, 'memoria');
120
263
  const memoryDest = path.join(agDest, 'memoria');
121
264
  if (!fs.existsSync(memoryDest)) fs.copySync(memorySrc, memoryDest);
122
265
 
123
- const configDest = path.join(agDest, 'config.md');
124
- if (!fs.existsSync(configDest)) {
125
- fs.copySync(path.join(agSrc, 'config.md'), configDest);
126
- }
127
-
128
- // PLAN.md solo si no existe
129
266
  const planDest = path.join(agDest, 'PLAN.md');
130
- if (!fs.existsSync(planDest)) {
131
- fs.copySync(path.join(agSrc, 'PLAN.md'), planDest);
132
- }
267
+ if (!fs.existsSync(planDest)) fs.copySync(path.join(agSrc, 'PLAN.md'), planDest);
133
268
 
134
- // conocimiento/README siempre
135
269
  const knSrc = path.join(agSrc, 'conocimiento', 'README.md');
136
270
  const knDest = path.join(agDest, 'conocimiento', 'README.md');
137
271
  fs.ensureDirSync(path.dirname(knDest));
@@ -139,14 +273,21 @@ function copyAgenticFiles(sourcePath, projectPath) {
139
273
  }
140
274
  }
141
275
 
142
- // ── Escribir config.md con la info recopilada ──────────────────
276
+ // ── Escribir config.md completo y listo ────────────────────────
143
277
  function writeConfig(projectPath, data) {
144
- const { name, description, isNew, stack } = data;
278
+ const { name, description, isNew, stack, template } = data;
279
+ const tpl = template || {};
280
+
281
+ const modulosImpl = tpl.modulos_impl ? tpl.modulos_impl.join('\n') : '_El agente Setup los detecta al correr aa: configurar_';
282
+ const modulosPend = tpl.modulos_pend ? tpl.modulos_pend.join('\n') : '_El agente Setup los detecta al correr aa: configurar_';
283
+ const reglas = tpl.reglas ? tpl.reglas.join('\n') : '_Se definen durante el desarrollo._';
145
284
 
146
285
  const config = `# Agentic KDD — Configuración del proyecto
147
286
  CONFIGURADO: SI
148
287
  VERSION: 2.0
149
288
 
289
+ ---
290
+
150
291
  ## Proyecto
151
292
  Nombre: ${name}
152
293
  Descripción: ${description}
@@ -159,9 +300,9 @@ frontend:
159
300
  language: ${stack.language}
160
301
 
161
302
  backend:
162
- runtime: ${stack.language}
303
+ runtime: ${stack.runtime || stack.language}
163
304
  framework: ${stack.framework}
164
- base_datos: —
305
+ base_datos: ${stack.base_datos || ''}
165
306
 
166
307
  devops:
167
308
  package_manager: ${stack.packageManager}
@@ -175,30 +316,44 @@ commands:
175
316
  \`\`\`
176
317
 
177
318
  ## Módulos
319
+
178
320
  ### Implementados
179
- _El agente Setup los detecta al correr aa: configurar_
321
+ | Fase | Módulo | Rutas clave |
322
+ |------|--------|-------------|
323
+ ${modulosImpl}
180
324
 
181
325
  ### Pendientes
182
- _El agente Setup los detecta al correr aa: configurar_
326
+ ${modulosPend}
183
327
 
184
328
  ## Archivos compartidos críticos
185
- _El Setup los detecta._
329
+ _El Setup los detecta al correr aa: configurar._
186
330
 
187
331
  ## Reglas del proyecto
188
- _Se definen durante el desarrollo._
332
+
333
+ ### Agentic KDD
334
+ - \`aa:\` → pipeline completo sin pausas ni confirmaciones entre agentes
335
+ - \`audit:\` → solo auditar, no modificar código
336
+ - Context Guard: validar instrucción contra config/conocimiento/código
337
+
338
+ ### Desarrollo ${stack.framework !== '—' ? stack.framework : ''}
339
+ ${reglas}
189
340
 
190
341
  ## Sinónimos del proyecto
191
342
  _Sin sinónimos registrados aún._
343
+
344
+ ## Mapa BD → módulo
345
+ _El agente Setup lo detecta._
192
346
  `;
193
347
 
348
+ fs.ensureDirSync(path.join(projectPath, '.agentic'));
194
349
  fs.writeFileSync(path.join(projectPath, '.agentic', 'config.md'), config, 'utf8');
195
350
  }
196
351
 
197
- // ── Comando principal: akdd init ───────────────────────────────
352
+ // ── Comando principal: akdd init ────────────────────────────────
198
353
  async function init() {
199
354
  const projectPath = process.cwd();
200
355
 
201
- console.log('\n' + chalk.bold.blue(' Agentic KDD') + chalk.gray(' — autonomous development pipeline'));
356
+ console.log('\n' + chalk.bold.hex('#8b5cf6')(' 🤖 Agentic KDD') + chalk.gray(' — autonomous development pipeline'));
202
357
  console.log(chalk.gray(' github.com/Adrianlpz211/Agentic-KDD\n'));
203
358
 
204
359
  // Verificar si ya está instalado
@@ -207,27 +362,44 @@ async function init() {
207
362
  const content = fs.readFileSync(path.join(projectPath, '.agentic', 'config.md'), 'utf8');
208
363
  if (content.includes('CONFIGURADO: SI')) {
209
364
  const { confirm } = await inquirer.prompt([{
210
- type: 'confirm',
211
- name: 'confirm',
365
+ type: 'confirm', name: 'confirm',
212
366
  message: chalk.yellow('Agentic KDD ya está instalado. ¿Reinstalar?'),
213
367
  default: false
214
368
  }]);
215
369
  if (!confirm) {
216
- console.log(chalk.gray('\n Usa akdd update para actualizar sin perder tu memoria.\n'));
370
+ console.log(chalk.gray('\n Usa akdd update para actualizar los agentes sin perder tu memoria.\n'));
217
371
  return;
218
372
  }
219
373
  }
220
374
  }
221
375
 
222
- // Detectar estado del proyecto
376
+ // Detectar estado y stack automáticamente
223
377
  const state = detectProjectState(projectPath);
224
378
  const stack = detectStack(projectPath);
225
379
 
226
- // ── PREGUNTA 1 — Nuevo o existente ────────────────────────────
380
+ // Mostrar lo que detectó
381
+ if (stack.framework !== '—') {
382
+ console.log(chalk.green(` ✓ Stack detectado: ${stack.framework} · ${stack.language} · ${stack.packageManager}`));
383
+ }
384
+ if (state.hasCode) {
385
+ console.log(chalk.green(' ✓ Código existente detectado'));
386
+ }
387
+ if (state.hasKnowledge) {
388
+ console.log(chalk.green(' ✓ Documentación encontrada en conocimiento/'));
389
+ }
390
+ console.log('');
391
+
392
+ // ── PREGUNTA 1 — Nombre ─────────────────────────────────────────
393
+ const { name } = await inquirer.prompt([{
394
+ type: 'input', name: 'name',
395
+ message: 'Nombre del proyecto:',
396
+ default: path.basename(projectPath)
397
+ }]);
398
+
399
+ // ── PREGUNTA 2 — Nuevo o existente ──────────────────────────────
227
400
  const { isNew } = await inquirer.prompt([{
228
- type: 'list',
229
- name: 'isNew',
230
- message: '¿El proyecto es nuevo o ya está encaminado?',
401
+ type: 'list', name: 'isNew',
402
+ message: '¿El proyecto es nuevo o ya tiene código?',
231
403
  choices: [
232
404
  { name: 'Nuevo — empezando desde cero', value: true },
233
405
  { name: 'Existente — ya tiene código o avance', value: false }
@@ -235,62 +407,38 @@ async function init() {
235
407
  default: !state.hasCode
236
408
  }]);
237
409
 
238
- // ── PREGUNTA 2Documentación ────────────────────────────────
239
- let hasDocsAnswer = false;
410
+ // ── PREGUNTA 3Descripción (solo proyectos nuevos sin docs) ──
411
+ let description = '—';
412
+ if (isNew && !state.hasKnowledge) {
413
+ const { desc } = await inquirer.prompt([{
414
+ type: 'input', name: 'desc',
415
+ message: 'Describe brevemente qué hace el proyecto:',
416
+ validate: (v) => v.trim().length > 5 || 'Al menos 5 caracteres'
417
+ }]);
418
+ description = desc;
419
+ } else if (!isNew && state.hasCode) {
420
+ description = 'Proyecto existente — el agente Setup detectará módulos y describirá el proyecto al correr aa: configurar';
421
+ } else if (state.hasKnowledge) {
422
+ description = 'El agente Setup leerá conocimiento/ y generará la descripción';
423
+ }
240
424
 
425
+ // ── DOCUMENTACIÓN ──────────────────────────────────────────────
241
426
  if (!state.hasKnowledge) {
242
427
  const { hasDocs } = await inquirer.prompt([{
243
- type: 'confirm',
244
- name: 'hasDocs',
245
- message: '¿Tienes documentación del proyecto? (specs, wireframes, reglas de negocio, etc.)',
428
+ type: 'confirm', name: 'hasDocs',
429
+ message: '¿Tienes specs, wireframes o documentación del proyecto?',
246
430
  default: false
247
431
  }]);
248
- hasDocsAnswer = hasDocs;
249
-
250
432
  if (hasDocs) {
251
- console.log('\n' + chalk.cyan(' Sube tus archivos a la carpeta:'));
433
+ console.log('\n' + chalk.cyan(' Sube tus archivos a:'));
252
434
  console.log(chalk.bold(' .agentic/conocimiento/'));
253
- console.log(chalk.gray(' (PDFs, Markdown, Word, specs — cualquier formato)\n'));
254
-
255
- await inquirer.prompt([{
256
- type: 'input',
257
- name: 'ready',
258
- message: 'Presiona Enter cuando hayas subido los archivos...'
259
- }]);
435
+ console.log(chalk.gray(' (PDFs, Markdown, specs, wireframes — cualquier formato)\n'));
436
+ await inquirer.prompt([{ type: 'input', name: 'ready', message: 'Presiona Enter cuando hayas subido los archivos...' }]);
260
437
  }
261
- } else {
262
- console.log(chalk.green(' ✓ Encontré archivos en conocimiento/ — el Setup los leerá al configurar'));
263
- hasDocsAnswer = true;
264
- }
265
-
266
- // ── PREGUNTA 3 — Nombre ────────────────────────────────────────
267
- const { name } = await inquirer.prompt([{
268
- type: 'input',
269
- name: 'name',
270
- message: 'Nombre del proyecto:',
271
- default: path.basename(projectPath)
272
- }]);
273
-
274
- // Descripción según el caso
275
- let description = '—';
276
-
277
- if (isNew && !hasDocsAnswer) {
278
- // Proyecto nuevo sin docs — pedir descripción
279
- const { desc } = await inquirer.prompt([{
280
- type: 'input',
281
- name: 'desc',
282
- message: 'Describe brevemente el proyecto (qué hace, para quién):',
283
- validate: (v) => v.trim().length > 10 || 'Por favor da una descripción de al menos 10 caracteres'
284
- }]);
285
- description = desc;
286
- } else if (!isNew && state.hasCode) {
287
- description = 'Proyecto existente — el agente Setup detectará los módulos y describirá el proyecto al correr aa: configurar';
288
- } else if (hasDocsAnswer) {
289
- description = 'El agente Setup leerá conocimiento/ y generará la descripción al correr aa: configurar';
290
438
  }
291
439
 
292
- // ── Descargar e instalar ───────────────────────────────────────
293
- const spinner = ora({ text: 'Descargando Agentic KDD desde GitHub...', color: 'blue' }).start();
440
+ // ── Instalar ────────────────────────────────────────────────────
441
+ const spinner = ora({ text: 'Descargando Agentic KDD...', color: 'magenta' }).start();
294
442
 
295
443
  try {
296
444
  const sourcePath = await downloadFromGitHub(spinner);
@@ -298,29 +446,36 @@ async function init() {
298
446
  spinner.text = 'Instalando archivos...';
299
447
  copyAgenticFiles(sourcePath, projectPath);
300
448
 
301
- spinner.text = 'Configurando proyecto...';
302
- writeConfig(projectPath, { name, description, isNew, stack });
449
+ spinner.text = 'Generando configuración...';
450
+ const template = stack.templateKey ? TEMPLATES[stack.templateKey] : null;
451
+ writeConfig(projectPath, { name, description, isNew, stack, template });
303
452
 
304
453
  fs.removeSync(TEMP_DIR);
305
-
306
454
  spinner.succeed(chalk.green('¡Agentic KDD instalado!'));
307
455
 
308
- console.log('\n' + chalk.bold(' Siguiente paso — abre el proyecto en Cursor o Claude Code y escribe:\n'));
456
+ // Resumen de lo instalado
457
+ console.log('\n' + chalk.bold(' Instalado:'));
458
+ console.log(chalk.gray(' .agentic/ — pipeline de agentes + memoria KDD'));
459
+ console.log(chalk.gray(' .audit/ — departamento QA (7 subagentes)'));
460
+ console.log(chalk.gray(' dashboard.cjs — dashboard visual'));
461
+ console.log(chalk.gray(' CLAUDE.md — activación aa: / ag: / audit:'));
462
+ console.log(chalk.gray(' .cursorrules — reglas para Cursor'));
463
+ if (template) {
464
+ console.log(chalk.green(`\n Plantilla aplicada: ${stack.framework}`));
465
+ }
309
466
 
467
+ console.log('\n' + chalk.bold(' Siguiente paso:\n'));
310
468
  if (!isNew && state.hasCode) {
311
- console.log(chalk.cyan(' aa: configurar') + chalk.gray(' ← el Setup leerá el código y configurará todo'));
312
- } else if (hasDocsAnswer) {
313
- console.log(chalk.cyan(' aa: configurar') + chalk.gray(' ← el Setup leerá conocimiento/ y configurará todo'));
469
+ console.log(' ' + chalk.hex('#a78bfa')('aa: configurar') + chalk.gray(' ← el Setup leerá el código y configurará todo'));
314
470
  } else {
315
- console.log(chalk.cyan(' aa: configurar') + chalk.gray(' ← el Setup terminará la configuración'));
471
+ console.log(' ' + chalk.hex('#a78bfa')('aa: configurar') + chalk.gray(' ← termina la configuración'));
316
472
  }
473
+ console.log(' ' + chalk.hex('#10b981')('aa: [tu tarea]') + chalk.gray(' ← cuando esté listo, a construir'));
474
+ console.log(' ' + chalk.hex('#06b6d4')('node dashboard.cjs') + chalk.gray(' ← abrir dashboard visual\n'));
317
475
 
318
- console.log(chalk.cyan(' aa: [tu tarea]') + chalk.gray(' ← cuando esté configurado, a trabajar\n'));
319
-
320
- if (!hasDocsAnswer && isNew) {
321
- console.log(chalk.yellow(' 💡 Tip: si tienes specs o docs del proyecto, súbelos a'));
322
- console.log(chalk.yellow(' .agentic/conocimiento/ antes de correr aa: configurar'));
323
- console.log(chalk.gray(' Esto hará que el Context Guard funcione mejor.\n'));
476
+ if (stack.templateKey === null) {
477
+ console.log(chalk.yellow(' 💡 Stack no detectado automáticamente. Edita .agentic/config.md'));
478
+ console.log(chalk.yellow(' con tu stack y luego corre aa: configurar\n'));
324
479
  }
325
480
 
326
481
  } catch (err) {