@saulwade/swl-ses 1.3.8 → 1.4.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/CLAUDE.md +15 -6
- package/README.md +15 -14
- package/agentes/nemesis-auditor-swl.md +161 -0
- package/bin/swl-mcp-server.js +187 -187
- package/bin/swl-webhook-server.js +198 -0
- package/comandos/swl/.evolved.json +22 -22
- package/comandos/swl/adoptar-proyecto.md +21 -1
- package/comandos/swl/claudemd.md +14 -1
- package/comandos/swl/contribuir.md +233 -233
- package/comandos/swl/exportar-vault.md +108 -0
- package/comandos/swl/nemesis.md +122 -0
- package/comandos/swl/nuevo-proyecto.md +24 -2
- package/comandos/swl/salud.md +34 -0
- package/comandos/swl/verificar.md +45 -0
- package/gateway/adapters/base.js +109 -0
- package/gateway/adapters/discord.js +167 -0
- package/gateway/adapters/email.js +221 -0
- package/gateway/adapters/slack.js +192 -0
- package/gateway/adapters/telegram.js +183 -0
- package/gateway/adapters/webhook.js +113 -0
- package/gateway/adapters/whatsapp.js +214 -0
- package/gateway/agent-executor.js +322 -0
- package/gateway/command-relay.js +271 -0
- package/gateway/cron/jobs.js +263 -0
- package/gateway/cron/scheduler.js +322 -0
- package/gateway/cron/store.js +335 -0
- package/gateway/index.js +320 -0
- package/gateway/lib/event-channel.js +191 -0
- package/gateway/session.js +131 -0
- package/gateway/webhook-server.js +324 -0
- package/habilidades/backend-production-resilience/SKILL.md +288 -288
- package/habilidades/benchmark-memoria/SKILL.md +186 -186
- package/habilidades/build-errors-nextjs/SKILL.md +55 -1
- package/habilidades/diagrama-arquitectura/assets/template.html +276 -276
- package/habilidades/doubt-driven-review/SKILL.md +171 -171
- package/habilidades/doubt-driven-review/recursos/EXAMPLES.md +130 -130
- package/habilidades/eval-framework/SKILL.md +212 -212
- package/habilidades/extractor-de-aprendizajes/SKILL.md +20 -10
- package/habilidades/feynman-auditor-swl/SKILL.md +123 -0
- package/habilidades/feynman-auditor-swl/recursos/preguntas-language-agnostic.md +108 -0
- package/habilidades/harness-claude-code/SKILL.md +299 -299
- package/habilidades/infra-github-actions/SKILL.md +166 -166
- package/habilidades/legacy-code-rescue/SKILL.md +267 -267
- package/habilidades/manejo-errores/.evolved.json +8 -8
- package/habilidades/meta-skills-estandar/recursos/convencion-examples.md +93 -93
- package/habilidades/meta-skills-estandar/recursos/skills-as-agents.md +163 -163
- package/habilidades/nextjs-testing/SKILL.md +89 -5
- package/habilidades/node-experto/SKILL.md +37 -1
- package/habilidades/patrones-python/SKILL.md +229 -229
- package/habilidades/patrones-python/recursos/patrones-avanzados.md +469 -469
- package/habilidades/planear-fase/SKILL.md +319 -319
- package/habilidades/react-experto/SKILL.md +45 -4
- package/habilidades/release-semver/.evolved.json +8 -8
- package/habilidades/state-inconsistency-auditor-swl/SKILL.md +166 -0
- package/habilidades/state-inconsistency-auditor-swl/recursos/coupled-state-patterns.md +147 -0
- package/habilidades/tdd-workflow/SKILL.md +36 -4
- package/habilidades/testing-python/SKILL.md +340 -340
- package/habilidades/web-fetcher-routing/SKILL.md +75 -0
- package/hooks/claudemd-bloat-detector.js +161 -161
- package/hooks/inyeccion-contexto.js +8 -3
- package/hooks/lib/agent-routing.js +107 -107
- package/hooks/lib/auto-consolidator.js +335 -335
- package/hooks/lib/error-classifier.js +308 -308
- package/hooks/lib/merkle-audit.js +96 -96
- package/hooks/lib/provenance-tracker.js +191 -191
- package/hooks/lib/rate-limit-ip.js +177 -0
- package/hooks/lib/rate-limit-tracker.js +253 -253
- package/hooks/lib/resource-quota.js +122 -122
- package/hooks/lib/retry-jitter.js +165 -165
- package/hooks/lib/security-net.js +201 -0
- package/hooks/lib/skill-auditor.js +588 -588
- package/hooks/lib/sync-status.js +228 -228
- package/hooks/lib/taint-tracker.js +107 -107
- package/hooks/lib/text-similarity.js +241 -241
- package/hooks/lib/toon-compressor.js +245 -245
- package/hooks/lib/webhook-dedup.js +184 -0
- package/hooks/lib/webhook-verify.js +123 -0
- package/hooks/proteccion-rutas.js +120 -15
- package/hooks/registro-turnos.js +209 -209
- package/hooks/sugerir-regenerar-inventario.js +170 -170
- package/hooks/validar-formato-post-subagente.js +140 -140
- package/hooks/validar-memoria-hook.js +218 -218
- package/instintos/prompt-appendices.yaml +57 -57
- package/manifiestos/agent-output-schemas.json +57 -57
- package/manifiestos/modulos.json +31 -0
- package/manifiestos/skills-lock.json +1114 -1093
- package/package.json +6 -4
- package/plantillas/auditor-veto-template.md +105 -105
- package/plantillas/github-workflows/README.md +47 -47
- package/plantillas/github-workflows/release-please.yml +44 -44
- package/plantillas/github-workflows/swl-ci.yml +107 -107
- package/plantillas/github-workflows/swl-security.yml +51 -51
- package/plugin.json +2 -2
- package/reglas/analisis-previo-tareas-grandes.md +172 -172
- package/reglas/arreglar-al-detectar.md +147 -147
- package/reglas/fragmentos-compartidos.md +152 -152
- package/reglas/harness-claude-code.md +213 -213
- package/reglas/usar-context7.md +226 -226
- package/reglas/usar-sistema-swl.md +251 -0
- package/schemas/diary-entry.schema.json +80 -80
- package/scripts/audit-tools/audit-history.js +330 -0
- package/scripts/audit-tools/bundle-tracker.js +290 -0
- package/scripts/audit-tools/canary-monitor.js +352 -0
- package/scripts/audit-tools/code-profiler.js +605 -0
- package/scripts/audit-tools/dep-doctor.js +320 -0
- package/scripts/audit-tools/env-validator.js +206 -0
- package/scripts/audit-tools/lib/fs-walk.js +48 -0
- package/scripts/audit-tools/lib/output.js +23 -0
- package/scripts/audit-tools/migration-checker.js +392 -0
- package/scripts/audit-tools/pentest-scanner.js +1436 -0
- package/scripts/benchmark-memoria.js +167 -167
- package/scripts/comandos/skills.js +251 -2
- package/scripts/configurar-branch-protection.js +418 -418
- package/scripts/detectar-aprendizajes-duplicados.js +151 -151
- package/scripts/field-report.js +199 -199
- package/scripts/generar-checklists-consolidados.js +273 -273
- package/scripts/generar-inventario.js +420 -420
- package/scripts/generar-matriz-lenguajes.js +271 -271
- package/scripts/lib/artefactos-python.js +43 -43
- package/scripts/lib/benchmark-metrics.js +160 -160
- package/scripts/lib/budget-enforcer.js +252 -252
- package/scripts/lib/configurar-ci.js +380 -380
- package/scripts/lib/contadores-inventario.js +217 -217
- package/scripts/lib/detectar-stack-detallado.js +307 -307
- package/scripts/lib/diary-entry.js +234 -234
- package/scripts/lib/eval-metrics-store.js +218 -218
- package/scripts/lib/eval-quality.js +171 -171
- package/scripts/lib/eval-schemas.js +144 -144
- package/scripts/lib/eval-self-correct.js +106 -106
- package/scripts/lib/eval-validator.js +185 -185
- package/scripts/lib/jaccard-similarity.js +98 -98
- package/scripts/lib/longmemeval-runner.js +125 -125
- package/scripts/lib/npm-version.js +261 -261
- package/scripts/lib/paquetes-conocidos.js +50 -50
- package/scripts/lib/prompt-builder.js +264 -264
- package/scripts/lib/rrf-fusion.js +175 -175
- package/scripts/lib/scoring-instintos.js +277 -277
- package/scripts/lib/semantic-search.js +252 -252
- package/scripts/limpiar-artefactos-python.js +131 -131
- package/scripts/mcp-server/README.md +128 -128
- package/scripts/mcp-server/handlers.js +206 -206
- package/scripts/migrar-csv-a-array.js +168 -168
- package/scripts/migrar-fase-dominio.js +201 -201
- package/scripts/publicar.js +511 -511
- package/scripts/run-eval.js +141 -141
- package/scripts/validar-manifest.js +195 -195
- package/scripts/validar-userland-vacio.js +110 -110
- package/scripts/verificar-release.js +110 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: swl:nemesis
|
|
3
|
+
description: >
|
|
4
|
+
Auditoría iterativa Feynman + State Inconsistency (loop hasta convergencia).
|
|
5
|
+
Invoca el agente nemesis-auditor-swl con los 2 skills subordinados.
|
|
6
|
+
Persiste hallazgos en .planning/audit/findings/.
|
|
7
|
+
allowed-tools: [Read, Grep, Glob, Bash, Write, Agent]
|
|
8
|
+
argument-hint: "[--pass1 | --pass2 | --continue | --modulo <ruta>]"
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# /swl:nemesis — Auditoría iterativa de profundidad
|
|
12
|
+
|
|
13
|
+
Dos auditores en loop: Feynman interroga suposiciones línea por línea; State
|
|
14
|
+
Inconsistency mapea pares de estado acoplado y encuentra mutaciones
|
|
15
|
+
incompletas. Cada pasada alimenta la siguiente hasta que no aparecen hallazgos
|
|
16
|
+
nuevos o se llega al máximo de 6 pasadas.
|
|
17
|
+
|
|
18
|
+
## Cuándo invocar
|
|
19
|
+
|
|
20
|
+
- El módulo pasó `/swl:revisar` con score ≥ 9.0 pero hay sospechas de bugs
|
|
21
|
+
de lógica profunda que el revisor de código no captura (suposiciones
|
|
22
|
+
incorrectas, invariantes rotos, condiciones de carrera sutiles).
|
|
23
|
+
- Antes de un release de componente crítico: auth, pagos, contratos, permisos.
|
|
24
|
+
- Cuando un bug en producción se atribuye a lógica aparentemente correcta —
|
|
25
|
+
usar Nemesis para encontrar el patrón de fallo subyacente.
|
|
26
|
+
- Para módulos legacy con alta deuda técnica donde los tests no cubren los
|
|
27
|
+
caminos de estado.
|
|
28
|
+
|
|
29
|
+
## Cuándo NO invocar
|
|
30
|
+
|
|
31
|
+
- El módulo tiene menos de 200 LOC y es CRUD simple sin lógica de negocio.
|
|
32
|
+
- Se necesita revisión de estilo, naming o cobertura de tests — usar
|
|
33
|
+
`/swl:revisar` en su lugar.
|
|
34
|
+
- El proyecto no tiene `agentes/nemesis-auditor-swl.md` instalado — verificar
|
|
35
|
+
con `ls agentes/ | grep nemesis` antes de invocar.
|
|
36
|
+
- La tarea urgente es un hotfix en producción — Nemesis es deliberado (8-20
|
|
37
|
+
turnos); en incidente activo, usar `/swl:verificar` acotado.
|
|
38
|
+
|
|
39
|
+
## Modos disponibles
|
|
40
|
+
|
|
41
|
+
| Modo | Flag | Descripción |
|
|
42
|
+
|---|---|---|
|
|
43
|
+
| Loop completo (default) | (sin flag) | Pasada 1 (Feynman) + Pasada 2 (State) + N pasadas alternadas hasta convergencia, máximo 6 en total |
|
|
44
|
+
| Solo Feynman | `--pass1` | Una pasada Feynman exhaustiva; no ejecuta State |
|
|
45
|
+
| Solo State | `--pass2` | Una pasada State Inconsistency; puede alimentarse con findings previos de Feynman si existen en `.planning/audit/findings/` |
|
|
46
|
+
| Retomar | `--continue` | Continúa desde la última pasada registrada en `.planning/audit/findings/`; útil si la sesión se interrumpió |
|
|
47
|
+
| Acotar módulo | `--modulo <ruta>` | Limita el scope a un archivo o subdirectorio específico; se puede combinar con cualquier otro flag |
|
|
48
|
+
|
|
49
|
+
## Qué produce
|
|
50
|
+
|
|
51
|
+
Todos los archivos se crean en `.planning/audit/findings/`:
|
|
52
|
+
|
|
53
|
+
| Archivo | Cuándo se genera |
|
|
54
|
+
|---|---|
|
|
55
|
+
| `feynman-pass[N].md` | Al completar cada pasada Feynman (N = número de pasada) |
|
|
56
|
+
| `state-pass[N].md` | Al completar cada pasada State Inconsistency |
|
|
57
|
+
| `nemesis-verified.md` | Al final del loop completo; consolida todos los hallazgos con estado de verificación |
|
|
58
|
+
|
|
59
|
+
Si el directorio `.planning/audit/findings/` no existe, el agente lo crea antes
|
|
60
|
+
de la primera escritura.
|
|
61
|
+
|
|
62
|
+
## Cómo interpretar el reporte
|
|
63
|
+
|
|
64
|
+
Cada hallazgo en los archivos de pasada usa este formato:
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
## [SEVERIDAD] Título del hallazgo
|
|
68
|
+
|
|
69
|
+
**Discovery path**: Feynman-only | State-only | Cross-feed Pass N → Pass M
|
|
70
|
+
**Verification**: Code trace | PoC test | Both
|
|
71
|
+
**Líneas afectadas**: archivo:L1-L2
|
|
72
|
+
|
|
73
|
+
Descripción del problema y por qué es un bug y no solo código sospechoso.
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
**Severidades**:
|
|
77
|
+
|
|
78
|
+
| Nivel | Criterio |
|
|
79
|
+
|---|---|
|
|
80
|
+
| CRITICAL | Explotable sin precondiciones; pérdida de datos o control total |
|
|
81
|
+
| HIGH | Explotable bajo condiciones razonables; impacto severo |
|
|
82
|
+
| MEDIUM | Requiere condiciones específicas; impacto moderado |
|
|
83
|
+
| LOW | Impacto menor o difícil de explotar; documentar para trazabilidad |
|
|
84
|
+
|
|
85
|
+
**Discovery path** indica cuándo se encontró:
|
|
86
|
+
|
|
87
|
+
- `Feynman-only`: Feynman lo detectó; State no lo confirmó ni refutó.
|
|
88
|
+
- `State-only`: State Inconsistency lo encontró analizando mutaciones.
|
|
89
|
+
- `Cross-feed Pass N → Pass M`: Feynman marcó un sospechoso en la pasada N;
|
|
90
|
+
State lo confirmó como bug real en la pasada M (o viceversa). Estos
|
|
91
|
+
hallazgos son los más confiables.
|
|
92
|
+
|
|
93
|
+
**Verification** indica la evidencia disponible:
|
|
94
|
+
|
|
95
|
+
- `Code trace`: el path al bug se puede seguir leyendo el código.
|
|
96
|
+
- `PoC test`: hay un caso de prueba que demuestra el comportamiento incorrecto.
|
|
97
|
+
- `Both`: lo más sólido; implica un test listo para agregar a la suite.
|
|
98
|
+
|
|
99
|
+
## Costo estimado
|
|
100
|
+
|
|
101
|
+
| Modo | Turnos aproximados |
|
|
102
|
+
|---|---|
|
|
103
|
+
| Loop completo, módulo pequeño (< 500 LOC) | 8-12 turnos |
|
|
104
|
+
| Loop completo, módulo mediano (500-2000 LOC) | 12-18 turnos |
|
|
105
|
+
| Loop completo, módulo grande (> 2000 LOC) | 18-30 turnos |
|
|
106
|
+
| Solo `--pass1` o `--pass2` | 4-8 turnos |
|
|
107
|
+
|
|
108
|
+
Para módulos mayores a 5000 LOC, usar `--modulo <ruta>` para acotar el scope.
|
|
109
|
+
Un loop sobre un módulo gigante puede tomar 30+ turnos sin garantía de que los
|
|
110
|
+
hallazgos sean más útiles que los de un subconjunto bien elegido.
|
|
111
|
+
|
|
112
|
+
## Ejemplos de invocación
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
/swl:nemesis # loop completo del proyecto
|
|
116
|
+
/swl:nemesis --modulo src/auth # acotado al módulo auth
|
|
117
|
+
/swl:nemesis --pass1 --modulo src/auth # solo Feynman sobre auth
|
|
118
|
+
/swl:nemesis --pass2 # solo State sobre findings existentes
|
|
119
|
+
/swl:nemesis --continue # retoma desde la última pasada guardada
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
<!-- Adaptado de nemesis-auditor-main bajo MIT License (transmissions11/nemesis-auditor) -->
|
|
@@ -135,11 +135,33 @@ Estructura:
|
|
|
135
135
|
- Si el usuario no definió fases claras, propón una división lógica basada en las respuestas del Bloque C
|
|
136
136
|
- Estado inicial de todas las fases: "Pendiente"
|
|
137
137
|
|
|
138
|
-
## Paso 6 —
|
|
138
|
+
## Paso 6 — Generar CLAUDE.md inicial del proyecto
|
|
139
|
+
|
|
140
|
+
Si NO existe `CLAUDE.md` en la raíz del proyecto, generarlo con la estructura
|
|
141
|
+
mínima definida en `/swl:claudemd init-project`. **OBLIGATORIO** incluir como
|
|
142
|
+
primera sección bajo el título:
|
|
143
|
+
|
|
144
|
+
```markdown
|
|
145
|
+
## Reglas obligatorias
|
|
146
|
+
|
|
147
|
+
@reglas/usar-sistema-swl.md
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Esta referencia carga la matriz operacional del sistema SWL al inicio de cada
|
|
151
|
+
sesión del proyecto y previene que el agente haga trabajo directo cuando
|
|
152
|
+
existe un componente especializado. Sin ella, el proyecto pierde el contrato
|
|
153
|
+
de uso del sistema SWL.
|
|
154
|
+
|
|
155
|
+
Si ya existe `CLAUDE.md` (verificado en Paso 1), revisar que incluya
|
|
156
|
+
`@reglas/usar-sistema-swl.md` en la sección de reglas obligatorias. Si NO
|
|
157
|
+
lo incluye, agregarlo en este paso preservando el resto del contenido.
|
|
158
|
+
|
|
159
|
+
## Paso 7 — Reporte al usuario
|
|
139
160
|
|
|
140
161
|
Al terminar, reporta:
|
|
141
162
|
|
|
142
|
-
1. Lista de archivos creados con sus rutas absolutas
|
|
163
|
+
1. Lista de archivos creados con sus rutas absolutas (incluyendo CLAUDE.md
|
|
164
|
+
si se generó o se modificó)
|
|
143
165
|
2. Resumen de la investigación del agente (cuando esté disponible)
|
|
144
166
|
3. Próximo paso recomendado: "Para comenzar a trabajar en la Fase 1, usa `/swl:discutir-fase 1`"
|
|
145
167
|
4. Si encontraste riesgos o ambigüedades durante la entrevista, listarlos aquí como "Puntos a resolver"
|
package/comandos/swl/salud.md
CHANGED
|
@@ -33,6 +33,34 @@ echo "Reglas: $(ls reglas/*.md 2>/dev/null | wc -l)" && \
|
|
|
33
33
|
echo "Hooks: $(ls hooks/*.js 2>/dev/null | wc -l)"
|
|
34
34
|
```
|
|
35
35
|
|
|
36
|
+
## Paso 0.5 — Detección automática de tier del proyecto
|
|
37
|
+
|
|
38
|
+
Antes de ejecutar los pasos de diagnóstico, /swl:salud detecta el tier del proyecto contando archivos relevantes:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
find . -type f \
|
|
42
|
+
-not -path '*/node_modules/*' \
|
|
43
|
+
-not -path '*/.git/*' \
|
|
44
|
+
-not -path '*/dist/*' \
|
|
45
|
+
-not -path '*/build/*' \
|
|
46
|
+
-not -path '*/.next/*' \
|
|
47
|
+
-not -path '*/coverage/*' \
|
|
48
|
+
-not -path '*/__pycache__/*' \
|
|
49
|
+
-not -path '*/.cache/*' \
|
|
50
|
+
-not -path '*/.planning/sessions/*' \
|
|
51
|
+
| wc -l
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
| Tier | Rango | Características esperadas |
|
|
55
|
+
|---|---|---|
|
|
56
|
+
| **Simple** | <500 archivos | 1 contributor, CI mínimo o ninguno. CLAUDE.md opcional. Skills/agentes opcionales. |
|
|
57
|
+
| **Standard** | 500–5,000 archivos | Equipo pequeño con CI. CLAUDE.md + 1-2 reglas. 2-4 skills. Hooks básicos. |
|
|
58
|
+
| **Complex** | >5,000 archivos | Múltiples contributors, CI activo. Setup completo de 6 capas: agentes + skills + reglas + hooks + instintos + memoria. |
|
|
59
|
+
|
|
60
|
+
El tier detectado se reporta al inicio del SALUD.md generado.
|
|
61
|
+
|
|
62
|
+
**Default ante ambigüedad**: si el conteo cae cerca de 500 (490-510) o 5000 (4900-5100), aplicar el tier superior. Es preferible diagnosticar de más que de menos.
|
|
63
|
+
|
|
36
64
|
## Paso 1 — Diagnóstico de agentes (determinista)
|
|
37
65
|
|
|
38
66
|
Ejecutar script Bash que verifica cada agente mecánicamente:
|
|
@@ -65,6 +93,8 @@ echo "Agentes: $ok OK, $warns advertencias, $errors errores"
|
|
|
65
93
|
|
|
66
94
|
Score de agentes = `(ok / total) * 100`
|
|
67
95
|
|
|
96
|
+
**Restricción de tier**: el análisis cruzado de agentes (cross-check entre `exclusiones` declaradas y rutas reales en `manifiestos/modulos.json`) se ejecuta solo en proyectos **Standard** o **Complex**. En tier Simple, reportar el conteo básico y omitir la validación cruzada.
|
|
97
|
+
|
|
68
98
|
## Paso 2 — Diagnóstico de skills (determinista)
|
|
69
99
|
|
|
70
100
|
```bash
|
|
@@ -109,6 +139,8 @@ grep -r "Skill(" agentes/ comandos/ 2>/dev/null | grep -o '"[^"]*"' | sort | uni
|
|
|
109
139
|
|
|
110
140
|
Score de skills = `((total - errors*10 - warns*2) / total) * 100`, mínimo 0
|
|
111
141
|
|
|
142
|
+
**Restricción de tier**: la detección de skills huérfanos (no referenciados en ningún agente ni comando) se ejecuta solo en proyectos **Standard** o **Complex**. En tier Simple, donde hay menos de 10 skills esperados, la verificación de huérfanos genera falsos positivos y se omite.
|
|
143
|
+
|
|
112
144
|
## Paso 3 — Diagnóstico de comandos (determinista)
|
|
113
145
|
|
|
114
146
|
```bash
|
|
@@ -413,3 +445,5 @@ Presenta resumen con los problemas más críticos. Si hay errores, listarlos tod
|
|
|
413
445
|
- Los scores son aritmética pura. No ajustar el score "porque parece un sistema sano".
|
|
414
446
|
- Si no hay git, omitir verificaciones dependientes y notar la omisión.
|
|
415
447
|
- Si detectas un patrón sistémico (mismo error en múltiples componentes), mencionarlo en recomendaciones.
|
|
448
|
+
|
|
449
|
+
<!-- Patrón de 3 tiers adaptado de Waza/skills/health bajo MIT License (tw93/Waza) -->
|
|
@@ -13,6 +13,7 @@ Eres el coordinador de verificación SWL. Tu trabajo es asegurar la calidad del
|
|
|
13
13
|
| Flag | Efecto |
|
|
14
14
|
|------|--------|
|
|
15
15
|
| (sin flag) | Verificación estándar: tests + linter + revisor-codigo-swl + revisor-seguridad-swl |
|
|
16
|
+
| `--full` | Añade 4 audits ejecutables en paralelo al flujo estándar: `code-profiler.js`, `pentest-scanner.js`, `dep-doctor.js` y secret-scanner. Produce un scorecard agregado 0-100 con thresholds de aprobación. Ver sección "Modo `--full`". |
|
|
16
17
|
| `--ultra` | Añade tercera pasada de **revisión profunda** con Opus 4.7 sobre los hallazgos de los dos revisores. Consolida, prioriza, detecta contradicciones entre reviewers y genera plan de acción. Ideal para fases críticas (auth, pagos, migraciones de schema, endpoints públicos). |
|
|
17
18
|
| `--solo-codigo` | Ejecuta solo revisor-codigo-swl (salta seguridad). Usar solo para refactors internos sin impacto externo. |
|
|
18
19
|
| `--solo-seguridad` | Ejecuta solo revisor-seguridad-swl (salta código). Usar para auditorías de seguridad focalizadas. |
|
|
@@ -576,6 +577,48 @@ El comando:
|
|
|
576
577
|
repetía 2+ veces por sesión con alta variación sobre el alcance exacto. Formalizar
|
|
577
578
|
con flag elimina los 2 mensajes de fricción y deja el scope auditable en el comando.
|
|
578
579
|
|
|
580
|
+
## Modo `--full` — Parallel Scorecard
|
|
581
|
+
|
|
582
|
+
Al pasar el flag `--full`, /swl:verificar lanza en paralelo 4 audits ejecutables además del flujo secuencial estándar (revisor-codigo-swl + revisor-seguridad-swl). Cada audit produce score 0-100 y findings JSON. El scorecard final agrega resultados con thresholds estándar.
|
|
583
|
+
|
|
584
|
+
### Audits paralelos invocados
|
|
585
|
+
|
|
586
|
+
| Tool | Detecta | Comando |
|
|
587
|
+
|---|---|---|
|
|
588
|
+
| `code-profiler.js` | N+1 queries, sync I/O en async, memory leaks, ReDoS, queries unbounded | `node scripts/audit-tools/code-profiler.js .` |
|
|
589
|
+
| `pentest-scanner.js` | XSS, SQLi, SSTI, CORS misconfig, JWT vulnerabilities, prototype pollution | `node scripts/audit-tools/pentest-scanner.js <target>` |
|
|
590
|
+
| `dep-doctor.js` | Deps no usadas, outdated, heavy deps con alternativa | `node scripts/audit-tools/dep-doctor.js .` |
|
|
591
|
+
| `secret-scanner` (hook existente) | Credenciales hardcodeadas | (vía hook) |
|
|
592
|
+
|
|
593
|
+
### Thresholds del scorecard
|
|
594
|
+
|
|
595
|
+
| Score | Status | Acción |
|
|
596
|
+
|---|---|---|
|
|
597
|
+
| ≥80 | READY | Listo para mergear |
|
|
598
|
+
| 60-79 | NEEDS WORK | Hallazgos menores; mergear bajo decisión informada |
|
|
599
|
+
| <60 | NOT READY | Hallazgos críticos; bloquear merge |
|
|
600
|
+
|
|
601
|
+
### Salida agregada
|
|
602
|
+
|
|
603
|
+
El comando produce un reporte tipo:
|
|
604
|
+
|
|
605
|
+
```
|
|
606
|
+
SCORECARD — Audits paralelos
|
|
607
|
+
─────────────────────────────────
|
|
608
|
+
code-profiler: 95 / 100 [READY]
|
|
609
|
+
pentest-scanner: 82 / 100 [READY]
|
|
610
|
+
dep-doctor: 70 / 100 [NEEDS WORK]
|
|
611
|
+
secret-scanner: 100 / 100 [READY]
|
|
612
|
+
─────────────────────────────────
|
|
613
|
+
Score promedio: 86.75 [READY]
|
|
614
|
+
Total findings: 3 (0 críticos, 2 mayores, 1 menor)
|
|
615
|
+
```
|
|
616
|
+
|
|
617
|
+
### Cuándo usar `--full` vs flujo estándar
|
|
618
|
+
|
|
619
|
+
- **Flujo estándar** (`/swl:verificar`): revisión cualitativa por agentes con criterio editorial. Adecuado para PRs pequeños/medianos donde la calidad arquitectónica importa más que cobertura mecánica.
|
|
620
|
+
- **Flag `--full`**: agrega análisis estático y dinámico ejecutable. Adecuado pre-release, audit de seguridad mensual, o features que tocan endpoints, dependencias o lógica compleja.
|
|
621
|
+
|
|
579
622
|
## Reglas de comportamiento
|
|
580
623
|
|
|
581
624
|
- NUNCA marques una fase como APROBADO si hay hallazgos CRÍTICOS de seguridad.
|
|
@@ -583,3 +626,5 @@ con flag elimina los 2 mensajes de fricción y deja el scope auditable en el com
|
|
|
583
626
|
- Si los tests fallan, es siempre CRÍTICO, sin excepción.
|
|
584
627
|
- Las SUGERENCIAS son de largo plazo — no bloquean el avance pero deben documentarse.
|
|
585
628
|
- Si el RESUMEN.md no existe, usa git diff para inferir el alcance. Nunca te bloquees.
|
|
629
|
+
|
|
630
|
+
<!-- El patrón parallel scorecard adaptado de Houseofmvps/ultraship /ship bajo MIT License -->
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Base Adapter — Clase base abstracta para adaptadores de plataforma.
|
|
5
|
+
*
|
|
6
|
+
* Cada plataforma (Telegram, Discord, Webhook) extiende esta clase
|
|
7
|
+
* e implementa los métodos abstractos. El gateway/index.js orquesta
|
|
8
|
+
* múltiples adaptadores de forma uniforme.
|
|
9
|
+
*
|
|
10
|
+
* Patrón adoptado de Hermes Agent (gateway/platforms/base.py).
|
|
11
|
+
*
|
|
12
|
+
* @module gateway/adapters/base
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @abstract
|
|
17
|
+
*/
|
|
18
|
+
class BaseAdapter {
|
|
19
|
+
/**
|
|
20
|
+
* @param {string} name - Nombre de la plataforma (ej: 'telegram').
|
|
21
|
+
* @param {object} config - Configuración específica de la plataforma.
|
|
22
|
+
*/
|
|
23
|
+
constructor(name, config) {
|
|
24
|
+
if (new.target === BaseAdapter) {
|
|
25
|
+
throw new Error('BaseAdapter es abstracto — usar un adaptador concreto.');
|
|
26
|
+
}
|
|
27
|
+
this.name = name;
|
|
28
|
+
this.config = config;
|
|
29
|
+
this.running = false;
|
|
30
|
+
this._messageHandler = null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Inicia la conexión con la plataforma.
|
|
35
|
+
* @abstract
|
|
36
|
+
* @returns {Promise<void>}
|
|
37
|
+
*/
|
|
38
|
+
async start() {
|
|
39
|
+
throw new Error(`${this.name}: start() no implementado`);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Detiene la conexión con la plataforma.
|
|
44
|
+
* @abstract
|
|
45
|
+
* @returns {Promise<void>}
|
|
46
|
+
*/
|
|
47
|
+
async stop() {
|
|
48
|
+
this.running = false;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Envía un mensaje formateado a la plataforma.
|
|
53
|
+
* @abstract
|
|
54
|
+
* @param {object} message
|
|
55
|
+
* @param {string} message.text - Texto del mensaje (Markdown).
|
|
56
|
+
* @param {string} [message.chatId] - Destino específico.
|
|
57
|
+
* @param {string} [message.type] - Tipo: 'notification', 'alert', 'response'.
|
|
58
|
+
* @returns {Promise<boolean>} true si se envió correctamente.
|
|
59
|
+
*/
|
|
60
|
+
async send(message) {
|
|
61
|
+
throw new Error(`${this.name}: send() no implementado`);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Registra un handler para mensajes entrantes de la plataforma.
|
|
66
|
+
* @param {function} handler - Callback (message) => void.
|
|
67
|
+
*/
|
|
68
|
+
onMessage(handler) {
|
|
69
|
+
this._messageHandler = handler;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Emite un mensaje entrante al handler registrado.
|
|
74
|
+
* @protected
|
|
75
|
+
* @param {object} message
|
|
76
|
+
*/
|
|
77
|
+
_emitMessage(message) {
|
|
78
|
+
if (typeof this._messageHandler === 'function') {
|
|
79
|
+
this._messageHandler({
|
|
80
|
+
platform: this.name,
|
|
81
|
+
...message,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Formatea un mensaje SWL para la plataforma específica.
|
|
88
|
+
* Override en cada adaptador para formato nativo (embeds, markdown, etc.).
|
|
89
|
+
*
|
|
90
|
+
* @param {object} swlMessage - Mensaje del sistema SWL.
|
|
91
|
+
* @returns {string} Texto formateado para la plataforma.
|
|
92
|
+
*/
|
|
93
|
+
formatMessage(swlMessage) {
|
|
94
|
+
const { jobName, status, output, type } = swlMessage.payload || swlMessage;
|
|
95
|
+
const lines = [];
|
|
96
|
+
|
|
97
|
+
if (type === 'gateway_notification' || jobName) {
|
|
98
|
+
lines.push(`*${jobName || 'SWL Notificación'}*`);
|
|
99
|
+
if (status) lines.push(`Estado: ${status}`);
|
|
100
|
+
if (output) lines.push(`\`\`\`\n${output.substring(0, 500)}\n\`\`\``);
|
|
101
|
+
} else {
|
|
102
|
+
lines.push(swlMessage.text || JSON.stringify(swlMessage));
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return lines.join('\n');
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
module.exports = BaseAdapter;
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Discord Adapter — Adaptador de plataforma para Discord.
|
|
5
|
+
*
|
|
6
|
+
* Usa discord.js para conectar un bot. Soporta:
|
|
7
|
+
* - Recepción de mensajes en canal dedicado
|
|
8
|
+
* - Envío con embeds para notificaciones estructuradas
|
|
9
|
+
* - Comandos slash nativos
|
|
10
|
+
* - Filtro por guildId y channelId
|
|
11
|
+
*
|
|
12
|
+
* Dependencia: discord.js (npm install discord.js)
|
|
13
|
+
* Si no está instalada, el adaptador se desactiva silenciosamente.
|
|
14
|
+
*
|
|
15
|
+
* Inspirado en Hermes Agent (gateway/platforms/discord.py).
|
|
16
|
+
*
|
|
17
|
+
* @module gateway/adapters/discord
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
const BaseAdapter = require('./base');
|
|
21
|
+
|
|
22
|
+
/** Límite de caracteres por mensaje de Discord. */
|
|
23
|
+
const MAX_MSG_LENGTH = 2000;
|
|
24
|
+
|
|
25
|
+
class DiscordAdapter extends BaseAdapter {
|
|
26
|
+
constructor(config) {
|
|
27
|
+
super('discord', config);
|
|
28
|
+
this._client = null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async start() {
|
|
32
|
+
let Discord;
|
|
33
|
+
try {
|
|
34
|
+
Discord = require('discord.js');
|
|
35
|
+
} catch (_) {
|
|
36
|
+
console.log('[discord] discord.js no instalado. Ejecutar: npm install discord.js');
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const token = this.config.token || process.env.DISCORD_BOT_TOKEN;
|
|
41
|
+
if (!token) {
|
|
42
|
+
console.log('[discord] Token no configurado. Establecer DISCORD_BOT_TOKEN.');
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const { Client, GatewayIntentBits } = Discord;
|
|
47
|
+
|
|
48
|
+
this._client = new Client({
|
|
49
|
+
intents: [
|
|
50
|
+
GatewayIntentBits.Guilds,
|
|
51
|
+
GatewayIntentBits.GuildMessages,
|
|
52
|
+
GatewayIntentBits.MessageContent,
|
|
53
|
+
],
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
this._client.on('ready', () => {
|
|
57
|
+
this.running = true;
|
|
58
|
+
console.log(`[discord] Bot conectado como ${this._client.user.tag}`);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
this._client.on('messageCreate', (msg) => {
|
|
62
|
+
// Ignorar mensajes del bot
|
|
63
|
+
if (msg.author.bot) return;
|
|
64
|
+
|
|
65
|
+
// Filtrar por guild y canal si están configurados
|
|
66
|
+
if (this.config.guildId && msg.guildId !== this.config.guildId) return;
|
|
67
|
+
if (this.config.channelId && msg.channelId !== this.config.channelId) return;
|
|
68
|
+
|
|
69
|
+
const text = msg.content || '';
|
|
70
|
+
const parts = text.split(/\s+/);
|
|
71
|
+
const command = parts[0].startsWith('/') ? parts[0] : null;
|
|
72
|
+
const args = command ? parts.slice(1).join(' ') : '';
|
|
73
|
+
|
|
74
|
+
this._emitMessage({
|
|
75
|
+
chatId: msg.channelId,
|
|
76
|
+
userId: msg.author.id,
|
|
77
|
+
userName: msg.author.username,
|
|
78
|
+
text: text,
|
|
79
|
+
command: command,
|
|
80
|
+
args: args,
|
|
81
|
+
guildId: msg.guildId,
|
|
82
|
+
raw: msg,
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
this._client.on('error', (err) => {
|
|
87
|
+
console.error(`[discord] Error: ${err.message}`);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
await this._client.login(token);
|
|
91
|
+
console.log('[discord] Adaptador iniciado.');
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async stop() {
|
|
95
|
+
if (this._client) {
|
|
96
|
+
try { await this._client.destroy(); } catch (_) {}
|
|
97
|
+
this._client = null;
|
|
98
|
+
}
|
|
99
|
+
this.running = false;
|
|
100
|
+
console.log('[discord] Adaptador detenido.');
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async send(message) {
|
|
104
|
+
if (!this._client) return false;
|
|
105
|
+
|
|
106
|
+
const channelId = message.chatId || this.config.channelId;
|
|
107
|
+
if (!channelId) return false;
|
|
108
|
+
|
|
109
|
+
try {
|
|
110
|
+
const channel = await this._client.channels.fetch(channelId);
|
|
111
|
+
if (!channel || !channel.isTextBased()) return false;
|
|
112
|
+
|
|
113
|
+
const embed = this._buildEmbed(message);
|
|
114
|
+
if (embed) {
|
|
115
|
+
await channel.send({ embeds: [embed] });
|
|
116
|
+
} else {
|
|
117
|
+
const text = this.formatMessage(message);
|
|
118
|
+
// Split si excede límite
|
|
119
|
+
if (text.length > MAX_MSG_LENGTH) {
|
|
120
|
+
const chunks = [];
|
|
121
|
+
for (let i = 0; i < text.length; i += MAX_MSG_LENGTH) {
|
|
122
|
+
chunks.push(text.substring(i, i + MAX_MSG_LENGTH));
|
|
123
|
+
}
|
|
124
|
+
for (const chunk of chunks) await channel.send(chunk);
|
|
125
|
+
} else {
|
|
126
|
+
await channel.send(text);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return true;
|
|
130
|
+
} catch (err) {
|
|
131
|
+
console.error(`[discord] Error enviando: ${err.message}`);
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Construye un embed de Discord para notificaciones estructuradas.
|
|
138
|
+
* @private
|
|
139
|
+
*/
|
|
140
|
+
_buildEmbed(message) {
|
|
141
|
+
const payload = message.payload || message;
|
|
142
|
+
if (!payload.jobName && !payload.title) return null;
|
|
143
|
+
|
|
144
|
+
let Discord;
|
|
145
|
+
try { Discord = require('discord.js'); } catch (_) { return null; }
|
|
146
|
+
|
|
147
|
+
const { EmbedBuilder } = Discord;
|
|
148
|
+
const isError = payload.status === 'error';
|
|
149
|
+
|
|
150
|
+
const embed = new EmbedBuilder()
|
|
151
|
+
.setTitle(payload.jobName || payload.title || 'SWL Notificación')
|
|
152
|
+
.setColor(isError ? 0xFF0000 : 0x00CC66)
|
|
153
|
+
.setTimestamp();
|
|
154
|
+
|
|
155
|
+
if (payload.status) {
|
|
156
|
+
embed.addFields({ name: 'Estado', value: `\`${payload.status}\``, inline: true });
|
|
157
|
+
}
|
|
158
|
+
if (payload.output) {
|
|
159
|
+
const output = payload.output.substring(0, 1000);
|
|
160
|
+
embed.addFields({ name: 'Output', value: `\`\`\`\n${output}\n\`\`\`` });
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return embed;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
module.exports = DiscordAdapter;
|