@ingcrea/aumic-puf 0.0.0-stage → 3.1.0

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 (149) hide show
  1. package/LICENSE +661 -0
  2. package/MANIFEST.es.md +172 -0
  3. package/MANIFEST.md +64 -0
  4. package/PUF-15.md +118 -0
  5. package/PUF_G16_Lighthouse.md +70 -0
  6. package/README.es.md +256 -0
  7. package/README.md +253 -2
  8. package/dist/adapters/astro.d.ts +28 -0
  9. package/dist/adapters/astro.d.ts.map +1 -0
  10. package/dist/adapters/astro.js +68 -0
  11. package/dist/adapters/astro.js.map +1 -0
  12. package/dist/adapters/base.d.ts +53 -0
  13. package/dist/adapters/base.d.ts.map +1 -0
  14. package/dist/adapters/base.js +138 -0
  15. package/dist/adapters/base.js.map +1 -0
  16. package/dist/adapters/cpp.d.ts +27 -0
  17. package/dist/adapters/cpp.d.ts.map +1 -0
  18. package/dist/adapters/cpp.js +48 -0
  19. package/dist/adapters/cpp.js.map +1 -0
  20. package/dist/adapters/csharp.d.ts +28 -0
  21. package/dist/adapters/csharp.d.ts.map +1 -0
  22. package/dist/adapters/csharp.js +100 -0
  23. package/dist/adapters/csharp.js.map +1 -0
  24. package/dist/adapters/flutter.d.ts +27 -0
  25. package/dist/adapters/flutter.d.ts.map +1 -0
  26. package/dist/adapters/flutter.js +49 -0
  27. package/dist/adapters/flutter.js.map +1 -0
  28. package/dist/adapters/java.d.ts +28 -0
  29. package/dist/adapters/java.d.ts.map +1 -0
  30. package/dist/adapters/java.js +123 -0
  31. package/dist/adapters/java.js.map +1 -0
  32. package/dist/adapters/nextjs.d.ts +27 -0
  33. package/dist/adapters/nextjs.d.ts.map +1 -0
  34. package/dist/adapters/nextjs.js +59 -0
  35. package/dist/adapters/nextjs.js.map +1 -0
  36. package/dist/adapters/php.d.ts +27 -0
  37. package/dist/adapters/php.d.ts.map +1 -0
  38. package/dist/adapters/php.js +50 -0
  39. package/dist/adapters/php.js.map +1 -0
  40. package/dist/adapters/python.d.ts +27 -0
  41. package/dist/adapters/python.d.ts.map +1 -0
  42. package/dist/adapters/python.js +55 -0
  43. package/dist/adapters/python.js.map +1 -0
  44. package/dist/adapters/rust.d.ts +27 -0
  45. package/dist/adapters/rust.d.ts.map +1 -0
  46. package/dist/adapters/rust.js +59 -0
  47. package/dist/adapters/rust.js.map +1 -0
  48. package/dist/adapters/selector.d.ts +14 -0
  49. package/dist/adapters/selector.d.ts.map +1 -0
  50. package/dist/adapters/selector.js +65 -0
  51. package/dist/adapters/selector.js.map +1 -0
  52. package/dist/adapters/shell.d.ts +28 -0
  53. package/dist/adapters/shell.d.ts.map +1 -0
  54. package/dist/adapters/shell.js +101 -0
  55. package/dist/adapters/shell.js.map +1 -0
  56. package/dist/adapters/swift.d.ts +28 -0
  57. package/dist/adapters/swift.d.ts.map +1 -0
  58. package/dist/adapters/swift.js +91 -0
  59. package/dist/adapters/swift.js.map +1 -0
  60. package/dist/adapters/typescript.d.ts +27 -0
  61. package/dist/adapters/typescript.d.ts.map +1 -0
  62. package/dist/adapters/typescript.js +63 -0
  63. package/dist/adapters/typescript.js.map +1 -0
  64. package/dist/cli/index.d.ts +10 -0
  65. package/dist/cli/index.d.ts.map +1 -0
  66. package/dist/cli/index.js +259 -0
  67. package/dist/cli/index.js.map +1 -0
  68. package/dist/cli/interfaz.d.ts +21 -0
  69. package/dist/cli/interfaz.d.ts.map +1 -0
  70. package/dist/cli/interfaz.js +71 -0
  71. package/dist/cli/interfaz.js.map +1 -0
  72. package/dist/core/arbol-proyecto.d.ts +18 -0
  73. package/dist/core/arbol-proyecto.d.ts.map +1 -0
  74. package/dist/core/arbol-proyecto.js +119 -0
  75. package/dist/core/arbol-proyecto.js.map +1 -0
  76. package/dist/core/certificado.d.ts +17 -0
  77. package/dist/core/certificado.d.ts.map +1 -0
  78. package/dist/core/certificado.js +49 -0
  79. package/dist/core/certificado.js.map +1 -0
  80. package/dist/core/evaluador-ciberseguridad.d.ts +9 -0
  81. package/dist/core/evaluador-ciberseguridad.d.ts.map +1 -0
  82. package/dist/core/evaluador-ciberseguridad.js +139 -0
  83. package/dist/core/evaluador-ciberseguridad.js.map +1 -0
  84. package/dist/core/evaluador-estilos.d.ts +9 -0
  85. package/dist/core/evaluador-estilos.d.ts.map +1 -0
  86. package/dist/core/evaluador-estilos.js +132 -0
  87. package/dist/core/evaluador-estilos.js.map +1 -0
  88. package/dist/core/evaluador-licencias.d.ts +10 -0
  89. package/dist/core/evaluador-licencias.d.ts.map +1 -0
  90. package/dist/core/evaluador-licencias.js +139 -0
  91. package/dist/core/evaluador-licencias.js.map +1 -0
  92. package/dist/core/evaluador-lighthouse.d.ts +5 -0
  93. package/dist/core/evaluador-lighthouse.d.ts.map +1 -0
  94. package/dist/core/evaluador-lighthouse.js +78 -0
  95. package/dist/core/evaluador-lighthouse.js.map +1 -0
  96. package/dist/core/evaluador-sanitizer.d.ts +5 -0
  97. package/dist/core/evaluador-sanitizer.d.ts.map +1 -0
  98. package/dist/core/evaluador-sanitizer.js +109 -0
  99. package/dist/core/evaluador-sanitizer.js.map +1 -0
  100. package/dist/core/evaluador-sintaxis.d.ts +37 -0
  101. package/dist/core/evaluador-sintaxis.d.ts.map +1 -0
  102. package/dist/core/evaluador-sintaxis.js +372 -0
  103. package/dist/core/evaluador-sintaxis.js.map +1 -0
  104. package/dist/core/evaluador-topologia.d.ts +9 -0
  105. package/dist/core/evaluador-topologia.d.ts.map +1 -0
  106. package/dist/core/evaluador-topologia.js +86 -0
  107. package/dist/core/evaluador-topologia.js.map +1 -0
  108. package/dist/core/evaluador-wp-woo.d.ts +15 -0
  109. package/dist/core/evaluador-wp-woo.d.ts.map +1 -0
  110. package/dist/core/evaluador-wp-woo.js +197 -0
  111. package/dist/core/evaluador-wp-woo.js.map +1 -0
  112. package/dist/core/generador-reporte-html.d.ts +12 -0
  113. package/dist/core/generador-reporte-html.d.ts.map +1 -0
  114. package/dist/core/generador-reporte-html.js +760 -0
  115. package/dist/core/generador-reporte-html.js.map +1 -0
  116. package/dist/core/linter-inline-css.d.ts +20 -0
  117. package/dist/core/linter-inline-css.d.ts.map +1 -0
  118. package/dist/core/linter-inline-css.js +77 -0
  119. package/dist/core/linter-inline-css.js.map +1 -0
  120. package/dist/core/orquestador.d.ts +33 -0
  121. package/dist/core/orquestador.d.ts.map +1 -0
  122. package/dist/core/orquestador.js +518 -0
  123. package/dist/core/orquestador.js.map +1 -0
  124. package/dist/core/punto-control.d.ts +26 -0
  125. package/dist/core/punto-control.d.ts.map +1 -0
  126. package/dist/core/punto-control.js +129 -0
  127. package/dist/core/punto-control.js.map +1 -0
  128. package/dist/core/repositorio-sqlite.d.ts +16 -0
  129. package/dist/core/repositorio-sqlite.d.ts.map +1 -0
  130. package/dist/core/repositorio-sqlite.js +129 -0
  131. package/dist/core/repositorio-sqlite.js.map +1 -0
  132. package/dist/core/types.d.ts +77 -0
  133. package/dist/core/types.d.ts.map +1 -0
  134. package/dist/core/types.js +41 -0
  135. package/dist/core/types.js.map +1 -0
  136. package/dist/hooks/guardian-git.d.ts +23 -0
  137. package/dist/hooks/guardian-git.d.ts.map +1 -0
  138. package/dist/hooks/guardian-git.js +111 -0
  139. package/dist/hooks/guardian-git.js.map +1 -0
  140. package/dist/index.d.ts +13 -0
  141. package/dist/index.d.ts.map +1 -0
  142. package/dist/index.js +29 -0
  143. package/dist/index.js.map +1 -0
  144. package/dist/utils/ejecutor.d.ts +19 -0
  145. package/dist/utils/ejecutor.d.ts.map +1 -0
  146. package/dist/utils/ejecutor.js +44 -0
  147. package/dist/utils/ejecutor.js.map +1 -0
  148. package/package.json +53 -4
  149. package/puf-github-action.yml +30 -0
@@ -0,0 +1,760 @@
1
+ "use strict";
2
+ /**
3
+ * @file generador-reporte-html.ts
4
+ * @description Generador visual del Reporte Forense HTML Soberano para el Protocolo PUF.
5
+ * Diseño visual idéntico y de alta fidelidad basado en el estándar AUM-IC Inspector Forense.
6
+ * Incluye SVG Gauge animado, tarjetas KPI con iconografía y bordes, tabla forense detallada.
7
+ * Estándar AUM-IC 7:2026.
8
+ */
9
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ var desc = Object.getOwnPropertyDescriptor(m, k);
12
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
13
+ desc = { enumerable: true, get: function() { return m[k]; } };
14
+ }
15
+ Object.defineProperty(o, k2, desc);
16
+ }) : (function(o, m, k, k2) {
17
+ if (k2 === undefined) k2 = k;
18
+ o[k2] = m[k];
19
+ }));
20
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
21
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
22
+ }) : function(o, v) {
23
+ o["default"] = v;
24
+ });
25
+ var __importStar = (this && this.__importStar) || (function () {
26
+ var ownKeys = function(o) {
27
+ ownKeys = Object.getOwnPropertyNames || function (o) {
28
+ var ar = [];
29
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
30
+ return ar;
31
+ };
32
+ return ownKeys(o);
33
+ };
34
+ return function (mod) {
35
+ if (mod && mod.__esModule) return mod;
36
+ var result = {};
37
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
38
+ __setModuleDefault(result, mod);
39
+ return result;
40
+ };
41
+ })();
42
+ Object.defineProperty(exports, "__esModule", { value: true });
43
+ exports.GeneradorReporteHtml = void 0;
44
+ const fs_1 = require("fs");
45
+ const path = __importStar(require("path"));
46
+ class GeneradorReporteHtml {
47
+ static async generar(resultado, rutaDestino) {
48
+ const timestamp = new Date().toLocaleString('es-MX', {
49
+ timeZone: 'America/Mexico_City',
50
+ dateStyle: 'full',
51
+ timeStyle: 'medium',
52
+ });
53
+ const compuertas = resultado.compuertas || [];
54
+ const aprobadas = compuertas.filter((c) => c.estado === 'aprobada').length;
55
+ const rechazadas = compuertas.filter((c) => c.estado === 'rechazada').length;
56
+ const omitidas = compuertas.filter((c) => c.estado === 'omitida').length;
57
+ const total = compuertas.length;
58
+ // Score calculado sobre total
59
+ const score = total > 0 ? Math.round(((aprobadas + omitidas * 0.5) / total) * 100) : 100;
60
+ const scoreEntero = Math.min(100, Math.max(0, score));
61
+ let scoreColor = '#10B981';
62
+ let scoreGrade = 'Grado A+';
63
+ let scoreStatus = 'Soberano / Excelente';
64
+ let scoreDesc = 'Sin hallazgos críticos detectados en la auditoría PUF.';
65
+ let scoreStroke = '#10B981';
66
+ if (rechazadas > 0) {
67
+ if (scoreEntero < 50) {
68
+ scoreColor = '#EF4444';
69
+ scoreGrade = 'Grado F';
70
+ scoreStatus = 'Crítico / Riesgo Operativo';
71
+ scoreDesc = 'Se detectaron fallos críticos que impiden la certificación.';
72
+ scoreStroke = '#EF4444';
73
+ }
74
+ else if (scoreEntero < 80) {
75
+ scoreColor = '#F59E0B';
76
+ scoreGrade = 'Grado C';
77
+ scoreStatus = 'Atención Requerida';
78
+ scoreDesc = 'Existen compuertas rechazadas que requieren remediación inmediata.';
79
+ scoreStroke = '#F59E0B';
80
+ }
81
+ else {
82
+ scoreColor = '#F59E0B';
83
+ scoreGrade = 'Grado B';
84
+ scoreStatus = 'Desviaciones Menores';
85
+ scoreDesc = 'Incidencias activas detectadas en la matriz forense.';
86
+ scoreStroke = '#F59E0B';
87
+ }
88
+ }
89
+ // Circumference con r=54 -> 2 * PI * 54 = 339.29200658769764
90
+ const radius = 54;
91
+ const circumference = 2 * Math.PI * radius;
92
+ const strokeDashoffset = circumference - (scoreEntero / 100) * circumference;
93
+ const escapeHtml = (str) => {
94
+ if (!str)
95
+ return '';
96
+ return String(str)
97
+ .replace(/&/g, '&amp;')
98
+ .replace(/</g, '&lt;')
99
+ .replace(/>/g, '&gt;')
100
+ .replace(/"/g, '&quot;');
101
+ };
102
+ const compuertasRows = compuertas.map((c) => {
103
+ let badgeClass = 'badge-success';
104
+ let badgeText = 'APROBADA';
105
+ let icon = '✔';
106
+ if (c.estado === 'rechazada') {
107
+ badgeClass = 'badge-status';
108
+ badgeText = 'RECHAZADA';
109
+ icon = '✖';
110
+ }
111
+ else if (c.estado === 'omitida') {
112
+ badgeClass = 'badge-warn';
113
+ badgeText = 'OMITIDA';
114
+ icon = '~';
115
+ }
116
+ return `
117
+ <tr>
118
+ <td><strong style="color: #F8FAFC; font-family: var(--font-mono); font-size: 0.85rem;">${escapeHtml(c.id)}</strong></td>
119
+ <td><span style="font-weight: 600; color: #F1F5F9;">${escapeHtml(c.nombre)}</span></td>
120
+ <td><span class="badge ${badgeClass}">${icon} ${badgeText}</span></td>
121
+ <td style="color: #94A3B8; font-size: 0.82rem; line-height: 1.4;">${escapeHtml(c.detalle)}</td>
122
+ <td><span class="code-pill" title="${escapeHtml(c.evidencia)}">${escapeHtml(c.evidencia)}</span></td>
123
+ <td style="text-align: right; color: var(--text-dim); font-size: 0.8rem; font-family: var(--font-mono); white-space: nowrap;">${c.tiempoEjecucionMs} ms</td>
124
+ </tr>
125
+ `;
126
+ }).join('');
127
+ const html = `<!DOCTYPE html>
128
+ <html lang="es">
129
+ <head>
130
+ <meta charset="UTF-8">
131
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
132
+ <title>AUM-IC Forensics | Reporte Ejecutivo de Inspección PUF</title>
133
+ <link rel="preconnect" href="https://fonts.googleapis.com">
134
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
135
+ <link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap" rel="stylesheet">
136
+ <style>
137
+ :root {
138
+ --bg: #060911;
139
+ --card-bg: rgba(13, 20, 36, 0.72);
140
+ --card-border: rgba(255, 255, 255, 0.08);
141
+ --card-hover: rgba(25, 36, 62, 0.75);
142
+ --gold: #D4AF37;
143
+ --gold-light: #F6E05E;
144
+ --gold-glow: rgba(212, 175, 55, 0.25);
145
+ --text: #F1F5F9;
146
+ --text-muted: #94A3B8;
147
+ --text-dim: #64748B;
148
+ --danger: #EF4444;
149
+ --danger-bg: rgba(239, 68, 68, 0.12);
150
+ --warning: #F59E0B;
151
+ --warning-bg: rgba(245, 158, 11, 0.12);
152
+ --success: #10B981;
153
+ --success-bg: rgba(16, 185, 129, 0.12);
154
+ --info: #38BDF8;
155
+ --info-bg: rgba(56, 189, 248, 0.12);
156
+ --font-sans: 'Plus Jakarta Sans', system-ui, -apple-system, sans-serif;
157
+ --font-mono: 'JetBrains Mono', monospace;
158
+ }
159
+
160
+ * {
161
+ box-sizing: border-box;
162
+ margin: 0;
163
+ padding: 0;
164
+ }
165
+
166
+ body {
167
+ background-color: var(--bg);
168
+ background-image:
169
+ radial-gradient(at 0% 0%, rgba(212, 175, 55, 0.08) 0px, transparent 50%),
170
+ radial-gradient(at 100% 0%, rgba(56, 189, 248, 0.08) 0px, transparent 50%),
171
+ radial-gradient(at 50% 100%, rgba(16, 185, 129, 0.05) 0px, transparent 50%);
172
+ background-attachment: fixed;
173
+ color: var(--text);
174
+ font-family: var(--font-sans);
175
+ line-height: 1.6;
176
+ -webkit-font-smoothing: antialiased;
177
+ padding: 32px 20px 60px;
178
+ }
179
+
180
+ .container {
181
+ max-width: 1240px;
182
+ margin: 0 auto;
183
+ }
184
+
185
+ .header {
186
+ background: var(--card-bg);
187
+ backdrop-filter: blur(16px);
188
+ -webkit-backdrop-filter: blur(16px);
189
+ border: 1px solid var(--card-border);
190
+ border-radius: 20px;
191
+ padding: 32px 36px;
192
+ margin-bottom: 28px;
193
+ display: flex;
194
+ justify-content: space-between;
195
+ align-items: center;
196
+ flex-wrap: wrap;
197
+ gap: 24px;
198
+ box-shadow: 0 20px 40px -15px rgba(0, 0, 0, 0.5);
199
+ position: relative;
200
+ overflow: hidden;
201
+ }
202
+
203
+ .header::before {
204
+ content: '';
205
+ position: absolute;
206
+ top: 0;
207
+ left: 0;
208
+ right: 0;
209
+ height: 2px;
210
+ background: linear-gradient(90deg, transparent, var(--gold), transparent);
211
+ }
212
+
213
+ .brand-meta {
214
+ display: flex;
215
+ align-items: center;
216
+ gap: 12px;
217
+ margin-bottom: 8px;
218
+ }
219
+
220
+ .pill-badge {
221
+ display: inline-flex;
222
+ align-items: center;
223
+ gap: 6px;
224
+ font-family: var(--font-mono);
225
+ font-size: 0.75rem;
226
+ font-weight: 600;
227
+ text-transform: uppercase;
228
+ letter-spacing: 0.05em;
229
+ padding: 4px 10px;
230
+ border-radius: 9999px;
231
+ background: rgba(212, 175, 55, 0.1);
232
+ border: 1px solid rgba(212, 175, 55, 0.3);
233
+ color: var(--gold-light);
234
+ }
235
+
236
+ .pill-badge .dot {
237
+ width: 6px;
238
+ height: 6px;
239
+ border-radius: 50%;
240
+ background: var(--gold);
241
+ box-shadow: 0 0 8px var(--gold);
242
+ }
243
+
244
+ .header-title {
245
+ font-size: 2.1rem;
246
+ font-weight: 800;
247
+ letter-spacing: -0.03em;
248
+ color: #FFFFFF;
249
+ margin-bottom: 6px;
250
+ }
251
+
252
+ .header-title .accent {
253
+ background: linear-gradient(135deg, #FFFFFF 30%, var(--gold-light) 100%);
254
+ -webkit-background-clip: text;
255
+ -webkit-text-fill-color: transparent;
256
+ }
257
+
258
+ .target-url {
259
+ display: flex;
260
+ align-items: center;
261
+ gap: 8px;
262
+ color: var(--text-muted);
263
+ font-size: 0.9rem;
264
+ margin-bottom: 8px;
265
+ }
266
+
267
+ .target-url span {
268
+ font-weight: 600;
269
+ color: var(--text-dim);
270
+ text-transform: uppercase;
271
+ font-size: 0.75rem;
272
+ letter-spacing: 0.05em;
273
+ }
274
+
275
+ .target-url a {
276
+ color: var(--info);
277
+ text-decoration: none;
278
+ font-family: var(--font-mono);
279
+ word-break: break-all;
280
+ }
281
+
282
+ .timestamp-box {
283
+ font-size: 0.8rem;
284
+ color: var(--text-dim);
285
+ font-family: var(--font-mono);
286
+ }
287
+
288
+ .health-summary {
289
+ display: flex;
290
+ align-items: center;
291
+ gap: 20px;
292
+ background: rgba(6, 11, 22, 0.6);
293
+ border: 1px solid rgba(255, 255, 255, 0.06);
294
+ border-radius: 16px;
295
+ padding: 16px 24px;
296
+ }
297
+
298
+ .gauge-wrapper {
299
+ position: relative;
300
+ width: 120px;
301
+ height: 120px;
302
+ display: flex;
303
+ align-items: center;
304
+ justify-content: center;
305
+ }
306
+
307
+ .gauge-svg {
308
+ width: 120px;
309
+ height: 120px;
310
+ transform: rotate(-90deg);
311
+ }
312
+
313
+ .gauge-bg {
314
+ fill: none;
315
+ stroke: rgba(255, 255, 255, 0.06);
316
+ stroke-width: 10;
317
+ }
318
+
319
+ .gauge-meter {
320
+ fill: none;
321
+ stroke: ${scoreStroke};
322
+ stroke-width: 10;
323
+ stroke-linecap: round;
324
+ stroke-dasharray: ${circumference};
325
+ stroke-dashoffset: ${strokeDashoffset};
326
+ transition: stroke-dashoffset 1s ease-in-out;
327
+ filter: drop-shadow(0 0 6px ${scoreStroke});
328
+ }
329
+
330
+ .gauge-content {
331
+ position: absolute;
332
+ display: flex;
333
+ flex-direction: column;
334
+ align-items: center;
335
+ justify-content: center;
336
+ text-align: center;
337
+ }
338
+
339
+ .gauge-score {
340
+ font-size: 1.7rem;
341
+ font-weight: 800;
342
+ font-family: var(--font-mono);
343
+ color: #FFFFFF;
344
+ line-height: 1;
345
+ }
346
+
347
+ .gauge-grade {
348
+ font-size: 0.7rem;
349
+ font-weight: 700;
350
+ color: ${scoreColor};
351
+ text-transform: uppercase;
352
+ letter-spacing: 0.05em;
353
+ margin-top: 4px;
354
+ }
355
+
356
+ .health-details {
357
+ display: flex;
358
+ flex-direction: column;
359
+ gap: 3px;
360
+ }
361
+
362
+ .health-label {
363
+ font-size: 0.72rem;
364
+ text-transform: uppercase;
365
+ letter-spacing: 0.08em;
366
+ color: var(--text-dim);
367
+ font-weight: 600;
368
+ }
369
+
370
+ .health-status {
371
+ font-size: 1.15rem;
372
+ font-weight: 700;
373
+ color: #FFFFFF;
374
+ }
375
+
376
+ .health-desc {
377
+ font-size: 0.8rem;
378
+ color: var(--text-muted);
379
+ max-width: 200px;
380
+ line-height: 1.3;
381
+ }
382
+
383
+ .stats-grid {
384
+ display: grid;
385
+ grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
386
+ gap: 16px;
387
+ margin-bottom: 32px;
388
+ }
389
+
390
+ .stat-card {
391
+ background: var(--card-bg);
392
+ backdrop-filter: blur(12px);
393
+ -webkit-backdrop-filter: blur(12px);
394
+ border: 1px solid var(--card-border);
395
+ border-radius: 16px;
396
+ padding: 20px 22px;
397
+ display: flex;
398
+ flex-direction: column;
399
+ gap: 10px;
400
+ transition: transform 0.2s, border-color 0.2s;
401
+ }
402
+
403
+ .stat-card:hover {
404
+ transform: translateY(-2px);
405
+ border-color: rgba(255, 255, 255, 0.15);
406
+ }
407
+
408
+ .stat-header {
409
+ display: flex;
410
+ justify-content: space-between;
411
+ align-items: center;
412
+ }
413
+
414
+ .stat-label {
415
+ font-size: 0.75rem;
416
+ text-transform: uppercase;
417
+ letter-spacing: 0.06em;
418
+ color: var(--text-muted);
419
+ font-weight: 600;
420
+ }
421
+
422
+ .stat-icon {
423
+ width: 28px;
424
+ height: 28px;
425
+ border-radius: 8px;
426
+ display: flex;
427
+ align-items: center;
428
+ justify-content: center;
429
+ font-size: 0.85rem;
430
+ }
431
+
432
+ .stat-icon.blue {
433
+ background: var(--info-bg);
434
+ color: var(--info);
435
+ border: 1px solid rgba(56, 189, 248, 0.2);
436
+ }
437
+
438
+ .stat-icon.green {
439
+ background: var(--success-bg);
440
+ color: var(--success);
441
+ border: 1px solid rgba(16, 185, 129, 0.2);
442
+ }
443
+
444
+ .stat-icon.red {
445
+ background: var(--danger-bg);
446
+ color: var(--danger);
447
+ border: 1px solid rgba(239, 68, 68, 0.2);
448
+ }
449
+
450
+ .stat-icon.yellow {
451
+ background: var(--warning-bg);
452
+ color: var(--warning);
453
+ border: 1px solid rgba(245, 158, 11, 0.2);
454
+ }
455
+
456
+ .stat-value {
457
+ font-size: 2.2rem;
458
+ font-weight: 800;
459
+ font-family: var(--font-mono);
460
+ line-height: 1;
461
+ color: #FFFFFF;
462
+ }
463
+
464
+ .stat-sub {
465
+ font-size: 0.75rem;
466
+ color: var(--text-dim);
467
+ }
468
+
469
+ .section {
470
+ background: var(--card-bg);
471
+ backdrop-filter: blur(12px);
472
+ -webkit-backdrop-filter: blur(12px);
473
+ border: 1px solid var(--card-border);
474
+ border-radius: 16px;
475
+ padding: 26px 28px;
476
+ margin-bottom: 24px;
477
+ }
478
+
479
+ .section-header {
480
+ display: flex;
481
+ justify-content: space-between;
482
+ align-items: center;
483
+ margin-bottom: 18px;
484
+ padding-bottom: 14px;
485
+ border-bottom: 1px solid rgba(255, 255, 255, 0.06);
486
+ }
487
+
488
+ .section-title {
489
+ font-size: 1.15rem;
490
+ font-weight: 700;
491
+ color: #FFFFFF;
492
+ display: flex;
493
+ align-items: center;
494
+ gap: 10px;
495
+ }
496
+
497
+ .section-count {
498
+ font-size: 0.75rem;
499
+ font-weight: 700;
500
+ font-family: var(--font-mono);
501
+ padding: 4px 10px;
502
+ border-radius: 9999px;
503
+ }
504
+
505
+ .section-count.danger {
506
+ background: var(--danger-bg);
507
+ color: var(--danger);
508
+ border: 1px solid rgba(239, 68, 68, 0.3);
509
+ }
510
+
511
+ .section-count.warning {
512
+ background: var(--warning-bg);
513
+ color: var(--warning);
514
+ border: 1px solid rgba(245, 158, 11, 0.3);
515
+ }
516
+
517
+ .section-count.success {
518
+ background: var(--success-bg);
519
+ color: var(--success);
520
+ border: 1px solid rgba(16, 185, 129, 0.3);
521
+ }
522
+
523
+ .table-container {
524
+ overflow-x: auto;
525
+ border-radius: 12px;
526
+ border: 1px solid rgba(255, 255, 255, 0.06);
527
+ background: rgba(8, 13, 24, 0.5);
528
+ }
529
+
530
+ table {
531
+ width: 100%;
532
+ border-collapse: collapse;
533
+ text-align: left;
534
+ font-size: 0.88rem;
535
+ }
536
+
537
+ th {
538
+ background: rgba(15, 23, 42, 0.85);
539
+ color: var(--text-muted);
540
+ font-weight: 600;
541
+ text-transform: uppercase;
542
+ font-size: 0.72rem;
543
+ letter-spacing: 0.06em;
544
+ padding: 14px 18px;
545
+ border-bottom: 1px solid rgba(255, 255, 255, 0.08);
546
+ }
547
+
548
+ td {
549
+ padding: 14px 18px;
550
+ border-bottom: 1px solid rgba(255, 255, 255, 0.04);
551
+ color: var(--text);
552
+ vertical-align: middle;
553
+ }
554
+
555
+ tr:last-child td {
556
+ border-bottom: none;
557
+ }
558
+
559
+ tr:hover td {
560
+ background: rgba(255, 255, 255, 0.02);
561
+ }
562
+
563
+ .code-pill {
564
+ font-family: var(--font-mono);
565
+ font-size: 0.78rem;
566
+ background: rgba(255, 255, 255, 0.05);
567
+ border: 1px solid rgba(255, 255, 255, 0.08);
568
+ padding: 3px 8px;
569
+ border-radius: 6px;
570
+ color: #E2E8F0;
571
+ max-width: 320px;
572
+ display: inline-block;
573
+ overflow: hidden;
574
+ text-overflow: ellipsis;
575
+ white-space: nowrap;
576
+ vertical-align: middle;
577
+ }
578
+
579
+ .badge {
580
+ display: inline-flex;
581
+ align-items: center;
582
+ gap: 4px;
583
+ font-size: 0.72rem;
584
+ font-weight: 700;
585
+ padding: 3px 8px;
586
+ border-radius: 6px;
587
+ font-family: var(--font-mono);
588
+ text-transform: uppercase;
589
+ }
590
+
591
+ .badge-success {
592
+ background: var(--success-bg);
593
+ color: var(--success);
594
+ border: 1px solid rgba(16, 185, 129, 0.3);
595
+ }
596
+
597
+ .badge-status {
598
+ background: var(--danger-bg);
599
+ color: var(--danger);
600
+ border: 1px solid rgba(239, 68, 68, 0.3);
601
+ }
602
+
603
+ .badge-warn {
604
+ background: var(--warning-bg);
605
+ color: var(--warning);
606
+ border: 1px solid rgba(245, 158, 11, 0.3);
607
+ }
608
+
609
+ .footer {
610
+ text-align: center;
611
+ margin-top: 48px;
612
+ padding-top: 24px;
613
+ border-top: 1px solid rgba(255, 255, 255, 0.06);
614
+ color: var(--text-dim);
615
+ font-size: 0.8rem;
616
+ }
617
+
618
+ .footer a {
619
+ color: var(--gold);
620
+ text-decoration: none;
621
+ font-weight: 600;
622
+ }
623
+
624
+ .footer a:hover {
625
+ text-decoration: underline;
626
+ }
627
+
628
+ @media (max-width: 768px) {
629
+ .header {
630
+ flex-direction: column;
631
+ align-items: flex-start;
632
+ }
633
+ .health-summary {
634
+ width: 100%;
635
+ justify-content: center;
636
+ }
637
+ .stat-value {
638
+ font-size: 1.7rem;
639
+ }
640
+ }
641
+ </style>
642
+ </head>
643
+ <body>
644
+ <div class="container">
645
+
646
+ <header class="header">
647
+ <div>
648
+ <div class="brand-meta">
649
+ <span class="pill-badge"><span class="dot"></span>AUM-IC PUF Forense V3</span>
650
+ <span class="pill-badge" style="border-color: rgba(56, 189, 248, 0.3); color: #7DD3FC; background: rgba(56, 189, 248, 0.1);">${escapeHtml(resultado.lenguajeDetectado.toUpperCase())}</span>
651
+ </div>
652
+ <h1 class="header-title">Reporte de <span class="accent">Calidad e Integridad</span></h1>
653
+ <div class="target-url">
654
+ <span>Incidente:</span>
655
+ <a href="#">${escapeHtml(resultado.idIncidente)}</a>
656
+ </div>
657
+ <div class="timestamp-box">Generado el ${escapeHtml(timestamp)}</div>
658
+ </div>
659
+
660
+ <div class="health-summary">
661
+ <div class="gauge-wrapper">
662
+ <svg class="gauge-svg" viewBox="0 0 128 128">
663
+ <circle class="gauge-bg" cx="64" cy="64" r="54" />
664
+ <circle class="gauge-meter" cx="64" cy="64" r="54" />
665
+ </svg>
666
+ <div class="gauge-content">
667
+ <span class="gauge-score">${scoreEntero}%</span>
668
+ <span class="gauge-grade">${scoreGrade}</span>
669
+ </div>
670
+ </div>
671
+ <div class="health-details">
672
+ <span class="health-label">Índice PUF</span>
673
+ <span class="health-status">${scoreStatus}</span>
674
+ <span class="health-desc">${scoreDesc}</span>
675
+ </div>
676
+ </div>
677
+ </header>
678
+
679
+ <div class="stats-grid">
680
+ <div class="stat-card">
681
+ <div class="stat-header">
682
+ <span class="stat-label">Compuertas Totales</span>
683
+ <div class="stat-icon blue">📋</div>
684
+ </div>
685
+ <div class="stat-value">${total}</div>
686
+ <div class="stat-sub">Alcance evaluado de la matriz</div>
687
+ </div>
688
+
689
+ <div class="stat-card">
690
+ <div class="stat-header">
691
+ <span class="stat-label">Aprobadas</span>
692
+ <div class="stat-icon green">✔</div>
693
+ </div>
694
+ <div class="stat-value" style="color: var(--success);">${aprobadas}</div>
695
+ <div class="stat-sub">Cumplimiento estricto AUM-IC</div>
696
+ </div>
697
+
698
+ <div class="stat-card">
699
+ <div class="stat-header">
700
+ <span class="stat-label">Rechazadas</span>
701
+ <div class="stat-icon red">✖</div>
702
+ </div>
703
+ <div class="stat-value" style="color: ${rechazadas > 0 ? 'var(--danger)' : 'var(--text-dim)'};">${rechazadas}</div>
704
+ <div class="stat-sub">Incidencias y fallos activos</div>
705
+ </div>
706
+
707
+ <div class="stat-card">
708
+ <div class="stat-header">
709
+ <span class="stat-label">Omitidas</span>
710
+ <div class="stat-icon yellow">~</div>
711
+ </div>
712
+ <div class="stat-value" style="color: var(--warning);">${omitidas}</div>
713
+ <div class="stat-sub">No aplicables al ecosistema</div>
714
+ </div>
715
+ </div>
716
+
717
+ <section class="section">
718
+ <div class="section-header">
719
+ <div class="section-title">
720
+ <span>🛡️</span> Matriz Forense de Calidad PUF
721
+ </div>
722
+ <span class="section-count ${rechazadas > 0 ? 'danger' : 'success'}">
723
+ ${rechazadas > 0 ? rechazadas + ' fallos' : '100% aprobada'}
724
+ </span>
725
+ </div>
726
+
727
+ <div class="table-container">
728
+ <table>
729
+ <thead>
730
+ <tr>
731
+ <th style="width: 70px;">ID</th>
732
+ <th style="width: 280px;">Compuerta</th>
733
+ <th style="width: 130px;">Estado</th>
734
+ <th>Detalle Forense</th>
735
+ <th style="width: 240px;">Evidencia</th>
736
+ <th style="width: 100px; text-align: right;">Tiempo</th>
737
+ </tr>
738
+ </thead>
739
+ <tbody>
740
+ ${compuertasRows}
741
+ </tbody>
742
+ </table>
743
+ </div>
744
+ </section>
745
+
746
+ <footer class="footer">
747
+ <p>Reporte generado por <strong>AUM-IC PUF Inspector</strong> — Cumplimiento Estándar AUM-IC 7:2026</p>
748
+ <p style="margin-top: 4px;">Desarrollado con rigor soberano por <a href="https://ingcrea.com" target="_blank">Ingeniería Creativa</a>.</p>
749
+ </footer>
750
+
751
+ </div>
752
+ </body>
753
+ </html>`;
754
+ const rutaFinal = path.resolve(rutaDestino);
755
+ await fs_1.promises.writeFile(rutaFinal, html.replace(/\r\n/g, '\n'), 'utf-8');
756
+ return rutaFinal;
757
+ }
758
+ }
759
+ exports.GeneradorReporteHtml = GeneradorReporteHtml;
760
+ //# sourceMappingURL=generador-reporte-html.js.map