agentic-kdd 2.1.1 → 2.1.3

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/init.js +179 -400
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentic-kdd",
3
- "version": "2.1.1",
3
+ "version": "2.1.3",
4
4
  "description": "Autonomous development pipeline with KDD — aa: · ag: · audit: · Visual Dashboard. Works with Cursor and Claude Code.",
5
5
  "main": "src/index.js",
6
6
  "bin": {
package/src/init.js CHANGED
@@ -10,223 +10,6 @@ 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
- // ── 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 ──────────────────────────────────────────────
138
- function detectStack(projectPath) {
139
- const stack = {
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' }
144
- };
145
-
146
- if (fs.existsSync(path.join(projectPath, 'package.json'))) {
147
- const pkg = fs.readJsonSync(path.join(projectPath, 'package.json'), { throws: false }) || {};
148
- const deps = { ...pkg.dependencies, ...pkg.devDependencies };
149
- stack.language = deps['typescript'] ? 'TypeScript' : 'JavaScript';
150
- stack.runtime = 'Node.js';
151
-
152
- if (fs.existsSync(path.join(projectPath, 'pnpm-lock.yaml'))) {
153
- stack.packageManager = 'pnpm';
154
- stack.commands = { install: 'pnpm install', dev: 'pnpm dev', build: 'pnpm build', test: 'pnpm test', lint: 'pnpm lint' };
155
- } else if (fs.existsSync(path.join(projectPath, 'yarn.lock'))) {
156
- stack.packageManager = 'yarn';
157
- stack.commands = { install: 'yarn', dev: 'yarn dev', build: 'yarn build', test: 'yarn test', lint: 'yarn lint' };
158
- }
159
-
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
- }
183
- }
184
-
185
- if (fs.existsSync(path.join(projectPath, 'composer.json'))) {
186
- const composer = fs.readJsonSync(path.join(projectPath, 'composer.json'), { throws: false }) || {};
187
- stack.language = 'PHP'; stack.runtime = 'PHP';
188
- stack.packageManager = 'composer';
189
- stack.commands = { install: 'composer install', dev: 'php artisan serve', build: 'composer build', test: './vendor/bin/phpunit', lint: 'composer lint' };
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
- }
197
- }
198
-
199
- if (fs.existsSync(path.join(projectPath, 'pyproject.toml')) ||
200
- fs.existsSync(path.join(projectPath, 'requirements.txt'))) {
201
- stack.language = 'Python'; stack.runtime = 'Python';
202
- stack.packageManager = 'pip';
203
- stack.templateKey = 'python';
204
- stack.commands = { install: 'pip install -r requirements.txt', dev: 'uvicorn main:app --reload', build: 'pip install -e .', test: 'pytest', lint: 'flake8' };
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
- }
211
- }
212
-
213
- return stack;
214
- }
215
-
216
- // ── Detectar si el proyecto tiene contenido ─────────────────────
217
- function detectProjectState(projectPath) {
218
- const hasCode = fs.existsSync(path.join(projectPath, 'src')) ||
219
- fs.existsSync(path.join(projectPath, 'app')) ||
220
- fs.existsSync(path.join(projectPath, 'pages')) ||
221
- fs.existsSync(path.join(projectPath, 'api'));
222
- const hasKnowledge = fs.existsSync(path.join(projectPath, '.agentic', 'conocimiento')) &&
223
- fs.readdirSync(path.join(projectPath, '.agentic', 'conocimiento')).filter(f => f !== 'README.md').length > 0;
224
- const hasPackageFile = fs.existsSync(path.join(projectPath, 'package.json')) ||
225
- fs.existsSync(path.join(projectPath, 'composer.json')) ||
226
- fs.existsSync(path.join(projectPath, 'pyproject.toml'));
227
- return { hasCode, hasKnowledge, hasPackageFile };
228
- }
229
-
230
13
  // ── Descargar desde GitHub ──────────────────────────────────────
231
14
  async function downloadFromGitHub(spinner) {
232
15
  const tmpFile = path.join(require('os').tmpdir(), 'agentic-kdd.tar.gz');
@@ -243,110 +26,127 @@ async function downloadFromGitHub(spinner) {
243
26
 
244
27
  // ── Copiar archivos al proyecto ─────────────────────────────────
245
28
  function copyAgenticFiles(sourcePath, projectPath) {
246
- const files = ['CLAUDE.md', '_LOCKS.md', '.cursorrules', 'dashboard.cjs', 'docs', '.cursor', '.audit'];
247
- for (const file of files) {
248
- const src = path.join(sourcePath, file);
29
+ const rootFiles = ['CLAUDE.md', '_LOCKS.md', '.cursorrules', 'dashboard.cjs', 'docs', '.cursor', '.audit'];
30
+ for (const file of rootFiles) {
31
+ const src = path.join(sourcePath, file);
249
32
  const dest = path.join(projectPath, file);
250
33
  if (fs.existsSync(src)) fs.copySync(src, dest, { overwrite: true });
251
34
  }
252
35
 
253
- const agSrc = path.join(sourcePath, '.agentic');
36
+ const agSrc = path.join(sourcePath, '.agentic');
254
37
  const agDest = path.join(projectPath, '.agentic');
255
38
 
256
39
  if (fs.existsSync(agSrc)) {
257
40
  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'));
261
-
262
- const memorySrc = path.join(agSrc, 'memoria');
263
- const memoryDest = path.join(agDest, 'memoria');
264
- if (!fs.existsSync(memoryDest)) fs.copySync(memorySrc, memoryDest);
41
+ fs.copySync(path.join(agSrc, 'grafo'), path.join(agDest, 'grafo'), { overwrite: true });
42
+
43
+ const onlyCreate = ['memoria', 'specs', 'conocimiento'];
44
+ for (const dir of onlyCreate) {
45
+ const dest = path.join(agDest, dir);
46
+ if (!fs.existsSync(dest)) {
47
+ const src = path.join(agSrc, dir);
48
+ if (fs.existsSync(src)) fs.copySync(src, dest);
49
+ else fs.ensureDirSync(dest);
50
+ }
51
+ }
265
52
 
266
53
  const planDest = path.join(agDest, 'PLAN.md');
267
- if (!fs.existsSync(planDest)) fs.copySync(path.join(agSrc, 'PLAN.md'), planDest);
268
-
269
- const knSrc = path.join(agSrc, 'conocimiento', 'README.md');
270
- const knDest = path.join(agDest, 'conocimiento', 'README.md');
271
- fs.ensureDirSync(path.dirname(knDest));
272
- if (!fs.existsSync(knDest)) fs.copySync(knSrc, knDest);
54
+ if (!fs.existsSync(planDest)) {
55
+ const planSrc = path.join(agSrc, 'PLAN.md');
56
+ if (fs.existsSync(planSrc)) fs.copySync(planSrc, planDest);
57
+ }
273
58
  }
274
- }
275
-
276
- // ── Escribir config.md completo y listo ────────────────────────
277
- function writeConfig(projectPath, 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._';
284
-
285
- const config = `# Agentic KDD — Configuración del proyecto
286
- CONFIGURADO: SI
287
- VERSION: 2.0
288
-
289
- ---
290
-
291
- ## Proyecto
292
- Nombre: ${name}
293
- Descripción: ${description}
294
- Tipo: ${isNew ? 'NUEVO' : 'EXISTENTE'}
295
-
296
- ## Stack
297
- \`\`\`yaml
298
- frontend:
299
- framework: ${stack.framework}
300
- language: ${stack.language}
301
59
 
302
- backend:
303
- runtime: ${stack.runtime || stack.language}
304
- framework: ${stack.framework}
305
- base_datos: ${stack.base_datos || '—'}
306
-
307
- devops:
308
- package_manager: ${stack.packageManager}
309
-
310
- commands:
311
- install: ${stack.commands.install}
312
- dev: ${stack.commands.dev}
313
- build: ${stack.commands.build}
314
- test: ${stack.commands.test}
315
- lint: ${stack.commands.lint}
316
- \`\`\`
317
-
318
- ## Módulos
319
-
320
- ### Implementados
321
- | Fase | Módulo | Rutas clave |
322
- |------|--------|-------------|
323
- ${modulosImpl}
324
-
325
- ### Pendientes
326
- ${modulosPend}
327
-
328
- ## Archivos compartidos críticos
329
- _El Setup los detecta al correr aa: configurar._
330
-
331
- ## Reglas del proyecto
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
60
+ fs.ensureDirSync(path.join(projectPath, '_output'));
61
+ }
337
62
 
338
- ### Desarrollo ${stack.framework !== '—' ? stack.framework : ''}
339
- ${reglas}
63
+ // ── Detectar stack ──────────────────────────────────────────────
64
+ function detectStack(projectPath) {
65
+ const stack = { framework: '—', language: '—', packageManager: 'npm' };
66
+ if (fs.existsSync(path.join(projectPath, 'package.json'))) {
67
+ const pkg = fs.readJsonSync(path.join(projectPath, 'package.json'), { throws: false }) || {};
68
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
69
+ stack.language = deps['typescript'] ? 'TypeScript' : 'JavaScript';
70
+ if (fs.existsSync(path.join(projectPath, 'pnpm-lock.yaml'))) stack.packageManager = 'pnpm';
71
+ else if (fs.existsSync(path.join(projectPath, 'yarn.lock'))) stack.packageManager = 'yarn';
72
+ if (deps['next']) stack.framework = `Next.js ${(deps['next']||'').replace(/[\^~]/,'')}`;
73
+ else if (deps['react'] && !deps['next']) stack.framework = 'React';
74
+ else if (deps['express']) stack.framework = 'Express';
75
+ else if (deps['fastify']) stack.framework = 'Fastify';
76
+ else if (deps['@nestjs/core']) stack.framework = 'NestJS';
77
+ }
78
+ if (fs.existsSync(path.join(projectPath, 'composer.json'))) {
79
+ const composer = fs.readJsonSync(path.join(projectPath, 'composer.json'), { throws: false }) || {};
80
+ stack.language = 'PHP'; stack.packageManager = 'composer';
81
+ if ((composer.require||{})['laravel/framework']) stack.framework = 'Laravel';
82
+ else stack.framework = 'PHP';
83
+ }
84
+ if (fs.existsSync(path.join(projectPath, 'pyproject.toml')) ||
85
+ fs.existsSync(path.join(projectPath, 'requirements.txt'))) {
86
+ stack.language = 'Python'; stack.packageManager = 'pip';
87
+ stack.framework = 'Python';
88
+ }
89
+ return stack;
90
+ }
340
91
 
341
- ## Sinónimos del proyecto
342
- _Sin sinónimos registrados aún._
92
+ // ── Consolidar docs en conocimiento/ ───────────────────────────
93
+ function consolidarDocs(projectPath) {
94
+ const conocimientoPath = path.join(projectPath, '.agentic', 'conocimiento');
95
+ const consolidados = [];
96
+ const ignorar = ['node_modules', '.git', '.agentic', '_output', 'dist', 'build', '.next', 'vendor'];
97
+
98
+ // Extensiones útiles como conocimiento
99
+ const extensionesUtiles = ['.md', '.pdf', '.txt'];
100
+ // Nombres específicos que siempre son útiles
101
+ const nombresUtiles = ['README', 'SPEC', 'SPECS', 'CONTEXT', 'CONTEXTO', 'REQUIREMENTS',
102
+ 'ARCHITECTURE', 'DISEÑO', 'DESIGN', 'BRIEF', 'PRD', 'CLAUDE', 'AGENTS'];
103
+
104
+ function esArchivoUtil(nombre) {
105
+ const upper = nombre.toUpperCase().replace(/\.[^.]+$/, '');
106
+ const ext = path.extname(nombre).toLowerCase();
107
+ if (extensionesUtiles.includes(ext)) return true;
108
+ if (nombresUtiles.some(n => upper.includes(n))) return true;
109
+ return false;
110
+ }
343
111
 
344
- ## Mapa BD → módulo
345
- _El agente Setup lo detecta._
346
- `;
112
+ function recorrer(dir, nivel) {
113
+ if (nivel > 3) return; // máximo 3 niveles de profundidad
114
+ let items;
115
+ try { items = fs.readdirSync(dir); } catch(e) { return; }
116
+
117
+ for (const item of items) {
118
+ if (ignorar.includes(item) || item.startsWith('.')) continue;
119
+ const fullPath = path.join(dir, item);
120
+ const stat = fs.statSync(fullPath);
121
+
122
+ if (stat.isDirectory()) {
123
+ recorrer(fullPath, nivel + 1);
124
+ } else if (stat.isFile() && esArchivoUtil(item)) {
125
+ // No mover repomix — solo usarlo como referencia
126
+ if (item.includes('repomix')) {
127
+ consolidados.push({ src: fullPath, nombre: item, tipo: 'referencia' });
128
+ continue;
129
+ }
130
+ // No copiar si ya está en conocimiento/
131
+ if (fullPath.startsWith(conocimientoPath)) continue;
132
+
133
+ const destNombre = item;
134
+ const destPath = path.join(conocimientoPath, destNombre);
135
+ // Si ya existe uno con el mismo nombre, agregar prefijo del directorio padre
136
+ const finalDest = fs.existsSync(destPath)
137
+ ? path.join(conocimientoPath, path.basename(dir) + '_' + destNombre)
138
+ : destPath;
139
+
140
+ try {
141
+ fs.copySync(fullPath, finalDest, { overwrite: false });
142
+ consolidados.push({ src: fullPath, nombre: destNombre, tipo: 'copiado' });
143
+ } catch(e) {}
144
+ }
145
+ }
146
+ }
347
147
 
348
- fs.ensureDirSync(path.join(projectPath, '.agentic'));
349
- fs.writeFileSync(path.join(projectPath, '.agentic', 'config.md'), config, 'utf8');
148
+ recorrer(projectPath, 0);
149
+ return consolidados;
350
150
  }
351
151
 
352
152
  // ── Comando principal: akdd init ────────────────────────────────
@@ -357,46 +157,32 @@ async function init() {
357
157
  console.log(chalk.gray(' github.com/Adrianlpz211/Agentic-KDD\n'));
358
158
 
359
159
  // Verificar si ya está instalado
360
- const alreadyInstalled = fs.existsSync(path.join(projectPath, '.agentic', 'config.md'));
361
- if (alreadyInstalled) {
362
- const content = fs.readFileSync(path.join(projectPath, '.agentic', 'config.md'), 'utf8');
363
- if (content.includes('CONFIGURADO: SI')) {
364
- const { confirm } = await inquirer.prompt([{
365
- type: 'confirm', name: 'confirm',
366
- message: chalk.yellow('Agentic KDD ya está instalado. ¿Reinstalar?'),
367
- default: false
368
- }]);
369
- if (!confirm) {
370
- console.log(chalk.gray('\n Usa akdd update para actualizar los agentes sin perder tu memoria.\n'));
371
- return;
372
- }
373
- }
160
+ if (fs.existsSync(path.join(projectPath, '.agentic', 'agentes'))) {
161
+ console.log(chalk.yellow(' Agentic KDD ya está instalado en este proyecto.'));
162
+ console.log(chalk.gray(' Para actualizar los agentes sin perder tu memoria: akdd update\n'));
163
+ return;
374
164
  }
375
165
 
376
- // Detectar estado y stack automáticamente
377
- const state = detectProjectState(projectPath);
166
+ // Detectar stack
378
167
  const stack = detectStack(projectPath);
168
+ const hasCode = fs.existsSync(path.join(projectPath, 'src')) ||
169
+ fs.existsSync(path.join(projectPath, 'app')) ||
170
+ fs.existsSync(path.join(projectPath, 'pages'));
379
171
 
380
- // Mostrar lo que detectó
381
- if (stack.framework !== '—') {
172
+ if (stack.framework !== '—')
382
173
  console.log(chalk.green(` ✓ Stack detectado: ${stack.framework} · ${stack.language} · ${stack.packageManager}`));
383
- }
384
- if (state.hasCode) {
174
+ if (hasCode)
385
175
  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
176
  console.log('');
391
177
 
392
- // ── PREGUNTA 1 Nombre ─────────────────────────────────────────
178
+ // ── PREGUNTA 1: Nombre ──────────────────────────────────────
393
179
  const { name } = await inquirer.prompt([{
394
180
  type: 'input', name: 'name',
395
181
  message: 'Nombre del proyecto:',
396
182
  default: path.basename(projectPath)
397
183
  }]);
398
184
 
399
- // ── PREGUNTA 2 Nuevo o existente ──────────────────────────────
185
+ // ── PREGUNTA 2: Nuevo o existente ──────────────────────────
400
186
  const { isNew } = await inquirer.prompt([{
401
187
  type: 'list', name: 'isNew',
402
188
  message: '¿El proyecto es nuevo o ya tiene código?',
@@ -404,86 +190,79 @@ async function init() {
404
190
  { name: 'Nuevo — empezando desde cero', value: true },
405
191
  { name: 'Existente — ya tiene código o avance', value: false }
406
192
  ],
407
- default: !state.hasCode
193
+ default: !hasCode
408
194
  }]);
409
195
 
410
- // ── PREGUNTA 3 Descripció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
- }
424
-
425
- // ── DOCUMENTACIÓN ──────────────────────────────────────────────
426
- if (!state.hasKnowledge) {
427
- const { hasDocs } = await inquirer.prompt([{
428
- type: 'confirm', name: 'hasDocs',
429
- message: '¿Tienes specs, wireframes o documentación del proyecto?',
430
- default: false
431
- }]);
432
- if (hasDocs) {
433
- console.log('\n' + chalk.cyan(' Sube tus archivos a:'));
434
- console.log(chalk.bold(' .agentic/conocimiento/'));
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...' }]);
437
- }
438
- }
439
-
440
- // ── Instalar ────────────────────────────────────────────────────
196
+ // ── INSTALARcrear carpetas PRIMERO antes de preguntar docs ──
441
197
  const spinner = ora({ text: 'Descargando Agentic KDD...', color: 'magenta' }).start();
442
-
198
+ let sourcePath;
443
199
  try {
444
- const sourcePath = await downloadFromGitHub(spinner);
445
-
200
+ sourcePath = await downloadFromGitHub(spinner);
446
201
  spinner.text = 'Instalando archivos...';
447
202
  copyAgenticFiles(sourcePath, projectPath);
448
-
449
- spinner.text = 'Generando configuración...';
450
- const template = stack.templateKey ? TEMPLATES[stack.templateKey] : null;
451
- writeConfig(projectPath, { name, description, isNew, stack, template });
452
-
453
203
  fs.removeSync(TEMP_DIR);
454
- spinner.succeed(chalk.green('¡Agentic KDD instalado!'));
455
-
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
- }
466
-
467
- console.log('\n' + chalk.bold(' Siguiente paso:\n'));
468
- if (!isNew && state.hasCode) {
469
- console.log(' ' + chalk.hex('#a78bfa')('aa: configurar') + chalk.gray(' ← el Setup leerá el código y configurará todo'));
470
- } else {
471
- console.log(' ' + chalk.hex('#a78bfa')('aa: configurar') + chalk.gray(' ← termina la configuración'));
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'));
475
-
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'));
479
- }
480
-
204
+ spinner.succeed(chalk.green('Archivos instalados'));
481
205
  } catch (err) {
482
206
  spinner.fail(chalk.red('Error en la instalación'));
483
- console.error(chalk.red('\n ' + err.message));
484
- console.log(chalk.gray(' Descarga manual: https://github.com/Adrianlpz211/Agentic-KDD\n'));
207
+ console.error(chalk.red('\n ' + err.message + '\n'));
485
208
  process.exit(1);
486
209
  }
210
+
211
+ // ── PREGUNTA 3: Docs (DESPUÉS de crear carpetas) ───────────
212
+ const { hasDocs } = await inquirer.prompt([{
213
+ type: 'confirm', name: 'hasDocs',
214
+ message: '¿Tienes specs, wireframes o documentación del proyecto?',
215
+ default: false
216
+ }]);
217
+
218
+ if (hasDocs) {
219
+ // Recorrer el proyecto y consolidar docs automáticamente
220
+ console.log('');
221
+ const docsSpinner = ora({ text: 'Buscando archivos de conocimiento...', color: 'cyan' }).start();
222
+ const consolidados = consolidarDocs(projectPath);
223
+ const copiados = consolidados.filter(d => d.tipo === 'copiado');
224
+ const referencias = consolidados.filter(d => d.tipo === 'referencia');
225
+
226
+ if (copiados.length > 0) {
227
+ docsSpinner.succeed(chalk.green(`Archivos de conocimiento centralizados en .agentic/conocimiento/`));
228
+ copiados.forEach(d => console.log(chalk.gray(` ✓ ${d.nombre}`)));
229
+ if (referencias.length > 0) {
230
+ console.log(chalk.gray(`\n Como referencia (no movido):`));
231
+ referencias.forEach(d => console.log(chalk.gray(` ~ ${d.nombre}`)));
232
+ }
233
+ } else {
234
+ docsSpinner.warn(chalk.yellow('No se encontraron archivos de conocimiento en el proyecto.'));
235
+ console.log(chalk.gray(' Puedes agregarlos manualmente en .agentic/conocimiento/'));
236
+ }
237
+ } else {
238
+ console.log('');
239
+ console.log(chalk.gray(' Tip: puedes agregar specs, docs o wireframes en'));
240
+ console.log(chalk.gray(' .agentic/conocimiento/ en cualquier momento.'));
241
+ console.log(chalk.gray(' Agentic los usará automáticamente en el siguiente aa:'));
242
+ }
243
+
244
+ // ── RESUMEN FINAL ───────────────────────────────────────────
245
+ console.log('\n' + chalk.bold(' Instalado:'));
246
+ console.log(chalk.gray(' .agentic/agentes/ — pipeline de 9 agentes'));
247
+ console.log(chalk.gray(' .agentic/grafo/ — motor SQLite de conocimiento'));
248
+ console.log(chalk.gray(' .agentic/memoria/ — errores, patrones, decisiones'));
249
+ console.log(chalk.gray(' .agentic/conocimiento/ — documentación del proyecto'));
250
+ console.log(chalk.gray(' .agentic/specs/ — specs auto-generadas'));
251
+ console.log(chalk.gray(' .audit/ — departamento QA (7 subagentes)'));
252
+ console.log(chalk.gray(' dashboard.cjs — dashboard visual'));
253
+ console.log(chalk.gray(' CLAUDE.md — activa aa: / ag: / audit:'));
254
+ console.log(chalk.gray(' .cursorrules — reglas para Cursor'));
255
+
256
+ // Instrucción final
257
+ console.log('\n' + chalk.dim(' ─────────────────────────────────────────────'));
258
+ console.log(chalk.bold(' Último paso — abre este proyecto en'));
259
+ console.log(chalk.bold(' Cursor o Claude Code y ejecuta:'));
260
+ console.log('');
261
+ console.log(' ' + chalk.bold.hex('#a78bfa')('aa: configurar'));
262
+ console.log('');
263
+ console.log(chalk.gray(' Esto completa la configuración leyendo tu'));
264
+ console.log(chalk.gray(' código real. Solo se hace una vez.'));
265
+ console.log(chalk.dim(' ─────────────────────────────────────────────\n'));
487
266
  }
488
267
 
489
268
  module.exports = { init };