agentic-kdd 3.5.5 → 3.5.7
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/README.md +120 -35
- package/akdd-analyze.cjs +319 -0
- package/bin/akdd.js +5 -0
- package/mem-curator.cjs +290 -513
- package/package.json +1 -1
- package/src/init.js +1 -1
- package/src/onboard.js +312 -0
- package/src/update.js +154 -33
- package/tdd-gate.cjs +12 -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/mem-curator.cjs +361 -0
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,8 @@ 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
|
|
27
30
|
akdd health System health check — what's configured, what's missing
|
|
28
31
|
akdd health --fix Auto-fix common issues
|
|
29
32
|
|
|
@@ -155,6 +158,8 @@ switch (command) {
|
|
|
155
158
|
|
|
156
159
|
case 'init': init(); break;
|
|
157
160
|
case 'update': update(); break;
|
|
161
|
+
case 'onboard': onboard(); break;
|
|
162
|
+
case 'analyze': runModule('akdd-analyze.cjs', args[0] || 'run'); break;
|
|
158
163
|
case 'analyze': analyze(); break;
|
|
159
164
|
|
|
160
165
|
// ── v3.0: Health ──────────────────────────────────────────────────────
|