agent-rev 0.5.14 → 0.5.24
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/dist/commands/repl.d.ts +0 -2
- package/dist/commands/repl.js +196 -233
- package/dist/commands/setup.js +64 -6
- package/dist/core/engine.js +265 -172
- package/dist/index.js +26 -19
- package/dist/ui/input.d.ts +23 -25
- package/dist/ui/input.js +310 -248
- package/dist/utils/qwen-auth.d.ts +14 -4
- package/dist/utils/qwen-auth.js +81 -8
- package/package.json +44 -1
package/dist/core/engine.js
CHANGED
|
@@ -69,7 +69,7 @@ function rebuildCmd(cliName, model, flags) {
|
|
|
69
69
|
}
|
|
70
70
|
async function ask(prompt, rl, fi) {
|
|
71
71
|
if (fi) {
|
|
72
|
-
fi.println(chalk.cyan(
|
|
72
|
+
fi.println(chalk.cyan(prompt));
|
|
73
73
|
const answer = await fi.readLine();
|
|
74
74
|
// Echo user response right-aligned (chat style, per line)
|
|
75
75
|
const userLines = answer.trim().split('\n').filter(l => l.trim());
|
|
@@ -238,9 +238,11 @@ async function walkForKeyFiles(root) {
|
|
|
238
238
|
'server.ts', 'server.js', 'server.py',
|
|
239
239
|
'application.ts', 'application.js', 'application.py',
|
|
240
240
|
]);
|
|
241
|
-
const ENTRY_REGEX = /Application\.
|
|
241
|
+
const ENTRY_REGEX = /Application\.[a-z]+$/i; // *Application.java, *Application.kt, etc.
|
|
242
242
|
const CTRL_REGEX = /(controller|router|routes|handler|endpoint|resource)/i;
|
|
243
243
|
const SCHEMA_REGEX = /(schema|\.entity|\.model|\.dto|models?\.|entities?\.)/i;
|
|
244
|
+
// Directories that conventionally hold data/domain classes (language-agnostic)
|
|
245
|
+
const DOMAIN_DIR_REGEX = /[\/\\](domain|entity|entities|model|models|dto|dtos|schema|schemas)[\/\\]/i;
|
|
244
246
|
async function walk(dir, depth) {
|
|
245
247
|
if (depth > 6)
|
|
246
248
|
return;
|
|
@@ -276,7 +278,8 @@ async function walkForKeyFiles(root) {
|
|
|
276
278
|
if (CTRL_REGEX.test(e.name) && result.controllers.length < 5) {
|
|
277
279
|
result.controllers.push(p);
|
|
278
280
|
}
|
|
279
|
-
|
|
281
|
+
const isSchema = SCHEMA_REGEX.test(e.name) || DOMAIN_DIR_REGEX.test(p);
|
|
282
|
+
if (isSchema && result.schemas.length < 5) {
|
|
280
283
|
result.schemas.push(p);
|
|
281
284
|
}
|
|
282
285
|
}
|
|
@@ -326,17 +329,25 @@ export class AgentEngine {
|
|
|
326
329
|
if (!this.fi)
|
|
327
330
|
return noop;
|
|
328
331
|
const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
332
|
+
const dotFrames = ['· ', '·· ', '···'];
|
|
329
333
|
let i = 0;
|
|
334
|
+
let ti = 0;
|
|
330
335
|
const t0 = Date.now();
|
|
331
336
|
const fi = this.fi;
|
|
337
|
+
let streaming = false;
|
|
332
338
|
fi.startActivity(`${frames[0]} ${label} 0s`);
|
|
339
|
+
fi.setActivityLines([` ${dotFrames[0]} esperando respuesta...`]);
|
|
333
340
|
const iv = setInterval(() => {
|
|
334
341
|
const s = Math.floor((Date.now() - t0) / 1000);
|
|
342
|
+
ti++;
|
|
335
343
|
fi.updateActivityHeader(`${frames[i++ % frames.length]} ${label} ${s}s`);
|
|
336
|
-
|
|
344
|
+
if (!streaming) {
|
|
345
|
+
fi.setActivityLines([` ${dotFrames[ti % dotFrames.length]} esperando respuesta...`]);
|
|
346
|
+
}
|
|
347
|
+
}, 300);
|
|
337
348
|
return {
|
|
338
349
|
stop() { clearInterval(iv); fi.stopActivity(); },
|
|
339
|
-
push(
|
|
350
|
+
push(_chunk) { streaming = true; },
|
|
340
351
|
};
|
|
341
352
|
}
|
|
342
353
|
/** Extract readable text lines from a qwen/CLI streaming chunk. */
|
|
@@ -406,7 +417,7 @@ INSTRUCCIONES:
|
|
|
406
417
|
const model = this.coordinatorCmd.match(/(?:-m|--model)\s+(\S+)/)?.[1] || 'coder-model';
|
|
407
418
|
const sp = this._startSpinner(`coordinador ${model}`);
|
|
408
419
|
try {
|
|
409
|
-
const result = await callQwenAPI(prompt, model, (c) =>
|
|
420
|
+
const result = await callQwenAPI(prompt, model, (c) => sp.push(c));
|
|
410
421
|
sp.stop();
|
|
411
422
|
return result;
|
|
412
423
|
}
|
|
@@ -617,26 +628,22 @@ INSTRUCCIONES:
|
|
|
617
628
|
const ROLE_BINARIES = new Set(['agent-orch', 'agent-impl', 'agent-rev', 'agent-explorer']);
|
|
618
629
|
const tryRoleBinaryCreds = async (cliName, model) => {
|
|
619
630
|
const credsPath = path.join(os.homedir(), `.${cliName}`, 'oauth_creds.json');
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
631
|
+
const hasOAuthCreds = await fileExists(credsPath);
|
|
632
|
+
if (!hasOAuthCreds) {
|
|
633
|
+
// No role OAuth creds — try global API key config before giving up
|
|
634
|
+
const { loadApiKeyConfig } = await import('../utils/qwen-auth.js');
|
|
635
|
+
const apiKeyCfg = await loadApiKeyConfig();
|
|
636
|
+
if (!apiKeyCfg) {
|
|
637
|
+
log.warn(`${cliName} has no credentials — run: agent-mp setup api-key or ${cliName} --login`);
|
|
638
|
+
return null;
|
|
639
|
+
}
|
|
640
|
+
// Fall through: callQwenAPIFromCreds will use the API key config
|
|
623
641
|
}
|
|
624
642
|
const sp = this._startSpinner(`${cliName} ${model}`);
|
|
625
|
-
|
|
626
|
-
const onChunk = (delta) => {
|
|
627
|
-
lineBuf += delta;
|
|
628
|
-
const lines = lineBuf.split('\n');
|
|
629
|
-
lineBuf = lines.pop() || '';
|
|
630
|
-
for (const l of lines) {
|
|
631
|
-
if (l.trim())
|
|
632
|
-
sp.push(l.trim());
|
|
633
|
-
}
|
|
634
|
-
};
|
|
643
|
+
const onChunk = (delta) => sp.push(delta);
|
|
635
644
|
try {
|
|
636
645
|
log.info(`${cliName}: calling Qwen API with own credentials (${model})`);
|
|
637
646
|
const result = await callQwenAPIFromCreds(rolePrompt, model, credsPath, onChunk);
|
|
638
|
-
if (lineBuf.trim())
|
|
639
|
-
sp.push(lineBuf.trim());
|
|
640
647
|
sp.stop();
|
|
641
648
|
return result;
|
|
642
649
|
}
|
|
@@ -693,20 +700,9 @@ INSTRUCCIONES:
|
|
|
693
700
|
const fb = this.config.fallback_global;
|
|
694
701
|
log.warn(`Using global fallback: ${fb.cli} (${fb.model})`);
|
|
695
702
|
const sp = this._startSpinner(`${fb.cli} ${fb.model} (fallback)`);
|
|
696
|
-
|
|
697
|
-
const onChunk = (delta) => {
|
|
698
|
-
lineBuf += delta;
|
|
699
|
-
const lines = lineBuf.split('\n');
|
|
700
|
-
lineBuf = lines.pop() || '';
|
|
701
|
-
for (const l of lines) {
|
|
702
|
-
if (l.trim())
|
|
703
|
-
sp.push(l.trim());
|
|
704
|
-
}
|
|
705
|
-
};
|
|
703
|
+
const onChunk = (delta) => sp.push(delta);
|
|
706
704
|
try {
|
|
707
705
|
const globalResult = await callQwenAPI(rolePrompt, fb.model, onChunk);
|
|
708
|
-
if (lineBuf.trim())
|
|
709
|
-
sp.push(lineBuf.trim());
|
|
710
706
|
sp.stop();
|
|
711
707
|
trackTokens(globalResult, fb.cli, fb.model);
|
|
712
708
|
return globalResult;
|
|
@@ -1155,7 +1151,7 @@ INSTRUCCIONES:
|
|
|
1155
1151
|
compSection.push(`### ENTRY POINT: ${rel}\n\`\`\`\n${content}\n\`\`\``);
|
|
1156
1152
|
}
|
|
1157
1153
|
}
|
|
1158
|
-
const ctrls = found.controllers.slice(0,
|
|
1154
|
+
const ctrls = found.controllers.slice(0, 5);
|
|
1159
1155
|
for (const ctrl of ctrls) {
|
|
1160
1156
|
const content = await readFileSafe(ctrl, MAX_CTRL);
|
|
1161
1157
|
if (content) {
|
|
@@ -1163,7 +1159,7 @@ INSTRUCCIONES:
|
|
|
1163
1159
|
compSection.push(`### CONTROLLER/ROUTER: ${rel}\n\`\`\`\n${content}\n\`\`\``);
|
|
1164
1160
|
}
|
|
1165
1161
|
}
|
|
1166
|
-
const schemas = found.schemas.slice(0,
|
|
1162
|
+
const schemas = found.schemas.slice(0, 4);
|
|
1167
1163
|
for (const sch of schemas) {
|
|
1168
1164
|
const content = await readFileSafe(sch, MAX_SCHEMA);
|
|
1169
1165
|
if (content) {
|
|
@@ -1190,8 +1186,30 @@ INSTRUCCIONES:
|
|
|
1190
1186
|
// Ensure .agent/ structure exists
|
|
1191
1187
|
const agentDir = path.join(this.projectDir, '.agent');
|
|
1192
1188
|
const contextDir = path.join(agentDir, 'context');
|
|
1189
|
+
const docsDir = path.join(agentDir, 'docs');
|
|
1190
|
+
const rulesDir = path.join(agentDir, 'rules');
|
|
1193
1191
|
await fs.mkdir(contextDir, { recursive: true });
|
|
1194
|
-
await fs.mkdir(
|
|
1192
|
+
await fs.mkdir(docsDir, { recursive: true });
|
|
1193
|
+
await fs.mkdir(rulesDir, { recursive: true });
|
|
1194
|
+
// Seed rules files if they don't exist yet (idempotent — never overwrites)
|
|
1195
|
+
const proj = this.config.project;
|
|
1196
|
+
const rulesSeeds = {
|
|
1197
|
+
'workflow.md': `# Workflow Contract — ${proj}\n\n\`\`\`\n[ORCHESTRATOR] planifica → genera plan.json\n ↓\n[IMPLEMENTOR] ejecuta el plan → modifica archivos\n ↓\n[REVIEWER] valida → genera result.md\n\`\`\`\n\n## REGLA #1 — Separacion de roles\nCada CLI opera SOLO en su rol.\n\n## REGLA #2 — Orden estricto\nOrchestrator primero. Implementor no actua sin plan. Reviewer no actua sin implementacion.\n\n## REGLA #3 — Sin inventar\nCada rol trabaja con los archivos reales del proyecto.\n`,
|
|
1198
|
+
'orchestrator.md': `# Rol: ORCHESTRATOR — ${proj}\n\n## Responsabilidad\nAnalizar el requerimiento, leer el contexto y generar un plan de tareas ejecutable.\n\n## Antes de planificar\n1. Leer .agent/context/architecture.md\n2. Leer .agent/rules/structure.md\n3. Leer .agent/rules/patterns.md\n\n## Al generar el plan\n- Pasos atomicos (1 paso = 1 cambio verificable)\n- Rutas de archivos REALES\n- Dependencias entre pasos si las hay\n\n## Prohibido\n- Modificar archivos de codigo directamente\n- Ejecutar comandos de build o test\n`,
|
|
1199
|
+
'implementor.md': `# Rol: IMPLEMENTOR — ${proj}\n\n## Responsabilidad\nEjecutar el plan del Orchestrator. Modificar archivos de codigo siguiendo las instrucciones exactas.\n\n## Antes de implementar\n1. Leer .agent/tasks/{ID}/plan.json completo\n2. Leer .agent/rules/structure.md\n3. Leer .agent/rules/patterns.md\n\n## Al implementar\n- Seguir el plan paso a paso, en orden\n- No agregar cambios fuera del scope\n- Marcar cada paso como completado\n\n## Prohibido\n- Modificar el plan\n- Hacer refactors no solicitados\n`,
|
|
1200
|
+
'reviewer.md': `# Rol: REVIEWER — ${proj}\n\n## Responsabilidad\nValidar que la implementacion cumple el plan y respeta las reglas del proyecto.\n\n## Checklist\n- [ ] Cada paso del plan fue implementado\n- [ ] Sin archivos modificados fuera del scope\n- [ ] Convenciones de patterns.md respetadas\n- [ ] Estructura de structure.md respetada\n- [ ] Sin codigo muerto ni imports sin usar\n\n## Al generar result.md\n- Indicar cada item: OK / FAIL / SKIP con razon\n- Si FAILs: describir qué falta y en qué archivo\n\n## Prohibido\n- Modificar archivos de codigo\n- Aprobar implementaciones incompletas\n`,
|
|
1201
|
+
'structure.md': `# Estructura — ${proj}\n\n## Directorios aprobados\n- . (raiz del proyecto)\n\n## Prohibidos\n- node_modules/, dist/, .git/, build/, target/, __pycache__/, .venv/\n`,
|
|
1202
|
+
'patterns.md': `# Patrones — ${proj}\n\n## Nombrado\n- Archivos: kebab-case\n- Clases: PascalCase\n- Variables/funciones: camelCase\n- Constantes: UPPER_SNAKE_CASE\n\n## Reglas generales\n- Sin console.log de debug en produccion\n- Un archivo = una responsabilidad principal\n`,
|
|
1203
|
+
};
|
|
1204
|
+
for (const [name, content] of Object.entries(rulesSeeds)) {
|
|
1205
|
+
const fp = path.join(rulesDir, name);
|
|
1206
|
+
try {
|
|
1207
|
+
await fs.access(fp);
|
|
1208
|
+
}
|
|
1209
|
+
catch {
|
|
1210
|
+
await writeFile(fp, content);
|
|
1211
|
+
} // only create if missing
|
|
1212
|
+
}
|
|
1195
1213
|
// NOTE: cleanup of stray files moved to AFTER successful parse, to avoid
|
|
1196
1214
|
// wiping previous docs when the explorer fails (e.g. tool-call hallucination).
|
|
1197
1215
|
// Build a quick filesystem snapshot to give the explorer context
|
|
@@ -1273,11 +1291,28 @@ El engine YA leyo por vos los archivos clave de cada componente y te los pasa ar
|
|
|
1273
1291
|
- Del MANIFEST: nombre, version, framework, dependencias clave con sus versiones, scripts, entry point
|
|
1274
1292
|
- Del ENTRY POINT: puerto real, middlewares, modulos cargados
|
|
1275
1293
|
- De los CONFIG/ENV: variables reales y su proposito
|
|
1276
|
-
- De los CONTROLLER/ROUTER: endpoints REALES (metodo, ruta, parametros)
|
|
1277
|
-
- De los SCHEMA/MODEL: shape real de los datos
|
|
1294
|
+
- De los CONTROLLER/ROUTER: endpoints REALES (metodo, ruta, parametros, anotaciones como @GetMapping/@PostMapping/router.get)
|
|
1295
|
+
- De los SCHEMA/MODEL/DOMAIN: shape real de los datos (campos, tipos, anotaciones @Column/@Entity)
|
|
1278
1296
|
3. Identificar relaciones REALES entre componentes (URLs/hosts de otros servicios en .env, imports cross-component, conexiones a BBDD).
|
|
1279
1297
|
4. Generar la documentacion en los 3 niveles, en formato markdown, dentro de los bloques === ... ===.
|
|
1280
1298
|
|
|
1299
|
+
REGLA CRITICA PARA MODULOS (NIVEL 2):
|
|
1300
|
+
- Los modulos SON LAS FEATURES DEL NEGOCIO, NO las capas tecnicas.
|
|
1301
|
+
- MAL: modulos llamados "web-api", "security", "data-access" — eso es hablar de capas, no de features
|
|
1302
|
+
- BIEN: modulos llamados "clients", "sales", "products", "auth", "orders" — eso es hablar de features reales
|
|
1303
|
+
- Para identificar los modulos, MIRA los CONTROLLER/ROUTER pre-leidos: el nombre del modulo = lo que maneja ese controller
|
|
1304
|
+
* ClientController o clients.controller → modulo "clients"
|
|
1305
|
+
* SaleController o sale.routes → modulo "sales"
|
|
1306
|
+
* AuthController o auth.handler → modulo "auth"
|
|
1307
|
+
- "Archivos clave" en cada modulo DEBE listar los archivos FUENTE REALES que leiste, NO solo el manifest.
|
|
1308
|
+
Ejemplo correcto:
|
|
1309
|
+
| Archivo (ruta relativa al componente) | Rol |
|
|
1310
|
+
| controller/ClientController.java | Endpoints REST /clients |
|
|
1311
|
+
| domain/Client.java | Entidad mapeada a tabla CLIENTS |
|
|
1312
|
+
| repository/ClientRepository.java | Acceso a base de datos |
|
|
1313
|
+
| src/clients/clients.controller.ts | Endpoints /clients |
|
|
1314
|
+
| src/clients/client.schema.ts | Modelo de datos Client |
|
|
1315
|
+
|
|
1281
1316
|
NO inventes datos. Si un componente no tiene una de esas piezas en los archivos leidos, simplemente omiti esa seccion en su documentacion.
|
|
1282
1317
|
|
|
1283
1318
|
================================================================
|
|
@@ -1292,190 +1327,254 @@ ESTRUCTURA DE LOS 3 NIVELES
|
|
|
1292
1327
|
================================================================
|
|
1293
1328
|
|
|
1294
1329
|
────────────────────────────────────────────────────────────────
|
|
1295
|
-
NIVEL 0 — architecture.md (raiz de .agent/context/)
|
|
1296
|
-
Indice global. Objetivo: 50-150 lineas. Concreto.
|
|
1297
1330
|
────────────────────────────────────────────────────────────────
|
|
1298
|
-
|
|
1331
|
+
NIVEL 0 — architecture.md (raiz de .agent/context/)
|
|
1332
|
+
Objetivo: 80-150 lineas. Panorama global real, no generico.
|
|
1333
|
+
────────────────────────────────────────────────────────────────
|
|
1299
1334
|
|
|
1300
|
-
#
|
|
1335
|
+
# [Nombre del proyecto] — Arquitectura Global (NIVEL 0)
|
|
1301
1336
|
|
|
1302
|
-
>
|
|
1337
|
+
> Lectura escalonada:
|
|
1303
1338
|
> NIVEL 0: este archivo
|
|
1304
1339
|
> NIVEL 1: .agent/context/[componente]/architecture.md
|
|
1305
1340
|
> NIVEL 2: .agent/context/[componente]/modules/[modulo].md
|
|
1306
1341
|
|
|
1307
1342
|
## 1. Overview funcional
|
|
1308
|
-
2-4 lineas
|
|
1343
|
+
2-4 lineas. Que es el sistema, para quien sirve, que problema resuelve.
|
|
1344
|
+
Si hay multiples componentes con roles distintos, nombrarlos y contrastarlos en el overview:
|
|
1345
|
+
ej. "X es la API de ingesta (escritura, batch), Y es la API de gestion (CRUD, portal Nexus)."
|
|
1309
1346
|
|
|
1310
1347
|
## 2. Componentes del proyecto
|
|
1311
|
-
| Componente |
|
|
1312
|
-
|
|
1313
|
-
(
|
|
1348
|
+
| Componente | Stack (version exacta) | Puerto | Rol principal | Consumers tipicos |
|
|
1349
|
+
|---|---|---|---|---|
|
|
1350
|
+
(datos REALES del manifest. "Consumers tipicos" = quien llama a este componente: frontend, proceso batch, sistema externo)
|
|
1314
1351
|
|
|
1315
1352
|
## 3. Relaciones entre componentes
|
|
1316
|
-
| Origen | Destino | Tipo
|
|
1317
|
-
|
|
1318
|
-
(
|
|
1353
|
+
| Origen | Destino | Tipo | Proposito |
|
|
1354
|
+
|---|---|---|---|
|
|
1355
|
+
(incluir URLs/hosts reales si aparecen en .env o config: ej. "http://57.151.96.13:8000/v1/validate")
|
|
1319
1356
|
|
|
1320
1357
|
## 4. Diagrama de arquitectura
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1358
|
+
Usar box-drawing (┌─┐│└┘┬┴├┤) y flechas (→ ──> ▼ ▲). Mostrar puertos REALES.
|
|
1359
|
+
Incluir endpoints clave inline en los componentes cuando se conocen.
|
|
1360
|
+
\`\`\`text
|
|
1361
|
+
┌─────────────────────┐ ┌──────────────────────┐
|
|
1362
|
+
│ componente-a :8083 │ │ componente-b :8084 │
|
|
1363
|
+
│ POST /api/sales │ │ GET /api/nexus/combos │
|
|
1364
|
+
│ POST /api/stock │────────>│ PUT /api/nexus/... │
|
|
1365
|
+
└──────────┬──────────┘ └──────────────────────┘
|
|
1366
|
+
│ │
|
|
1367
|
+
▼ ▼
|
|
1368
|
+
┌──────────────┐ ┌──────────────┐
|
|
1369
|
+
│ SQL Server │ │ Auth Service│
|
|
1370
|
+
│ :31434 │ │ :8000 │
|
|
1371
|
+
└──────────────┘ └──────────────┘
|
|
1326
1372
|
\`\`\`
|
|
1327
1373
|
|
|
1328
|
-
## 5. Flujos end-to-end principales
|
|
1329
|
-
|
|
1330
|
-
- **"
|
|
1374
|
+
## 5. Flujos end-to-end principales
|
|
1375
|
+
Concretos, con componentes, endpoints y acciones reales. 2-5 flujos.
|
|
1376
|
+
- **"Nombre del flujo":** Actor → POST /endpoint (componente-a) → valida JWT con auth-service → escribe en SQL Server → responde 201.
|
|
1331
1377
|
|
|
1332
|
-
## 6. Prerequisitos para levantar
|
|
1333
|
-
|
|
1378
|
+
## 6. Prerequisitos para levantar
|
|
1379
|
+
Solo lo que es real: acceso de red a hosts externos, herramientas requeridas. Sin generalidades.
|
|
1334
1380
|
|
|
1335
|
-
## 7. Comandos
|
|
1381
|
+
## 7. Comandos de desarrollo
|
|
1336
1382
|
| Comando | Descripcion | Directorio |
|
|
1337
|
-
|
|
1338
|
-
|
|
1383
|
+
|---|---|---|
|
|
1384
|
+
(comandos reales del Makefile, run.sh, package.json scripts, mvnw, etc.)
|
|
1339
1385
|
|
|
1340
1386
|
────────────────────────────────────────────────────────────────
|
|
1341
1387
|
NIVEL 1 — [componente]/architecture.md
|
|
1342
|
-
|
|
1388
|
+
Objetivo: 120-250 lineas. Un archivo por cada componente no trivial.
|
|
1343
1389
|
────────────────────────────────────────────────────────────────
|
|
1344
|
-
Secciones obligatorias:
|
|
1345
1390
|
|
|
1346
1391
|
# [componente] — Arquitectura (NIVEL 1)
|
|
1347
1392
|
|
|
1348
1393
|
## Que hace
|
|
1349
|
-
|
|
1394
|
+
Parrafo 1: describe el rol del componente en lenguaje de negocio + quien lo consume.
|
|
1395
|
+
Parrafo 2 (si hay componentes hermanos): contrasta con ellos. ej. "A diferencia de X que solo escribe en bulk, esta API expone CRUD con paginacion y filtros para el portal."
|
|
1350
1396
|
|
|
1351
1397
|
## Casos de uso principales
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1398
|
+
Tabla con: Caso de uso | Actor (quien lo dispara) | Descripcion + endpoint si se conoce.
|
|
1399
|
+
| Caso de uso | Actor | Descripcion |
|
|
1400
|
+
|---|---|---|
|
|
1401
|
+
| Ingesta de ventas | Proceso batch BAT | POST /api/sales — upsert bulk de ventas finales |
|
|
1402
|
+
| Consulta de productos | Portal Nexus | GET /api/products?eanCode=XXX |
|
|
1355
1403
|
|
|
1356
1404
|
## Stack tecnico
|
|
1357
1405
|
| Item | Valor |
|
|
1358
|
-
|
|
1359
|
-
| Lenguaje |
|
|
1360
|
-
| Framework |
|
|
1361
|
-
| ORM |
|
|
1362
|
-
|
|
|
1363
|
-
(
|
|
1406
|
+
|---|---|
|
|
1407
|
+
| Lenguaje | Java 21 (Temurin LTS) |
|
|
1408
|
+
| Framework | Spring Boot 3.5.6 |
|
|
1409
|
+
| ORM | Spring Data JPA + Hibernate |
|
|
1410
|
+
| Seguridad | Spring Security 6 + JJWT |
|
|
1411
|
+
(versiones REALES del manifest. Si hay librerias clave como POI, MapStruct, HikariCP: incluirlas)
|
|
1364
1412
|
|
|
1365
1413
|
## Puerto y URLs
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1414
|
+
| Recurso | URL |
|
|
1415
|
+
|---|---|
|
|
1416
|
+
| API base | http://localhost:8084 |
|
|
1417
|
+
| Swagger / docs | http://localhost:8084/swagger-ui/index.html |
|
|
1418
|
+
| Perfil activo | development (application-development.properties) |
|
|
1419
|
+
|
|
1420
|
+
## Estructura de capas / paquetes
|
|
1421
|
+
Arbol con los archivos y directorios REALES que leiste. Usar → para anotar inline que hace cada clase o directorio.
|
|
1422
|
+
\`\`\`text
|
|
1423
|
+
paquete.raiz/
|
|
1424
|
+
├── controller/ → endpoints REST, delegan a service, responden ApiResponse<T>
|
|
1425
|
+
│ ├── ClientController → CRUD /api/clients
|
|
1426
|
+
│ ├── SaleController → POST /api/sales, /api/sales/interim-sales
|
|
1427
|
+
│ └── ExportController → GET /api/export/combos (genera .xlsx)
|
|
1428
|
+
├── service/ → interfaces de logica de negocio
|
|
1429
|
+
│ └── impl/ → implementaciones (@Transactional aqui)
|
|
1430
|
+
├── repository/ → Spring Data JPA Repositories
|
|
1431
|
+
├── domain/ → Entidades JPA (@Entity)
|
|
1432
|
+
│ ├── Client, InterimClient → clientes finales y en staging
|
|
1433
|
+
│ ├── Sale, InterimSale → ventas finales y en staging
|
|
1434
|
+
│ └── compositekeys/ → @IdClass para PKs compuestas
|
|
1435
|
+
├── dto/ → contratos de API (Request/Response DTOs)
|
|
1436
|
+
├── mapper/ → MapStruct: Entity ↔ DTO
|
|
1437
|
+
├── security/ → filtros JWT, validacion, handler 401
|
|
1438
|
+
└── configuration/ → CORS, Swagger, SecurityConfig
|
|
1371
1439
|
\`\`\`
|
|
1372
|
-
src
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1440
|
+
(Adaptar a la estructura real del proyecto: puede ser src/, app/, pkg/, etc.)
|
|
1441
|
+
|
|
1442
|
+
## Endpoints reales
|
|
1443
|
+
SOLO los que se leyeron en los CONTROLLER/ROUTER files. Incluir columna Auth si se conoce.
|
|
1444
|
+
| Metodo | Ruta | Auth | Funcion |
|
|
1445
|
+
|---|---|---|---|
|
|
1446
|
+
| GET | /api/clients | JWT | Lista clientes (paginado, filtrable) |
|
|
1447
|
+
| POST | /api/sales | JWT | Upsert bulk de ventas finales |
|
|
1448
|
+
| GET | /api/export/combos | JWT/Azure | Descarga Excel con combos |
|
|
1449
|
+
(querystring params relevantes en la ruta, ej. ?eanCode= , ?page=&size= )
|
|
1450
|
+
|
|
1451
|
+
## Formato de respuesta (si hay wrapper estandar)
|
|
1452
|
+
Si el codigo muestra un wrapper comun para todas las respuestas, documentarlo:
|
|
1453
|
+
\`\`\`json
|
|
1454
|
+
{
|
|
1455
|
+
"status": 200,
|
|
1456
|
+
"message": "Operacion exitosa",
|
|
1457
|
+
"data": [...],
|
|
1458
|
+
"pagination": { "page": 1, "size": 15, "totalElements": 120, "totalPages": 8 }
|
|
1459
|
+
}
|
|
1377
1460
|
\`\`\`
|
|
1461
|
+
Si no hay wrapper, omitir esta seccion.
|
|
1378
1462
|
|
|
1379
1463
|
## Modulos internos
|
|
1380
|
-
| Modulo | Proposito
|
|
1381
|
-
|
|
1382
|
-
|
|
|
1383
|
-
|
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|----------|---------|-----------|
|
|
1395
|
-
| PORT | 8085 | Puerto del servicio |
|
|
1396
|
-
| MONGODB_URI | mongodb://... | Conexion principal |
|
|
1397
|
-
|
|
1398
|
-
## Integraciones con otros servicios / sistemas
|
|
1399
|
-
| Servicio externo | Tipo (HTTP/DB/Queue) | Proposito |
|
|
1464
|
+
| Modulo | Proposito | Doc tecnica |
|
|
1465
|
+
|---|---|---|
|
|
1466
|
+
| seguridad | Autenticacion JWT/Azure, roles, filtro HTTP | modules/security.md |
|
|
1467
|
+
| acceso-datos | JPA, Specifications, pool, entidades | modules/data-access.md |
|
|
1468
|
+
| api-web | Controladores, DTOs, validacion, exportacion | modules/web-api.md |
|
|
1469
|
+
(Agrupar por responsabilidad tecnica real, no inventar modulos)
|
|
1470
|
+
|
|
1471
|
+
## Variables de configuracion clave
|
|
1472
|
+
| Propiedad / Variable | Valor actual | Proposito |
|
|
1473
|
+
|---|---|---|
|
|
1474
|
+
| server.port | 8084 | Puerto de la API |
|
|
1475
|
+
| spring.datasource.url | jdbc:sqlserver://... | Conexion SQL Server |
|
|
1476
|
+
| auth.url | http://57.151.96.13:8000/v1/validate | Servicio externo de validacion JWT |
|
|
1477
|
+
(Valores REALES del archivo de config/env leido. Si no se leyo el archivo, omitir la tabla)
|
|
1400
1478
|
|
|
1401
1479
|
## Como levantar
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1480
|
+
Comando principal primero. Luego paso a paso si existe.
|
|
1481
|
+
\`\`\`bash
|
|
1482
|
+
./run.sh # compila y levanta todo en uno (si existe)
|
|
1483
|
+
\`\`\`
|
|
1484
|
+
O paso a paso:
|
|
1485
|
+
\`\`\`bash
|
|
1486
|
+
source ./scripts/env.sh
|
|
1487
|
+
npm install && npm run dev
|
|
1488
|
+
\`\`\`
|
|
1408
1489
|
|
|
1409
|
-
##
|
|
1410
|
-
|
|
1490
|
+
## Testing (si hay tests en el proyecto)
|
|
1491
|
+
Frameworks, comando para correr, cobertura minima si se menciona en el manifest o config.
|
|
1492
|
+
\`\`\`bash
|
|
1493
|
+
npm test # todos los tests
|
|
1494
|
+
npm test -- --watch # modo watch
|
|
1495
|
+
\`\`\`
|
|
1411
1496
|
|
|
1412
1497
|
────────────────────────────────────────────────────────────────
|
|
1413
1498
|
NIVEL 2 — [componente]/modules/[modulo].md
|
|
1414
|
-
|
|
1499
|
+
Objetivo: 50-120 lineas. Un archivo por modulo significativo.
|
|
1415
1500
|
────────────────────────────────────────────────────────────────
|
|
1416
|
-
Secciones obligatorias:
|
|
1417
1501
|
|
|
1418
|
-
# Modulo: [
|
|
1502
|
+
# Modulo: [Nombre] — [componente]
|
|
1419
1503
|
|
|
1420
1504
|
## Funcion (lenguaje simple)
|
|
1421
|
-
1-2 lineas: "
|
|
1505
|
+
1-2 lineas: "Protege todos los endpoints /api/**. Cada request debe llevar un token JWT valido."
|
|
1422
1506
|
|
|
1423
1507
|
## Funcion (tecnica)
|
|
1424
|
-
1-2 lineas: como esta implementado
|
|
1425
|
-
|
|
1426
|
-
##
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1508
|
+
1-2 lineas: como esta implementado. ej. "Filtro OncePerRequestFilter que extrae el JWT del header Authorization, lo valida contra el servicio externo auth.url, y si es valido establece el SecurityContext."
|
|
1509
|
+
|
|
1510
|
+
## Flujo principal (diagrama ASCII)
|
|
1511
|
+
Para modulos de seguridad, acceso a datos, o cualquiera con logica de decision/secuencia:
|
|
1512
|
+
mostrar el flujo con ASCII art y nombres REALES de clases/metodos.
|
|
1513
|
+
\`\`\`text
|
|
1514
|
+
HTTP Request
|
|
1515
|
+
│
|
|
1516
|
+
▼
|
|
1517
|
+
AuthFilter (OncePerRequestFilter)
|
|
1518
|
+
│
|
|
1519
|
+
├── X-User-Source == "Azure"?
|
|
1520
|
+
│ ▼ SI
|
|
1521
|
+
│ AzureHeaderValidator → construye usuario virtual desde headers
|
|
1522
|
+
│
|
|
1523
|
+
└── NO
|
|
1524
|
+
▼
|
|
1525
|
+
JwtValidator → POST http://auth-service/validate → carga usuario de BD
|
|
1526
|
+
│
|
|
1527
|
+
▼
|
|
1528
|
+
SecurityContextHolder.setAuthentication(...)
|
|
1529
|
+
│
|
|
1530
|
+
▼
|
|
1531
|
+
@PreAuthorize("hasAnyAuthority('ROLE_A','ROLE_B')") en el controller
|
|
1443
1532
|
\`\`\`
|
|
1444
1533
|
|
|
1445
|
-
##
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1534
|
+
## Entidades / modelos relevantes (si aplica)
|
|
1535
|
+
Para modulos de acceso a datos: tabla de entidades con su proposito y notas.
|
|
1536
|
+
| Entidad | Proposito | Notas |
|
|
1537
|
+
|---|---|---|
|
|
1538
|
+
| Client | Clientes finales | Clave compuesta: ClientId |
|
|
1539
|
+
| InterimClient | Clientes en staging | Tabla intermedia antes de procesar |
|
|
1540
|
+
|
|
1541
|
+
## Reglas del modulo
|
|
1542
|
+
- Rutas protegidas: /api/** → autenticacion obligatoria
|
|
1543
|
+
- Rutas publicas: OPTIONS /**, /swagger-ui/**, /*
|
|
1544
|
+
- Sin sesion: STATELESS — sin cookies
|
|
1545
|
+
- ddl-auto=validate → el schema nunca se auto-modifica
|
|
1449
1546
|
|
|
1450
1547
|
## Archivos clave
|
|
1548
|
+
Rutas RELATIVAS al directorio raiz del componente (no rutas absolutas, no solo el manifest).
|
|
1451
1549
|
| Archivo | Rol |
|
|
1452
|
-
|
|
1453
|
-
|
|
|
1454
|
-
|
|
|
1550
|
+
|---|---|
|
|
1551
|
+
| security/AuthFilter.java | Filtro principal — intercepta y valida cada request |
|
|
1552
|
+
| security/JwtValidator.java | Extrae username del JWT, verifica firma y expiracion |
|
|
1553
|
+
| configuration/SecurityConfig.java | Define SecurityFilterChain, rutas publicas/protegidas |
|
|
1554
|
+
| application-development.properties | auth.url, security.token.secret, security.token.expiration |
|
|
1455
1555
|
|
|
1456
1556
|
## Dependencias
|
|
1457
|
-
-
|
|
1458
|
-
-
|
|
1459
|
-
- **Cross-component:** llama a security-api via HTTP para validar JWT
|
|
1557
|
+
- Librerias clave con version si se conoce: io.jsonwebtoken:jjwt:0.9.1, spring-boot-starter-security
|
|
1558
|
+
- Cross-component si corresponde: "llama a http://auth-service:8000/v1/validate para validar tokens"
|
|
1460
1559
|
|
|
1461
1560
|
================================================================
|
|
1462
1561
|
CALIBRACION DE DETALLE
|
|
1463
1562
|
================================================================
|
|
1464
|
-
- NIVEL 0:
|
|
1465
|
-
- NIVEL 1:
|
|
1466
|
-
- NIVEL 2:
|
|
1467
|
-
- Si te queda corto →
|
|
1468
|
-
- Si te queda largo → estas repitiendo o agregando relleno
|
|
1563
|
+
- NIVEL 0: 80-150 lineas
|
|
1564
|
+
- NIVEL 1: 120-250 lineas por componente
|
|
1565
|
+
- NIVEL 2: 50-120 lineas por modulo
|
|
1566
|
+
- Si te queda corto → incluir mas endpoints reales, mas clases en el arbol, mas config values
|
|
1567
|
+
- Si te queda largo → estas repitiendo entre niveles o agregando relleno; recorta
|
|
1469
1568
|
|
|
1470
1569
|
================================================================
|
|
1471
1570
|
QUE NO HACER
|
|
1472
1571
|
================================================================
|
|
1473
1572
|
- NO usar "Inferido", "Probablemente", "(asumido)", "(quizas)", "parece"
|
|
1474
1573
|
- NO repetir lo mismo entre niveles sin agregar valor (cada nivel zoomea mas)
|
|
1475
|
-
- NO dejar tablas vacias ni con placeholders tipo "..."
|
|
1476
|
-
- NO
|
|
1477
|
-
- NO documentar componentes triviales (scripts
|
|
1478
|
-
- NO inventar endpoints, env vars, puertos o schemas que no leiste
|
|
1574
|
+
- NO dejar tablas vacias ni con placeholders tipo "..." o "ver manifest"
|
|
1575
|
+
- NO escribir overview que podria aplicar a cualquier proyecto (tiene que ser especifico de ESTE proyecto)
|
|
1576
|
+
- NO documentar componentes triviales (scripts sueltos, configs simples) con carpeta propia — mencionalos en NIVEL 0 y listo
|
|
1577
|
+
- NO inventar endpoints, env vars, puertos, hosts, clases o schemas que no leiste en los archivos reales
|
|
1479
1578
|
|
|
1480
1579
|
================================================================
|
|
1481
1580
|
FORMATO DE SALIDA — OBLIGATORIO
|
|
@@ -1483,35 +1582,29 @@ FORMATO DE SALIDA — OBLIGATORIO
|
|
|
1483
1582
|
Devolve UNICAMENTE bloques de archivos separados por marcadores ===. Nada de explicaciones extra fuera de los bloques.
|
|
1484
1583
|
|
|
1485
1584
|
IMPORTANTE: TODAS las rutas son RELATIVAS al directorio del proyecto.
|
|
1486
|
-
Los archivos se escriben SIEMPRE dentro de .agent/context/
|
|
1487
1585
|
|
|
1488
|
-
Ejemplos de marcadores:
|
|
1586
|
+
Ejemplos de marcadores validos:
|
|
1489
1587
|
=== .agent/context/architecture.md ===
|
|
1490
1588
|
=== .agent/context/datamart-data-access-api/architecture.md ===
|
|
1491
1589
|
=== .agent/context/datamart-data-access-api/modules/auth.md ===
|
|
1492
1590
|
=== .agent/context/nexus-core-api/architecture.md ===
|
|
1493
|
-
=== .agent/context/nexus-core-api/modules/
|
|
1591
|
+
=== .agent/context/nexus-core-api/modules/clients.md ===
|
|
1494
1592
|
|
|
1495
1593
|
=== .agent/context/architecture.md ===
|
|
1496
|
-
[contenido
|
|
1497
|
-
|
|
1498
|
-
=== .agent/context/nombre-componente-1/architecture.md ===
|
|
1499
|
-
[contenido completo del NIVEL 1 del componente 1]
|
|
1500
|
-
|
|
1501
|
-
=== .agent/context/nombre-componente-1/modules/auth.md ===
|
|
1502
|
-
[contenido completo del NIVEL 2 del modulo auth]
|
|
1594
|
+
[contenido NIVEL 0]
|
|
1503
1595
|
|
|
1504
|
-
=== .agent/context/nombre-componente
|
|
1505
|
-
[contenido
|
|
1596
|
+
=== .agent/context/nombre-componente/architecture.md ===
|
|
1597
|
+
[contenido NIVEL 1]
|
|
1506
1598
|
|
|
1507
|
-
=== .agent/context/nombre-componente
|
|
1508
|
-
|
|
1599
|
+
=== .agent/context/nombre-componente/modules/auth.md ===
|
|
1600
|
+
[contenido NIVEL 2]
|
|
1509
1601
|
|
|
1510
1602
|
REGLAS DE PATHS:
|
|
1511
|
-
-
|
|
1603
|
+
- Arquitectura global: === .agent/context/architecture.md ===
|
|
1512
1604
|
- Por componente: === .agent/context/[nombre-componente]/architecture.md ===
|
|
1513
1605
|
- Por modulo interno: === .agent/context/[nombre-componente]/modules/[nombre-modulo].md ===
|
|
1514
1606
|
- Documenta TODOS los componentes no triviales del DIRECTORIO_TRABAJO
|
|
1607
|
+
- NO escribir nada bajo .agent/docs/ — esa carpeta es de uso manual
|
|
1515
1608
|
- Si existe documentacion previa, ACTUALIZALA preservando lo que sigue siendo valido y agregando lo nuevo`;
|
|
1516
1609
|
const res = await this.runWithFallback('explorer', prompt, 'Exploracion');
|
|
1517
1610
|
const text = extractCliText(res);
|
|
@@ -1541,8 +1634,8 @@ REGLAS DE PATHS:
|
|
|
1541
1634
|
content = content.replace(/^```markdown\s*/i, '').replace(/^```\s*$/gm, '').trim();
|
|
1542
1635
|
if (!content)
|
|
1543
1636
|
continue;
|
|
1544
|
-
//
|
|
1545
|
-
|
|
1637
|
+
// All explorer output goes under .agent/context/ — docs/ is manual-only
|
|
1638
|
+
const relPath = fileName.replace(/^\.agent\/context\//i, '').replace(/^\/+/, '');
|
|
1546
1639
|
let targetPath = null;
|
|
1547
1640
|
if (relPath === 'architecture.md' || relPath === 'ARCHITECTURE.md') {
|
|
1548
1641
|
targetPath = mainArchPath;
|