agentic-kdd 3.5.6 → 3.5.8
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/CLAUDE.md +80 -55
- package/README.md +120 -35
- package/akdd-analyze.cjs +319 -0
- package/bin/akdd.js +8 -0
- package/lock-manager.cjs +545 -0
- package/mem-curator.cjs +290 -513
- package/package.json +1 -1
- package/src/onboard.js +312 -0
- package/src/update.js +154 -33
- package/tdd-gate.cjs +4 -0
- package/templates/.agentic/DESIGN_SYSTEM.fastapi.md +109 -0
- package/templates/.agentic/DESIGN_SYSTEM.nextjs.md +91 -0
- package/templates/.agentic/grafo/akdd-analyze.cjs +319 -0
- package/templates/.agentic/grafo/grafo.cjs +696 -2
- package/templates/.agentic/grafo/lock-manager.cjs +545 -0
- package/templates/.agentic/grafo/mem-curator.cjs +361 -0
package/CLAUDE.md
CHANGED
|
@@ -38,31 +38,6 @@ Variantes: `aa: aprende`, `aa: aprende — módulo [x]`, `aa: aprende [archivo]`
|
|
|
38
38
|
|
|
39
39
|
---
|
|
40
40
|
|
|
41
|
-
## CUANDO VES aa: sprint
|
|
42
|
-
|
|
43
|
-
Lee `.agentic/agentes/09-sprint.md` y ejecuta su protocolo completo.
|
|
44
|
-
Coordina múltiples tareas encadenadas donde el output de cada una alimenta la siguiente.
|
|
45
|
-
La memoria KDD fluye entre todas las tareas del sprint.
|
|
46
|
-
|
|
47
|
-
Variantes:
|
|
48
|
-
- `aa: sprint — [objetivo]` con lista de tareas explícitas
|
|
49
|
-
- `aa: sprint — [objetivo]` sin lista → inferir tareas y proponer antes de ejecutar
|
|
50
|
-
- `aa: sprint skip` → saltar tarea actual y continuar
|
|
51
|
-
- `aa: sprint abort` → cancelar sprint, mantener lo completado
|
|
52
|
-
|
|
53
|
-
---
|
|
54
|
-
|
|
55
|
-
## CUANDO VES aa: aprende
|
|
56
|
-
|
|
57
|
-
Lee `.agentic/agentes/08-aprende.md` y ejecuta su protocolo completo.
|
|
58
|
-
Analiza el proyecto, detecta patrones/errores/decisiones implícitas
|
|
59
|
-
y propone que registrar — siempre pregunta antes de escribir.
|
|
60
|
-
|
|
61
|
-
Variantes: aa: aprende / aa: aprende modulo [x] / aa: aprende [archivo]
|
|
62
|
-
aa: aprende error: [x] / aa: aprende decision: [x] / aa: aprende patron: [x]
|
|
63
|
-
|
|
64
|
-
---
|
|
65
|
-
|
|
66
41
|
## CUANDO VES aa: help
|
|
67
42
|
|
|
68
43
|
Mostrar exactamente esto:
|
|
@@ -89,36 +64,6 @@ Consulta del grafo (en terminal):
|
|
|
89
64
|
akdd update → actualizar Agentic KDD
|
|
90
65
|
```
|
|
91
66
|
|
|
92
|
-
## CUANDO VES aa: sprint
|
|
93
|
-
|
|
94
|
-
Lee `.agentic/agentes/09-sprint.md` y ejecuta su protocolo completo.
|
|
95
|
-
Coordina múltiples tareas encadenadas donde el output de cada una alimenta la siguiente.
|
|
96
|
-
La memoria KDD fluye entre todas las tareas del sprint.
|
|
97
|
-
|
|
98
|
-
Variantes:
|
|
99
|
-
- `aa: sprint — [objetivo]` con lista de tareas explícitas
|
|
100
|
-
- `aa: sprint — [objetivo]` sin lista → inferir tareas y proponer antes de ejecutar
|
|
101
|
-
- `aa: sprint skip` → saltar tarea actual y continuar
|
|
102
|
-
- `aa: sprint abort` → cancelar sprint, mantener lo completado
|
|
103
|
-
|
|
104
|
-
---
|
|
105
|
-
|
|
106
|
-
## CUANDO VES aa: aprende
|
|
107
|
-
|
|
108
|
-
Lee `.agentic/agentes/08-aprende.md` y ejecuta su protocolo.
|
|
109
|
-
Analiza el código, detecta patrones/errores/decisiones implícitas
|
|
110
|
-
y propone qué registrar en memoria KDD antes de escribir nada.
|
|
111
|
-
|
|
112
|
-
Variantes:
|
|
113
|
-
- `aa: aprende` → analiza todo
|
|
114
|
-
- `aa: aprende — módulo [x]` → foco en módulo
|
|
115
|
-
- `aa: aprende [archivo]` → foco en archivo
|
|
116
|
-
- `aa: aprende — error: [x]` → registrar error directo
|
|
117
|
-
- `aa: aprende — decisión: [x]` → registrar decisión directo
|
|
118
|
-
- `aa: aprende — patrón: [x]` → registrar patrón directo
|
|
119
|
-
|
|
120
|
-
---
|
|
121
|
-
|
|
122
67
|
## CUANDO VES aa:
|
|
123
68
|
|
|
124
69
|
```
|
|
@@ -454,3 +399,83 @@ Luego proceder con el pipeline completo como si el dev hubiera escrito `aa:`.
|
|
|
454
399
|
# ============================================================
|
|
455
400
|
# INSTRUCCIONES DEL PROYECTO — agregar las tuyas aquí abajo
|
|
456
401
|
# ============================================================
|
|
402
|
+
|
|
403
|
+
## MODO EXPLORE — aa: explore [objetivo]
|
|
404
|
+
|
|
405
|
+
Antes de implementar, pensar junto al dev sin escribir código.
|
|
406
|
+
|
|
407
|
+
Si el mensaje empieza con `aa: explore` o `aa: think`:
|
|
408
|
+
|
|
409
|
+
1. Leer `.agentic/config.md` y memoria relevante
|
|
410
|
+
2. Analizar el objetivo: ¿qué implica? ¿qué riesgos hay? ¿qué alternativas existen?
|
|
411
|
+
3. Presentar:
|
|
412
|
+
```
|
|
413
|
+
🔍 EXPLORE: [objetivo]
|
|
414
|
+
|
|
415
|
+
Opciones de implementación:
|
|
416
|
+
A) [enfoque 1] — pros/contras
|
|
417
|
+
B) [enfoque 2] — pros/contras
|
|
418
|
+
|
|
419
|
+
Contratos en riesgo: [lista]
|
|
420
|
+
Blast radius estimado: [ALTO/MEDIO/BAJO]
|
|
421
|
+
Archivos que tocaría: [lista]
|
|
422
|
+
|
|
423
|
+
¿Arrancamos con aa: [opción elegida]?
|
|
424
|
+
```
|
|
425
|
+
4. NO escribir ningún archivo. NO correr tests. Solo análisis.
|
|
426
|
+
|
|
427
|
+
---
|
|
428
|
+
|
|
429
|
+
## CONTRACT GUARD — Registro automático post-TDD Gate
|
|
430
|
+
|
|
431
|
+
Después de cada TDD Gate PASS en cualquier ciclo `aa:`, ejecutar:
|
|
432
|
+
|
|
433
|
+
```
|
|
434
|
+
node .agentic/grafo/tdd-gate.cjs run [area]
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
Donde `[area]` es el nombre del módulo implementado (ej: `clients`, `auth`, `invoices`).
|
|
438
|
+
|
|
439
|
+
**Esto es obligatorio.** Sin este paso los contratos no se acumulan.
|
|
440
|
+
|
|
441
|
+
---
|
|
442
|
+
|
|
443
|
+
# ============================================================
|
|
444
|
+
# INSTRUCCIONES DEL PROYECTO — agregar las tuyas aquí abajo
|
|
445
|
+
# ============================================================
|
|
446
|
+
|
|
447
|
+
## LOCK MANAGER — Desarrollo multi-instancia
|
|
448
|
+
|
|
449
|
+
Cuando múltiples instancias de Cursor o Claude Code trabajan en el mismo proyecto,
|
|
450
|
+
usar lock-manager.cjs para evitar colisiones.
|
|
451
|
+
|
|
452
|
+
### Al INICIO de cada ciclo aa:
|
|
453
|
+
```
|
|
454
|
+
node .agentic/grafo/lock-manager.cjs acquire --module=[área] --files=[archivos] --purpose=[tarea]
|
|
455
|
+
```
|
|
456
|
+
Si retorna 🔴 → STOP. Otro agente está trabajando en ese módulo. Esperar o elegir otro módulo.
|
|
457
|
+
|
|
458
|
+
### ANTES de cualquier migration de Prisma o schema:
|
|
459
|
+
```
|
|
460
|
+
node .agentic/grafo/lock-manager.cjs acquire-schema --purpose=migration
|
|
461
|
+
```
|
|
462
|
+
Si retorna 🔴 → STOP. No correr migrations hasta que el schema esté libre.
|
|
463
|
+
|
|
464
|
+
### AL TERMINAR cada ciclo aa: (después de Memory step):
|
|
465
|
+
```
|
|
466
|
+
node .agentic/grafo/lock-manager.cjs release --module=[área]
|
|
467
|
+
node .agentic/grafo/lock-manager.cjs release-schema # solo si se adquirió
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
### Comandos disponibles
|
|
471
|
+
```
|
|
472
|
+
akdd locks → ver locks activos
|
|
473
|
+
akdd locks release-all → liberar todos los locks de esta instancia
|
|
474
|
+
akdd locks check --files=src/auth.ts,src/middleware.ts → verificar archivos
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
### Reglas
|
|
478
|
+
- NUNCA adquirir lock de un módulo que ya tiene otro agente
|
|
479
|
+
- Renovar el lock si la tarea tarda más de 25 minutos: `lock-manager.cjs renew --module=[área]`
|
|
480
|
+
- Si Cursor crashea, los locks expiran solos en 30 minutos
|
|
481
|
+
- Schema lock: máximo 10 minutos — solo para el tiempo de la migration
|
package/README.md
CHANGED
|
@@ -1,68 +1,153 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Agentic KDD v3.6
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> Autonomous development pipeline with persistent knowledge memory. Forces TDD, blocks spec violations before build, and eliminates repeated errors across sessions.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
[](https://www.npmjs.com/package/agentic-kdd)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## What it is
|
|
11
|
+
|
|
12
|
+
Agentic KDD is a framework that runs inside **Cursor** and **Claude Code**. It turns your AI assistant into a disciplined development pipeline with:
|
|
13
|
+
|
|
14
|
+
- **KDD Memory** — errors, patterns and decisions persist across sessions. The agent reads them before every task.
|
|
15
|
+
- **TDD Gate** — deterministic self-healing loop. Forces tests to pass before continuing. Not a suggestion — it's code.
|
|
16
|
+
- **Spec Gate** — blocks changes that contradict documented business rules before writing a single line.
|
|
17
|
+
- **Security Gate** — detects JWT bypass, cross-tenant access and debug flags before build.
|
|
18
|
+
- **Regression Guard** — protects healthy behaviors across cascading file changes.
|
|
19
|
+
- **Contract Guard** — tracks passing test patterns and escalates them to protected contracts over time.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Benchmark results (19 phases, Node.js + Python stacks)
|
|
24
|
+
|
|
25
|
+
| Metric | Without | With | Change |
|
|
26
|
+
|---|---|---|---|
|
|
27
|
+
| Errors per phase | 2.6 | 0.0 | ✅ 100% |
|
|
28
|
+
| Repeated errors | 3 | 0 | ✅ 100% |
|
|
29
|
+
| Tests passing first try | 79% | 100% | ✅ +27pp |
|
|
30
|
+
| Spec drift detections | 3 | 6 | ✅ +100% |
|
|
31
|
+
| Cascade files correct | 4 | 11 | ✅ +175% |
|
|
32
|
+
| Security issues detected | 1 | 2 | ✅ +100% |
|
|
33
|
+
| Autonomous fixes | 4 | 7 | ✅ +75% |
|
|
34
|
+
|
|
35
|
+
> N=1 project per benchmark. Treat as directional, not definitive. Reproducible benchmark repo in progress.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Installation
|
|
6
40
|
|
|
7
41
|
```bash
|
|
8
42
|
npm install -g agentic-kdd
|
|
9
43
|
```
|
|
10
44
|
|
|
11
|
-
|
|
45
|
+
Requires Node.js 18+.
|
|
46
|
+
|
|
47
|
+
---
|
|
12
48
|
|
|
13
|
-
|
|
49
|
+
## Setup
|
|
14
50
|
|
|
15
51
|
```bash
|
|
16
52
|
cd your-project
|
|
17
53
|
akdd init
|
|
18
54
|
```
|
|
19
55
|
|
|
20
|
-
|
|
21
|
-
Then open the project in Cursor or Claude Code and type:
|
|
56
|
+
That's it. Agentic KDD detects your stack (Node.js, Python, PHP), installs `.agentic/`, injects the `dev:kdd` script, and configures the pipeline.
|
|
22
57
|
|
|
58
|
+
For brownfield projects (existing codebase):
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
akdd onboard
|
|
23
62
|
```
|
|
24
|
-
|
|
63
|
+
|
|
64
|
+
Scans your project, maps the stack, suggests a first small task, and pre-populates memory with what it finds.
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Usage
|
|
69
|
+
|
|
70
|
+
Every task goes through `aa:`:
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
aa: implement the clients module with CRUD and tenant isolation
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
The pipeline runs automatically:
|
|
77
|
+
|
|
25
78
|
```
|
|
79
|
+
① Analyst — reads memory, recalls patterns and past errors
|
|
80
|
+
② Spec Gate — blocks if prompt contradicts HIGH-confidence rules
|
|
81
|
+
③ Security Gate — checks CRITICAL/SENSITIVE files before build
|
|
82
|
+
④ Regression Check — verifies changeset won't break protected behaviors
|
|
83
|
+
⑤ Build — implementation
|
|
84
|
+
⑥ TDD Gate — runs tests, self-heals up to 3 iterations
|
|
85
|
+
⑦ QA — validates against spec and memory
|
|
86
|
+
⑧ Preservation Gate — verifies contracts
|
|
87
|
+
⑨ Regression Register — snapshots healthy behaviors
|
|
88
|
+
⑩ Memory — writes errors, patterns and decisions
|
|
89
|
+
⑪ Creative — detects improvement opportunities
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
---
|
|
26
93
|
|
|
27
|
-
|
|
94
|
+
## CLI commands
|
|
28
95
|
|
|
29
96
|
```bash
|
|
30
|
-
akdd
|
|
97
|
+
akdd init # Install in a new project
|
|
98
|
+
akdd onboard # Analyze an existing project (brownfield)
|
|
99
|
+
akdd update # Pull latest from GitHub
|
|
100
|
+
akdd contracts # Contract Guard status
|
|
101
|
+
akdd contracts list # List all contracts
|
|
102
|
+
akdd graph # Knowledge graph state
|
|
103
|
+
akdd metrics # Project metrics
|
|
104
|
+
akdd health # System health check
|
|
105
|
+
akdd analyze # Cross-artifact consistency check
|
|
31
106
|
```
|
|
32
107
|
|
|
33
|
-
|
|
34
|
-
Your memory, config, and knowledge base are never touched.
|
|
108
|
+
---
|
|
35
109
|
|
|
36
|
-
## What
|
|
110
|
+
## What's in the repo
|
|
37
111
|
|
|
38
112
|
```
|
|
39
|
-
|
|
40
|
-
├──
|
|
41
|
-
├──
|
|
42
|
-
├──
|
|
43
|
-
├── .
|
|
44
|
-
└── .
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
│ ├── trabajo.md
|
|
49
|
-
│ ├── errores.md
|
|
50
|
-
│ ├── patrones.md
|
|
51
|
-
│ └── decisiones.md
|
|
52
|
-
├── agentes/ ← 8 agent instruction files
|
|
53
|
-
└── conocimiento/ ← drop your project docs here
|
|
113
|
+
.agentic/
|
|
114
|
+
├── agentes/ # Role instructions (Orchestrator, Analyst, Back, Front, QA, Memory)
|
|
115
|
+
├── grafo/ # Gate modules (tdd-gate, spec-gate, security-gate, regression-guard, contract-guard)
|
|
116
|
+
├── memoria/ # KDD memory files (errors, patterns, decisions, work)
|
|
117
|
+
├── config.md # Project configuration
|
|
118
|
+
└── PLAN.md # Active task
|
|
119
|
+
|
|
120
|
+
CLAUDE.md # Pipeline rules for Claude Code
|
|
121
|
+
.cursor/rules/ # Pipeline rules for Cursor
|
|
54
122
|
```
|
|
55
123
|
|
|
56
|
-
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## How it compares
|
|
127
|
+
|
|
128
|
+
| | OpenSpec | Spec-Kit | Agentic KDD |
|
|
129
|
+
|---|---|---|---|
|
|
130
|
+
| Spec violation gate | ❌ | ❌ | ✅ blocks before build |
|
|
131
|
+
| Security gate | ❌ | ❌ | ✅ blocks before build |
|
|
132
|
+
| Error memory (KDD) | ❌ | ❌ | ✅ persists across sessions |
|
|
133
|
+
| TDD self-healing loop | ❌ | Partial | ✅ deterministic, 3 iterations |
|
|
134
|
+
| Regression protection | ❌ | ❌ | ✅ cascade-tested |
|
|
135
|
+
| Contract escalation | ❌ | ❌ | ✅ candidate → verified → protected |
|
|
136
|
+
| Python support | ❌ | ✅ | ✅ pytest + FastAPI |
|
|
137
|
+
| Brownfield onboarding | ✅ | Partial | ✅ akdd onboard |
|
|
138
|
+
| npm install | ✅ | ❌ | ✅ |
|
|
139
|
+
| MCP tools | 25+ | — | 59 |
|
|
140
|
+
|
|
141
|
+
---
|
|
57
142
|
|
|
58
|
-
|
|
59
|
-
- curl (pre-installed on Mac/Linux; on Windows use Git Bash)
|
|
143
|
+
## Stack support
|
|
60
144
|
|
|
61
|
-
|
|
145
|
+
- **Node.js** — Next.js, Express, Fastify, NestJS + Jest/Vitest
|
|
146
|
+
- **Python** — FastAPI, Django, Flask + pytest
|
|
147
|
+
- **PHP** — Laravel + PHPUnit
|
|
62
148
|
|
|
63
|
-
|
|
64
|
-
- [Documentation](https://github.com/Adrianlpz211/Agentic-KDD/blob/main/docs/kdd-methodology.md)
|
|
149
|
+
---
|
|
65
150
|
|
|
66
151
|
## License
|
|
67
152
|
|
|
68
|
-
MIT
|
|
153
|
+
MIT — Adrián López ([@Adrianlpz211](https://github.com/Adrianlpz211))
|
package/akdd-analyze.cjs
ADDED
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
/**
|
|
3
|
+
* Agentic KDD — Analyzer v1.0
|
|
4
|
+
* Verificación de consistencia cross-artefacto.
|
|
5
|
+
* Compara specs, código y tests para detectar inconsistencias antes de que
|
|
6
|
+
* el agente las encuentre en producción.
|
|
7
|
+
*
|
|
8
|
+
* Uso:
|
|
9
|
+
* node .agentic/grafo/akdd-analyze.cjs run → análisis completo
|
|
10
|
+
* node .agentic/grafo/akdd-analyze.cjs contracts → verifica contratos vs tests
|
|
11
|
+
* node .agentic/grafo/akdd-analyze.cjs memory → verifica memoria vs código
|
|
12
|
+
* node .agentic/grafo/akdd-analyze.cjs spec → verifica spec vs código
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const fs = require('fs');
|
|
16
|
+
const path = require('path');
|
|
17
|
+
|
|
18
|
+
const ROOT = process.cwd();
|
|
19
|
+
const AGENTIC_DIR = path.join(ROOT, '.agentic');
|
|
20
|
+
const MEMORIA_DIR = path.join(AGENTIC_DIR, 'memoria');
|
|
21
|
+
const CONFIG_FILE = path.join(AGENTIC_DIR, 'config.md');
|
|
22
|
+
const SPECS_DIR = path.join(AGENTIC_DIR, 'specs');
|
|
23
|
+
|
|
24
|
+
// ── Findings ──────────────────────────────────────────────────────────────────
|
|
25
|
+
|
|
26
|
+
const findings = [];
|
|
27
|
+
|
|
28
|
+
function addFinding(severity, category, message, suggestion) {
|
|
29
|
+
findings.push({ severity, category, message, suggestion });
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// ── Check 1: Contratos vs test files ─────────────────────────────────────────
|
|
33
|
+
|
|
34
|
+
function checkContractsVsTests() {
|
|
35
|
+
// Open the SQLite DB if available
|
|
36
|
+
const dbPath = path.join(AGENTIC_DIR, 'memoria.db');
|
|
37
|
+
if (!require('fs').existsSync(dbPath)) {
|
|
38
|
+
addFinding('INFO', 'contracts', 'memoria.db no encontrada — sin contratos que verificar', 'Corre akdd init y algunos ciclos aa:');
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
let db;
|
|
43
|
+
try {
|
|
44
|
+
const projNodeModules = path.join(ROOT, 'node_modules');
|
|
45
|
+
if (!module.paths.includes(projNodeModules)) module.paths.unshift(projNodeModules);
|
|
46
|
+
db = new (require('better-sqlite3'))(dbPath);
|
|
47
|
+
} catch(e) {
|
|
48
|
+
addFinding('WARN', 'contracts', 'No se pudo abrir memoria.db: ' + e.message, 'Verifica que better-sqlite3 está instalado');
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
const contracts = db.prepare("SELECT * FROM verified_contracts WHERE status != 'invalidated'").all();
|
|
54
|
+
|
|
55
|
+
if (contracts.length === 0) {
|
|
56
|
+
addFinding('INFO', 'contracts', 'Sin contratos registrados aún', 'Corre ciclos aa: para acumular contratos');
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Check each contract's test file still exists
|
|
61
|
+
for (const c of contracts) {
|
|
62
|
+
if (c.test_file && c.test_file !== 'npm test' && c.test_file !== 'pytest') {
|
|
63
|
+
const testPath = path.join(ROOT, c.test_file);
|
|
64
|
+
if (!fs.existsSync(testPath)) {
|
|
65
|
+
addFinding('HIGH', 'contracts',
|
|
66
|
+
`Contrato [${c.id}] referencia "${c.test_file}" que ya no existe`,
|
|
67
|
+
`Corre akdd contracts verify para actualizar el contrato`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Warn on stale protected contracts
|
|
72
|
+
if (c.status === 'protected' && c.last_verified) {
|
|
73
|
+
const days = Math.floor((Date.now() - new Date(c.last_verified).getTime()) / 86400000);
|
|
74
|
+
if (days > 30) {
|
|
75
|
+
addFinding('WARN', 'contracts',
|
|
76
|
+
`Contrato PROTECTED [${c.module}] no verificado en ${days} días`,
|
|
77
|
+
`Corre akdd contracts gate para re-verificar`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const protected_ = contracts.filter(c => c.status === 'protected').length;
|
|
83
|
+
const verified = contracts.filter(c => c.status === 'verified').length;
|
|
84
|
+
addFinding('INFO', 'contracts',
|
|
85
|
+
`${contracts.length} contratos: ${protected_} PROTECTED, ${verified} VERIFIED`,
|
|
86
|
+
null);
|
|
87
|
+
|
|
88
|
+
} catch(e) {
|
|
89
|
+
addFinding('WARN', 'contracts', 'Error leyendo contratos: ' + e.message, null);
|
|
90
|
+
} finally {
|
|
91
|
+
db.close();
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// ── Check 2: Memoria vs código actual ────────────────────────────────────────
|
|
96
|
+
|
|
97
|
+
function checkMemoryVsCode() {
|
|
98
|
+
const erroresFile = path.join(MEMORIA_DIR, 'errores.md');
|
|
99
|
+
const patronesFile= path.join(MEMORIA_DIR, 'patrones.md');
|
|
100
|
+
|
|
101
|
+
if (!fs.existsSync(erroresFile) && !fs.existsSync(patronesFile)) {
|
|
102
|
+
addFinding('INFO', 'memory', 'Archivos de memoria no encontrados', 'Corre akdd init');
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Check patrones.md for HIGH-confidence rules and verify they're not violated in code
|
|
107
|
+
if (fs.existsSync(patronesFile)) {
|
|
108
|
+
const patrones = fs.readFileSync(patronesFile, 'utf8');
|
|
109
|
+
const highPatterns = patrones.match(/###[^\n]+\n[\s\S]*?\*\*confianza\*\*:\s*ALTA[\s\S]*?(?=###|$)/gi) || [];
|
|
110
|
+
|
|
111
|
+
// Basic structural checks on source files
|
|
112
|
+
const srcFiles = findSourceFiles(ROOT);
|
|
113
|
+
|
|
114
|
+
for (const pattern of highPatterns) {
|
|
115
|
+
const titleMatch = pattern.match(/###\s+(.+)/);
|
|
116
|
+
const ruleMatch = pattern.match(/\*\*regla\*\*:\s*(.+)/i);
|
|
117
|
+
if (!titleMatch || !ruleMatch) continue;
|
|
118
|
+
|
|
119
|
+
const rule = ruleMatch[1].toLowerCase();
|
|
120
|
+
|
|
121
|
+
// Check: if rule mentions "tenant" or "agency_id", verify files filter by it
|
|
122
|
+
if ((rule.includes('tenant') || rule.includes('agency_id')) && srcFiles.length > 0) {
|
|
123
|
+
const routeFiles = srcFiles.filter(f => f.includes('route') || f.includes('router') || f.includes('api'));
|
|
124
|
+
const violations = routeFiles.filter(f => {
|
|
125
|
+
const content = safeRead(f);
|
|
126
|
+
return content && content.includes('findMany') && !content.includes('agency_id') &&
|
|
127
|
+
!content.includes('tenant') && !content.includes('TESTING');
|
|
128
|
+
});
|
|
129
|
+
if (violations.length > 0) {
|
|
130
|
+
addFinding('HIGH', 'memory',
|
|
131
|
+
`Patrón HIGH "${titleMatch[1]}" puede estar violado en: ${violations.slice(0,3).map(f => path.relative(ROOT,f)).join(', ')}`,
|
|
132
|
+
`Revisar manualmente — patrón: ${rule}`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
addFinding('INFO', 'memory', `${highPatterns.length} patrones HIGH verificados contra código`, null);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Check errores.md size
|
|
141
|
+
if (fs.existsSync(erroresFile)) {
|
|
142
|
+
const errLines = fs.readFileSync(erroresFile, 'utf8').split('\n').filter(l => l.startsWith('### ')).length;
|
|
143
|
+
if (errLines > 50) {
|
|
144
|
+
addFinding('WARN', 'memory',
|
|
145
|
+
`errores.md tiene ${errLines} entradas — puede degradar el contexto del agente`,
|
|
146
|
+
`Corre: node .agentic/grafo/mem-curator.cjs run`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// ── Check 3: Config vs stack real ────────────────────────────────────────────
|
|
152
|
+
|
|
153
|
+
function checkConfigVsStack() {
|
|
154
|
+
if (!fs.existsSync(CONFIG_FILE)) {
|
|
155
|
+
addFinding('HIGH', 'config', 'config.md no encontrado', 'Corre akdd init');
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const config = fs.readFileSync(CONFIG_FILE, 'utf8');
|
|
160
|
+
|
|
161
|
+
// Check test command is configured
|
|
162
|
+
const testMatch = config.match(/^\s*test:\s*(.+)$/m);
|
|
163
|
+
if (!testMatch || testMatch[1].trim() === '—' || testMatch[1].trim() === '') {
|
|
164
|
+
addFinding('HIGH', 'config',
|
|
165
|
+
'Comando de tests no configurado en config.md',
|
|
166
|
+
'Agrega: test: npm test (o el comando de tu stack)');
|
|
167
|
+
} else {
|
|
168
|
+
addFinding('INFO', 'config', `Comando de tests: ${testMatch[1].trim()}`, null);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Check Python project has test command pointing to pytest
|
|
172
|
+
const hasPython = fs.existsSync(path.join(ROOT, 'backend', 'requirements.txt')) ||
|
|
173
|
+
fs.existsSync(path.join(ROOT, 'requirements.txt'));
|
|
174
|
+
if (hasPython && testMatch && !testMatch[1].includes('pytest')) {
|
|
175
|
+
addFinding('WARN', 'config',
|
|
176
|
+
'Proyecto Python detectado pero test: no usa pytest',
|
|
177
|
+
`Cambia a: test: cd backend && py -3.13 -m pytest -x -v`);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Check DESIGN_SYSTEM
|
|
181
|
+
const hasDesignSystem = fs.existsSync(path.join(ROOT, 'DESIGN_SYSTEM.md')) ||
|
|
182
|
+
fs.existsSync(path.join(ROOT, '.agentic', 'DESIGN_SYSTEM.md'));
|
|
183
|
+
if (!hasDesignSystem) {
|
|
184
|
+
addFinding('INFO', 'config', 'DESIGN_SYSTEM.md no encontrado',
|
|
185
|
+
'Opcional: crea DESIGN_SYSTEM.md para que el agente Front tenga referencia de tokens');
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// ── Check 4: Specs vs código ──────────────────────────────────────────────────
|
|
190
|
+
|
|
191
|
+
function checkSpecsVsCode() {
|
|
192
|
+
if (!fs.existsSync(SPECS_DIR)) {
|
|
193
|
+
addFinding('INFO', 'specs', 'No hay specs registradas aún', 'Se crean automáticamente durante ciclos aa:');
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const specFiles = fs.readdirSync(SPECS_DIR).filter(f => f.endsWith('.md'));
|
|
198
|
+
if (specFiles.length === 0) {
|
|
199
|
+
addFinding('INFO', 'specs', 'Directorio specs vacío', null);
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
addFinding('INFO', 'specs', `${specFiles.length} specs encontradas`, null);
|
|
204
|
+
|
|
205
|
+
// Check specs for unresolved TODOs
|
|
206
|
+
for (const specFile of specFiles) {
|
|
207
|
+
const content = safeRead(path.join(SPECS_DIR, specFile)) || '';
|
|
208
|
+
const todos = (content.match(/\bTODO\b|\bPENDING\b|\bFIXME\b/gi) || []).length;
|
|
209
|
+
if (todos > 0) {
|
|
210
|
+
addFinding('WARN', 'specs',
|
|
211
|
+
`${specFile} tiene ${todos} TODOs/PENDINGs sin resolver`,
|
|
212
|
+
`Revisar y actualizar o eliminar entradas obsoletas`);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// ── Helpers ───────────────────────────────────────────────────────────────────
|
|
218
|
+
|
|
219
|
+
function findSourceFiles(root, extensions = ['.ts', '.tsx', '.js', '.py']) {
|
|
220
|
+
const results = [];
|
|
221
|
+
const skip = new Set(['node_modules', '.agentic', '.git', '__pycache__', '.next', 'dist', 'build']);
|
|
222
|
+
|
|
223
|
+
function walk(dir) {
|
|
224
|
+
try {
|
|
225
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
226
|
+
if (skip.has(entry.name)) continue;
|
|
227
|
+
const full = path.join(dir, entry.name);
|
|
228
|
+
if (entry.isDirectory()) walk(full);
|
|
229
|
+
else if (extensions.some(e => entry.name.endsWith(e))) results.push(full);
|
|
230
|
+
}
|
|
231
|
+
} catch {}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
walk(root);
|
|
235
|
+
return results;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function safeRead(filePath) {
|
|
239
|
+
try { return fs.readFileSync(filePath, 'utf8'); } catch { return null; }
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// ── Report printer ────────────────────────────────────────────────────────────
|
|
243
|
+
|
|
244
|
+
function printReport() {
|
|
245
|
+
console.log('\n══════════════════════════════════════════════════');
|
|
246
|
+
console.log(' 🔍 Agentic KDD — Analyzer');
|
|
247
|
+
console.log('══════════════════════════════════════════════════');
|
|
248
|
+
|
|
249
|
+
const bySeverity = { HIGH: [], WARN: [], INFO: [] };
|
|
250
|
+
for (const f of findings) {
|
|
251
|
+
(bySeverity[f.severity] || bySeverity.INFO).push(f);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
if (bySeverity.HIGH.length > 0) {
|
|
255
|
+
console.log('\n 🔴 HIGH — requieren atención:');
|
|
256
|
+
for (const f of bySeverity.HIGH) {
|
|
257
|
+
console.log(`\n [${f.category.toUpperCase()}] ${f.message}`);
|
|
258
|
+
if (f.suggestion) console.log(` → ${f.suggestion}`);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if (bySeverity.WARN.length > 0) {
|
|
263
|
+
console.log('\n 🟠 WARN — revisar:');
|
|
264
|
+
for (const f of bySeverity.WARN) {
|
|
265
|
+
console.log(`\n [${f.category.toUpperCase()}] ${f.message}`);
|
|
266
|
+
if (f.suggestion) console.log(` → ${f.suggestion}`);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
if (bySeverity.INFO.length > 0) {
|
|
271
|
+
console.log('\n ✅ INFO:');
|
|
272
|
+
for (const f of bySeverity.INFO) {
|
|
273
|
+
console.log(` [${f.category.toUpperCase()}] ${f.message}`);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const total = findings.length;
|
|
278
|
+
const issues = bySeverity.HIGH.length + bySeverity.WARN.length;
|
|
279
|
+
console.log(`\n Total: ${total} checks | Problemas: ${issues}`);
|
|
280
|
+
|
|
281
|
+
if (issues === 0) {
|
|
282
|
+
console.log(' ✅ Todo consistente — el proyecto está en buen estado.');
|
|
283
|
+
} else if (bySeverity.HIGH.length > 0) {
|
|
284
|
+
console.log(' ⛔ Hay inconsistencias críticas — resolver antes del próximo ciclo aa:');
|
|
285
|
+
process.exit(1);
|
|
286
|
+
} else {
|
|
287
|
+
console.log(' ⚠️ Hay advertencias — revisar cuando sea posible.');
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
console.log('══════════════════════════════════════════════════\n');
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// ── CLI ───────────────────────────────────────────────────────────────────────
|
|
294
|
+
|
|
295
|
+
if (require.main === module) {
|
|
296
|
+
const cmd = process.argv[2] || 'run';
|
|
297
|
+
|
|
298
|
+
if (cmd === 'run') {
|
|
299
|
+
checkContractsVsTests();
|
|
300
|
+
checkMemoryVsCode();
|
|
301
|
+
checkConfigVsStack();
|
|
302
|
+
checkSpecsVsCode();
|
|
303
|
+
} else if (cmd === 'contracts') {
|
|
304
|
+
checkContractsVsTests();
|
|
305
|
+
} else if (cmd === 'memory') {
|
|
306
|
+
checkMemoryVsCode();
|
|
307
|
+
} else if (cmd === 'spec') {
|
|
308
|
+
checkSpecsVsCode();
|
|
309
|
+
} else if (cmd === 'config') {
|
|
310
|
+
checkConfigVsStack();
|
|
311
|
+
} else {
|
|
312
|
+
console.log('Uso: node akdd-analyze.cjs [run|contracts|memory|spec|config]');
|
|
313
|
+
process.exit(0);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
printReport();
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
module.exports = { checkContractsVsTests, checkMemoryVsCode, checkConfigVsStack, checkSpecsVsCode };
|
package/bin/akdd.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
const { init } = require('../src/init');
|
|
5
5
|
const { update } = require('../src/update');
|
|
6
|
+
const { onboard } = require('../src/onboard');
|
|
6
7
|
const { graph } = require('../src/graph');
|
|
7
8
|
const { dashboard } = require('../src/dashboard');
|
|
8
9
|
const { analyze } = require('../src/analyze');
|
|
@@ -24,6 +25,10 @@ const HELP = `
|
|
|
24
25
|
Setup:
|
|
25
26
|
akdd init Install Agentic KDD in the current project
|
|
26
27
|
akdd update Update agents + engine (memory stays intact)
|
|
28
|
+
akdd onboard Analyze existing project + pre-populate memory
|
|
29
|
+
akdd analyze Cross-artifact consistency check
|
|
30
|
+
akdd locks Lock Manager status
|
|
31
|
+
akdd locks release-all Release all locks for this instance
|
|
27
32
|
akdd health System health check — what's configured, what's missing
|
|
28
33
|
akdd health --fix Auto-fix common issues
|
|
29
34
|
|
|
@@ -155,6 +160,9 @@ switch (command) {
|
|
|
155
160
|
|
|
156
161
|
case 'init': init(); break;
|
|
157
162
|
case 'update': update(); break;
|
|
163
|
+
case 'onboard': onboard(); break;
|
|
164
|
+
case 'analyze': runModule('akdd-analyze.cjs', args[0] || 'run'); break;
|
|
165
|
+
case 'locks': runModule('lock-manager.cjs', args[0] || 'status', args[1] || ''); break;
|
|
158
166
|
case 'analyze': analyze(); break;
|
|
159
167
|
|
|
160
168
|
// ── v3.0: Health ──────────────────────────────────────────────────────
|