agentic-kdd 2.1.2 → 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 +185 -47
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentic-kdd",
3
- "version": "2.1.2",
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
@@ -5,6 +5,7 @@ const path = require('path');
5
5
  const { execSync } = require('child_process');
6
6
  const chalk = require('chalk');
7
7
  const ora = require('ora');
8
+ const inquirer = require('inquirer');
8
9
 
9
10
  const GITHUB_REPO = 'Adrianlpz211/Agentic-KDD';
10
11
  const TEMP_DIR = path.join(require('os').tmpdir(), 'agentic-kdd-download');
@@ -25,10 +26,9 @@ async function downloadFromGitHub(spinner) {
25
26
 
26
27
  // ── Copiar archivos al proyecto ─────────────────────────────────
27
28
  function copyAgenticFiles(sourcePath, projectPath) {
28
- // Archivos raíz
29
29
  const rootFiles = ['CLAUDE.md', '_LOCKS.md', '.cursorrules', 'dashboard.cjs', 'docs', '.cursor', '.audit'];
30
30
  for (const file of rootFiles) {
31
- const src = path.join(sourcePath, file);
31
+ const src = path.join(sourcePath, file);
32
32
  const dest = path.join(projectPath, file);
33
33
  if (fs.existsSync(src)) fs.copySync(src, dest, { overwrite: true });
34
34
  }
@@ -37,24 +37,19 @@ function copyAgenticFiles(sourcePath, projectPath) {
37
37
  const agDest = path.join(projectPath, '.agentic');
38
38
 
39
39
  if (fs.existsSync(agSrc)) {
40
- // Agentes — siempre sobreescribir
41
40
  fs.copySync(path.join(agSrc, 'agentes'), path.join(agDest, 'agentes'), { overwrite: true });
41
+ fs.copySync(path.join(agSrc, 'grafo'), path.join(agDest, 'grafo'), { overwrite: true });
42
42
 
43
- // Grafo — siempre sobreescribir
44
- fs.copySync(path.join(agSrc, 'grafo'), path.join(agDest, 'grafo'), { overwrite: true });
45
-
46
- // Carpetas que solo se crean si no existen (no sobreescribir memoria del usuario)
47
43
  const onlyCreate = ['memoria', 'specs', 'conocimiento'];
48
44
  for (const dir of onlyCreate) {
49
- const src = path.join(agSrc, dir);
50
45
  const dest = path.join(agDest, dir);
51
46
  if (!fs.existsSync(dest)) {
47
+ const src = path.join(agSrc, dir);
52
48
  if (fs.existsSync(src)) fs.copySync(src, dest);
53
49
  else fs.ensureDirSync(dest);
54
50
  }
55
51
  }
56
52
 
57
- // PLAN.md — solo si no existe
58
53
  const planDest = path.join(agDest, 'PLAN.md');
59
54
  if (!fs.existsSync(planDest)) {
60
55
  const planSrc = path.join(agSrc, 'PLAN.md');
@@ -62,10 +57,98 @@ function copyAgenticFiles(sourcePath, projectPath) {
62
57
  }
63
58
  }
64
59
 
65
- // Crear _output si no existe
66
60
  fs.ensureDirSync(path.join(projectPath, '_output'));
67
61
  }
68
62
 
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
+ }
91
+
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
+ }
111
+
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
+ }
147
+
148
+ recorrer(projectPath, 0);
149
+ return consolidados;
150
+ }
151
+
69
152
  // ── Comando principal: akdd init ────────────────────────────────
70
153
  async function init() {
71
154
  const projectPath = process.cwd();
@@ -74,57 +157,112 @@ async function init() {
74
157
  console.log(chalk.gray(' github.com/Adrianlpz211/Agentic-KDD\n'));
75
158
 
76
159
  // Verificar si ya está instalado
77
- const alreadyInstalled = fs.existsSync(path.join(projectPath, '.agentic', 'agentes'));
78
- if (alreadyInstalled) {
160
+ if (fs.existsSync(path.join(projectPath, '.agentic', 'agentes'))) {
79
161
  console.log(chalk.yellow(' Agentic KDD ya está instalado en este proyecto.'));
80
162
  console.log(chalk.gray(' Para actualizar los agentes sin perder tu memoria: akdd update\n'));
81
163
  return;
82
164
  }
83
165
 
84
- // Instalar
85
- const spinner = ora({ text: 'Descargando Agentic KDD...', color: 'magenta' }).start();
166
+ // Detectar stack
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'));
86
171
 
87
- try {
88
- const sourcePath = await downloadFromGitHub(spinner);
172
+ if (stack.framework !== '—')
173
+ console.log(chalk.green(` ✓ Stack detectado: ${stack.framework} · ${stack.language} · ${stack.packageManager}`));
174
+ if (hasCode)
175
+ console.log(chalk.green(' ✓ Código existente detectado'));
176
+ console.log('');
177
+
178
+ // ── PREGUNTA 1: Nombre ──────────────────────────────────────
179
+ const { name } = await inquirer.prompt([{
180
+ type: 'input', name: 'name',
181
+ message: 'Nombre del proyecto:',
182
+ default: path.basename(projectPath)
183
+ }]);
184
+
185
+ // ── PREGUNTA 2: Nuevo o existente ──────────────────────────
186
+ const { isNew } = await inquirer.prompt([{
187
+ type: 'list', name: 'isNew',
188
+ message: '¿El proyecto es nuevo o ya tiene código?',
189
+ choices: [
190
+ { name: 'Nuevo — empezando desde cero', value: true },
191
+ { name: 'Existente — ya tiene código o avance', value: false }
192
+ ],
193
+ default: !hasCode
194
+ }]);
89
195
 
196
+ // ── INSTALAR — crear carpetas PRIMERO antes de preguntar docs ──
197
+ const spinner = ora({ text: 'Descargando Agentic KDD...', color: 'magenta' }).start();
198
+ let sourcePath;
199
+ try {
200
+ sourcePath = await downloadFromGitHub(spinner);
90
201
  spinner.text = 'Instalando archivos...';
91
202
  copyAgenticFiles(sourcePath, projectPath);
92
-
93
203
  fs.removeSync(TEMP_DIR);
94
- spinner.succeed(chalk.green('¡Agentic KDD instalado!'));
95
-
96
- // Mostrar qué se instaló
97
- console.log('\n' + chalk.bold(' Instalado:'));
98
- console.log(chalk.gray(' .agentic/agentes/ — pipeline de 9 agentes'));
99
- console.log(chalk.gray(' .agentic/grafo/ — motor SQLite de conocimiento'));
100
- console.log(chalk.gray(' .agentic/memoria/ — errores, patrones, decisiones'));
101
- console.log(chalk.gray(' .agentic/conocimiento/ — documentación del proyecto'));
102
- console.log(chalk.gray(' .agentic/specs/ — specs auto-generadas'));
103
- console.log(chalk.gray(' .audit/ — departamento QA (7 subagentes)'));
104
- console.log(chalk.gray(' dashboard.cjs — dashboard visual'));
105
- console.log(chalk.gray(' CLAUDE.md — activa aa: / ag: / audit:'));
106
- console.log(chalk.gray(' .cursorrules — reglas para Cursor'));
107
-
108
- // Instrucción final — clara y directa
109
- console.log('\n' + chalk.bold.hex('#2a3050')(' ─────────────────────────────────────────────'));
110
- console.log(chalk.bold(' Último paso — abre este proyecto en'));
111
- console.log(chalk.bold(' Cursor o Claude Code y ejecuta:'));
112
- console.log('');
113
- console.log(' ' + chalk.bold.hex('#a78bfa')('aa: configurar'));
114
- console.log('');
115
- console.log(chalk.gray(' Esto completa la configuración leyendo'));
116
- console.log(chalk.gray(' tu código real. Solo se hace una vez.'));
117
- console.log(chalk.bold.hex('#2a3050')(' ─────────────────────────────────────────────'));
118
-
119
- console.log('\n' + chalk.gray(' Tip: si tienes specs, wireframes o docs del proyecto,'));
120
- console.log(chalk.gray(' cópialos a .agentic/conocimiento/ antes de configurar.\n'));
121
-
204
+ spinner.succeed(chalk.green('Archivos instalados'));
122
205
  } catch (err) {
123
206
  spinner.fail(chalk.red('Error en la instalación'));
124
- console.error(chalk.red('\n ' + err.message));
125
- console.log(chalk.gray(' Descarga manual: https://github.com/Adrianlpz211/Agentic-KDD\n'));
207
+ console.error(chalk.red('\n ' + err.message + '\n'));
126
208
  process.exit(1);
127
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'));
128
266
  }
129
267
 
130
268
  module.exports = { init };