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/bin/akdd.js +10 -5
- package/package.json +7 -3
- package/src/dashboard-template.cjs +1730 -0
- package/src/dashboard-template.js +1345 -0
- package/src/dashboard.js +57 -0
- package/src/graph.js +27 -36
- package/src/init.js +280 -125
- package/templates/.agentic/grafo/grafo.cjs +524 -0
- package/templates/.agentic/grafo/schema.sql +95 -0
- package/templates/.agentic/grafo/watch-errors.cjs +238 -0
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
|
-
// ──
|
|
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
|
-
|
|
18
|
-
|
|
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
|
|
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
|
|
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'])
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
|
-
|
|
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
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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
|
-
|
|
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', '
|
|
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
|
|
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
|
-
|
|
321
|
+
| Fase | Módulo | Rutas clave |
|
|
322
|
+
|------|--------|-------------|
|
|
323
|
+
${modulosImpl}
|
|
180
324
|
|
|
181
325
|
### Pendientes
|
|
182
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
|
376
|
+
// Detectar estado y stack automáticamente
|
|
223
377
|
const state = detectProjectState(projectPath);
|
|
224
378
|
const stack = detectStack(projectPath);
|
|
225
379
|
|
|
226
|
-
//
|
|
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
|
-
|
|
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
|
|
239
|
-
let
|
|
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
|
+
}
|
|
240
424
|
|
|
425
|
+
// ── DOCUMENTACIÓN ──────────────────────────────────────────────
|
|
241
426
|
if (!state.hasKnowledge) {
|
|
242
427
|
const { hasDocs } = await inquirer.prompt([{
|
|
243
|
-
type: 'confirm',
|
|
244
|
-
|
|
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
|
|
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,
|
|
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
|
-
// ──
|
|
293
|
-
const spinner = ora({ text: 'Descargando Agentic KDD
|
|
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 = '
|
|
302
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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
|
-
|
|
319
|
-
|
|
320
|
-
|
|
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) {
|