@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.
Files changed (148) hide show
  1. package/CLAUDE.md +15 -6
  2. package/README.md +15 -14
  3. package/agentes/nemesis-auditor-swl.md +161 -0
  4. package/bin/swl-mcp-server.js +187 -187
  5. package/bin/swl-webhook-server.js +198 -0
  6. package/comandos/swl/.evolved.json +22 -22
  7. package/comandos/swl/adoptar-proyecto.md +21 -1
  8. package/comandos/swl/claudemd.md +14 -1
  9. package/comandos/swl/contribuir.md +233 -233
  10. package/comandos/swl/exportar-vault.md +108 -0
  11. package/comandos/swl/nemesis.md +122 -0
  12. package/comandos/swl/nuevo-proyecto.md +24 -2
  13. package/comandos/swl/salud.md +34 -0
  14. package/comandos/swl/verificar.md +45 -0
  15. package/gateway/adapters/base.js +109 -0
  16. package/gateway/adapters/discord.js +167 -0
  17. package/gateway/adapters/email.js +221 -0
  18. package/gateway/adapters/slack.js +192 -0
  19. package/gateway/adapters/telegram.js +183 -0
  20. package/gateway/adapters/webhook.js +113 -0
  21. package/gateway/adapters/whatsapp.js +214 -0
  22. package/gateway/agent-executor.js +322 -0
  23. package/gateway/command-relay.js +271 -0
  24. package/gateway/cron/jobs.js +263 -0
  25. package/gateway/cron/scheduler.js +322 -0
  26. package/gateway/cron/store.js +335 -0
  27. package/gateway/index.js +320 -0
  28. package/gateway/lib/event-channel.js +191 -0
  29. package/gateway/session.js +131 -0
  30. package/gateway/webhook-server.js +324 -0
  31. package/habilidades/backend-production-resilience/SKILL.md +288 -288
  32. package/habilidades/benchmark-memoria/SKILL.md +186 -186
  33. package/habilidades/build-errors-nextjs/SKILL.md +55 -1
  34. package/habilidades/diagrama-arquitectura/assets/template.html +276 -276
  35. package/habilidades/doubt-driven-review/SKILL.md +171 -171
  36. package/habilidades/doubt-driven-review/recursos/EXAMPLES.md +130 -130
  37. package/habilidades/eval-framework/SKILL.md +212 -212
  38. package/habilidades/extractor-de-aprendizajes/SKILL.md +20 -10
  39. package/habilidades/feynman-auditor-swl/SKILL.md +123 -0
  40. package/habilidades/feynman-auditor-swl/recursos/preguntas-language-agnostic.md +108 -0
  41. package/habilidades/harness-claude-code/SKILL.md +299 -299
  42. package/habilidades/infra-github-actions/SKILL.md +166 -166
  43. package/habilidades/legacy-code-rescue/SKILL.md +267 -267
  44. package/habilidades/manejo-errores/.evolved.json +8 -8
  45. package/habilidades/meta-skills-estandar/recursos/convencion-examples.md +93 -93
  46. package/habilidades/meta-skills-estandar/recursos/skills-as-agents.md +163 -163
  47. package/habilidades/nextjs-testing/SKILL.md +89 -5
  48. package/habilidades/node-experto/SKILL.md +37 -1
  49. package/habilidades/patrones-python/SKILL.md +229 -229
  50. package/habilidades/patrones-python/recursos/patrones-avanzados.md +469 -469
  51. package/habilidades/planear-fase/SKILL.md +319 -319
  52. package/habilidades/react-experto/SKILL.md +45 -4
  53. package/habilidades/release-semver/.evolved.json +8 -8
  54. package/habilidades/state-inconsistency-auditor-swl/SKILL.md +166 -0
  55. package/habilidades/state-inconsistency-auditor-swl/recursos/coupled-state-patterns.md +147 -0
  56. package/habilidades/tdd-workflow/SKILL.md +36 -4
  57. package/habilidades/testing-python/SKILL.md +340 -340
  58. package/habilidades/web-fetcher-routing/SKILL.md +75 -0
  59. package/hooks/claudemd-bloat-detector.js +161 -161
  60. package/hooks/inyeccion-contexto.js +8 -3
  61. package/hooks/lib/agent-routing.js +107 -107
  62. package/hooks/lib/auto-consolidator.js +335 -335
  63. package/hooks/lib/error-classifier.js +308 -308
  64. package/hooks/lib/merkle-audit.js +96 -96
  65. package/hooks/lib/provenance-tracker.js +191 -191
  66. package/hooks/lib/rate-limit-ip.js +177 -0
  67. package/hooks/lib/rate-limit-tracker.js +253 -253
  68. package/hooks/lib/resource-quota.js +122 -122
  69. package/hooks/lib/retry-jitter.js +165 -165
  70. package/hooks/lib/security-net.js +201 -0
  71. package/hooks/lib/skill-auditor.js +588 -588
  72. package/hooks/lib/sync-status.js +228 -228
  73. package/hooks/lib/taint-tracker.js +107 -107
  74. package/hooks/lib/text-similarity.js +241 -241
  75. package/hooks/lib/toon-compressor.js +245 -245
  76. package/hooks/lib/webhook-dedup.js +184 -0
  77. package/hooks/lib/webhook-verify.js +123 -0
  78. package/hooks/proteccion-rutas.js +120 -15
  79. package/hooks/registro-turnos.js +209 -209
  80. package/hooks/sugerir-regenerar-inventario.js +170 -170
  81. package/hooks/validar-formato-post-subagente.js +140 -140
  82. package/hooks/validar-memoria-hook.js +218 -218
  83. package/instintos/prompt-appendices.yaml +57 -57
  84. package/manifiestos/agent-output-schemas.json +57 -57
  85. package/manifiestos/modulos.json +31 -0
  86. package/manifiestos/skills-lock.json +1114 -1093
  87. package/package.json +6 -4
  88. package/plantillas/auditor-veto-template.md +105 -105
  89. package/plantillas/github-workflows/README.md +47 -47
  90. package/plantillas/github-workflows/release-please.yml +44 -44
  91. package/plantillas/github-workflows/swl-ci.yml +107 -107
  92. package/plantillas/github-workflows/swl-security.yml +51 -51
  93. package/plugin.json +2 -2
  94. package/reglas/analisis-previo-tareas-grandes.md +172 -172
  95. package/reglas/arreglar-al-detectar.md +147 -147
  96. package/reglas/fragmentos-compartidos.md +152 -152
  97. package/reglas/harness-claude-code.md +213 -213
  98. package/reglas/usar-context7.md +226 -226
  99. package/reglas/usar-sistema-swl.md +251 -0
  100. package/schemas/diary-entry.schema.json +80 -80
  101. package/scripts/audit-tools/audit-history.js +330 -0
  102. package/scripts/audit-tools/bundle-tracker.js +290 -0
  103. package/scripts/audit-tools/canary-monitor.js +352 -0
  104. package/scripts/audit-tools/code-profiler.js +605 -0
  105. package/scripts/audit-tools/dep-doctor.js +320 -0
  106. package/scripts/audit-tools/env-validator.js +206 -0
  107. package/scripts/audit-tools/lib/fs-walk.js +48 -0
  108. package/scripts/audit-tools/lib/output.js +23 -0
  109. package/scripts/audit-tools/migration-checker.js +392 -0
  110. package/scripts/audit-tools/pentest-scanner.js +1436 -0
  111. package/scripts/benchmark-memoria.js +167 -167
  112. package/scripts/comandos/skills.js +251 -2
  113. package/scripts/configurar-branch-protection.js +418 -418
  114. package/scripts/detectar-aprendizajes-duplicados.js +151 -151
  115. package/scripts/field-report.js +199 -199
  116. package/scripts/generar-checklists-consolidados.js +273 -273
  117. package/scripts/generar-inventario.js +420 -420
  118. package/scripts/generar-matriz-lenguajes.js +271 -271
  119. package/scripts/lib/artefactos-python.js +43 -43
  120. package/scripts/lib/benchmark-metrics.js +160 -160
  121. package/scripts/lib/budget-enforcer.js +252 -252
  122. package/scripts/lib/configurar-ci.js +380 -380
  123. package/scripts/lib/contadores-inventario.js +217 -217
  124. package/scripts/lib/detectar-stack-detallado.js +307 -307
  125. package/scripts/lib/diary-entry.js +234 -234
  126. package/scripts/lib/eval-metrics-store.js +218 -218
  127. package/scripts/lib/eval-quality.js +171 -171
  128. package/scripts/lib/eval-schemas.js +144 -144
  129. package/scripts/lib/eval-self-correct.js +106 -106
  130. package/scripts/lib/eval-validator.js +185 -185
  131. package/scripts/lib/jaccard-similarity.js +98 -98
  132. package/scripts/lib/longmemeval-runner.js +125 -125
  133. package/scripts/lib/npm-version.js +261 -261
  134. package/scripts/lib/paquetes-conocidos.js +50 -50
  135. package/scripts/lib/prompt-builder.js +264 -264
  136. package/scripts/lib/rrf-fusion.js +175 -175
  137. package/scripts/lib/scoring-instintos.js +277 -277
  138. package/scripts/lib/semantic-search.js +252 -252
  139. package/scripts/limpiar-artefactos-python.js +131 -131
  140. package/scripts/mcp-server/README.md +128 -128
  141. package/scripts/mcp-server/handlers.js +206 -206
  142. package/scripts/migrar-csv-a-array.js +168 -168
  143. package/scripts/migrar-fase-dominio.js +201 -201
  144. package/scripts/publicar.js +511 -511
  145. package/scripts/run-eval.js +141 -141
  146. package/scripts/validar-manifest.js +195 -195
  147. package/scripts/validar-userland-vacio.js +110 -110
  148. 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 — Reporte al usuario
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"
@@ -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;