@ssolis-ti/mcp-compra-agil 1.0.3 → 2.3.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 (121) hide show
  1. package/README.md +111 -23
  2. package/dist/api/compra-agil-client.d.ts +37 -2
  3. package/dist/api/compra-agil-client.d.ts.map +1 -1
  4. package/dist/api/compra-agil-client.js +76 -5
  5. package/dist/api/compra-agil-client.js.map +1 -1
  6. package/dist/index.js +32 -8
  7. package/dist/index.js.map +1 -1
  8. package/dist/reports/components.d.ts +59 -0
  9. package/dist/reports/components.d.ts.map +1 -0
  10. package/dist/reports/components.js +125 -0
  11. package/dist/reports/components.js.map +1 -0
  12. package/dist/reports/export.d.ts +27 -0
  13. package/dist/reports/export.d.ts.map +1 -0
  14. package/dist/reports/export.js +47 -0
  15. package/dist/reports/export.js.map +1 -0
  16. package/dist/reports/format.d.ts +24 -0
  17. package/dist/reports/format.d.ts.map +1 -0
  18. package/dist/reports/format.js +74 -0
  19. package/dist/reports/format.js.map +1 -0
  20. package/dist/reports/render.d.ts +18 -0
  21. package/dist/reports/render.d.ts.map +1 -0
  22. package/dist/reports/render.js +30 -0
  23. package/dist/reports/render.js.map +1 -0
  24. package/dist/reports/templates/radar-oportunidades.d.ts +41 -0
  25. package/dist/reports/templates/radar-oportunidades.d.ts.map +1 -0
  26. package/dist/reports/templates/radar-oportunidades.js +170 -0
  27. package/dist/reports/templates/radar-oportunidades.js.map +1 -0
  28. package/dist/reports/theme.d.ts +83 -0
  29. package/dist/reports/theme.d.ts.map +1 -0
  30. package/dist/reports/theme.js +284 -0
  31. package/dist/reports/theme.js.map +1 -0
  32. package/dist/resources/compras-template.d.ts.map +1 -1
  33. package/dist/resources/compras-template.js +2 -1
  34. package/dist/resources/compras-template.js.map +1 -1
  35. package/dist/resources/documentacion.d.ts.map +1 -1
  36. package/dist/resources/documentacion.js +5 -36
  37. package/dist/resources/documentacion.js.map +1 -1
  38. package/dist/resources/estados.d.ts.map +1 -1
  39. package/dist/resources/estados.js +24 -10
  40. package/dist/resources/estados.js.map +1 -1
  41. package/dist/services/monitor.js +38 -3
  42. package/dist/services/monitor.js.map +1 -1
  43. package/dist/tools/analizar-precios-mercado.d.ts +21 -0
  44. package/dist/tools/analizar-precios-mercado.d.ts.map +1 -0
  45. package/dist/tools/analizar-precios-mercado.js +217 -0
  46. package/dist/tools/analizar-precios-mercado.js.map +1 -0
  47. package/dist/tools/auditar-desiertas.d.ts.map +1 -1
  48. package/dist/tools/auditar-desiertas.js +66 -48
  49. package/dist/tools/auditar-desiertas.js.map +1 -1
  50. package/dist/tools/buscar-compras.d.ts.map +1 -1
  51. package/dist/tools/buscar-compras.js +2 -1
  52. package/dist/tools/buscar-compras.js.map +1 -1
  53. package/dist/tools/detalle-compra.d.ts.map +1 -1
  54. package/dist/tools/detalle-compra.js +6 -5
  55. package/dist/tools/detalle-compra.js.map +1 -1
  56. package/dist/tools/detalle-oc.js +6 -6
  57. package/dist/tools/detalle-oc.js.map +1 -1
  58. package/dist/tools/documentos.d.ts.map +1 -1
  59. package/dist/tools/documentos.js +75 -81
  60. package/dist/tools/documentos.js.map +1 -1
  61. package/dist/tools/estadisticas-uso.d.ts.map +1 -1
  62. package/dist/tools/estadisticas-uso.js +12 -2
  63. package/dist/tools/estadisticas-uso.js.map +1 -1
  64. package/dist/tools/generar-borrador.d.ts +25 -1
  65. package/dist/tools/generar-borrador.d.ts.map +1 -1
  66. package/dist/tools/generar-borrador.js +111 -82
  67. package/dist/tools/generar-borrador.js.map +1 -1
  68. package/dist/tools/generar-informe.d.ts +13 -0
  69. package/dist/tools/generar-informe.d.ts.map +1 -0
  70. package/dist/tools/generar-informe.js +111 -0
  71. package/dist/tools/generar-informe.js.map +1 -0
  72. package/dist/tools/monitorear-cambios.d.ts +32 -2
  73. package/dist/tools/monitorear-cambios.d.ts.map +1 -1
  74. package/dist/tools/monitorear-cambios.js +79 -10
  75. package/dist/tools/monitorear-cambios.js.map +1 -1
  76. package/dist/tools/radar-oportunidades.d.ts +42 -1
  77. package/dist/tools/radar-oportunidades.d.ts.map +1 -1
  78. package/dist/tools/radar-oportunidades.js +123 -103
  79. package/dist/tools/radar-oportunidades.js.map +1 -1
  80. package/dist/tools/recomendar-precio.d.ts +13 -0
  81. package/dist/tools/recomendar-precio.d.ts.map +1 -1
  82. package/dist/tools/recomendar-precio.js +53 -57
  83. package/dist/tools/recomendar-precio.js.map +1 -1
  84. package/dist/tools/verificar-oc.d.ts.map +1 -1
  85. package/dist/tools/verificar-oc.js +36 -8
  86. package/dist/tools/verificar-oc.js.map +1 -1
  87. package/dist/tools/verificar-ticket.d.ts +13 -0
  88. package/dist/tools/verificar-ticket.d.ts.map +1 -0
  89. package/dist/tools/verificar-ticket.js +79 -0
  90. package/dist/tools/verificar-ticket.js.map +1 -0
  91. package/dist/utils/cache.d.ts +53 -0
  92. package/dist/utils/cache.d.ts.map +1 -0
  93. package/dist/utils/cache.js +131 -0
  94. package/dist/utils/cache.js.map +1 -0
  95. package/dist/utils/doc-search.d.ts +52 -0
  96. package/dist/utils/doc-search.d.ts.map +1 -0
  97. package/dist/utils/doc-search.js +97 -0
  98. package/dist/utils/doc-search.js.map +1 -0
  99. package/dist/utils/docs-locator.d.ts +41 -0
  100. package/dist/utils/docs-locator.d.ts.map +1 -0
  101. package/dist/utils/docs-locator.js +82 -0
  102. package/dist/utils/docs-locator.js.map +1 -0
  103. package/dist/utils/error-handler.d.ts.map +1 -1
  104. package/dist/utils/error-handler.js +8 -7
  105. package/dist/utils/error-handler.js.map +1 -1
  106. package/dist/utils/logger.d.ts.map +1 -1
  107. package/dist/utils/logger.js +9 -6
  108. package/dist/utils/logger.js.map +1 -1
  109. package/dist/utils/quotation.d.ts +71 -0
  110. package/dist/utils/quotation.d.ts.map +1 -0
  111. package/dist/utils/quotation.js +140 -0
  112. package/dist/utils/quotation.js.map +1 -0
  113. package/dist/utils/rate-limiter.d.ts +44 -2
  114. package/dist/utils/rate-limiter.d.ts.map +1 -1
  115. package/dist/utils/rate-limiter.js +125 -13
  116. package/dist/utils/rate-limiter.js.map +1 -1
  117. package/dist/utils/redact.d.ts +48 -0
  118. package/dist/utils/redact.d.ts.map +1 -0
  119. package/dist/utils/redact.js +100 -0
  120. package/dist/utils/redact.js.map +1 -0
  121. package/package.json +55 -53
@@ -0,0 +1,170 @@
1
+ /**
2
+ * Template: Informe de Radar de Oportunidades.
3
+ *
4
+ * Recibe datos ya recolectados (no consulta la API) — así el mismo dataset
5
+ * alimenta tanto la respuesta JSON de la tool como este informe.
6
+ */
7
+ import { renderDocumento } from '../render.js';
8
+ import { portada, kpiRow, tabla, badge, callout, barChartSVG, pieDoc, esc, } from '../components.js';
9
+ import { clp, numero, fecha, fechaLarga, horasRestantes } from '../format.js';
10
+ import { TOKENS, PAPEL, FORMATO_POR_DEFECTO } from '../theme.js';
11
+ /** Clasifica el hot score en un tono semántico. Máximo teórico: 105 pts. */
12
+ export function tonoScore(score) {
13
+ if (score >= 80)
14
+ return { tono: 'critico', glosa: 'Muy caliente' };
15
+ if (score >= 55)
16
+ return { tono: 'alerta', glosa: 'Caliente' };
17
+ if (score >= 30)
18
+ return { tono: 'neutro', glosa: 'Templada' };
19
+ return { tono: 'neutro', glosa: 'Fría' };
20
+ }
21
+ function colorScore(score) {
22
+ if (score >= 80)
23
+ return TOKENS.color.critico;
24
+ if (score >= 55)
25
+ return TOKENS.color.alerta;
26
+ return TOKENS.color.marca;
27
+ }
28
+ export function renderRadarInforme(data) {
29
+ const { filtros } = data;
30
+ const formato = data.formato ?? FORMATO_POR_DEFECTO;
31
+ // Orden defensivo: aunque `recolectarDatosRadar` ya entrega los datos rankeados,
32
+ // el template no debe confiar en el orden de su entrada — un gráfico "Top N"
33
+ // desordenado es un error visible y silencioso. Ordenar aquí es O(n log n) sobre
34
+ // decenas de filas y hace al template correcto ante cualquier llamador.
35
+ const ops = [...data.oportunidades].sort((a, b) => b.puntuacion_caliente - a.puntuacion_caliente);
36
+ // ── KPIs de cabecera ──
37
+ const sinOferentes = ops.filter((o) => o.ofertas_recibidas === 0).length;
38
+ const cierran24h = ops.filter((o) => o.horas_restantes <= 24).length;
39
+ const montoTotal = ops.reduce((acc, o) => acc + (o.presupuesto_disponible || 0), 0);
40
+ const kpis = kpiRow([
41
+ { label: 'Oportunidades', valor: numero(ops.length), nota: `de ${numero(data.totalAnalizadas)} analizadas` },
42
+ { label: 'Sin oferentes', valor: numero(sinOferentes), nota: 'competencia cero' },
43
+ { label: 'Cierran en 24h', valor: numero(cierran24h), nota: 'requieren acción' },
44
+ { label: 'Monto en juego', valor: clp(montoTotal), nota: 'presupuesto sumado' },
45
+ ]);
46
+ // ── Filtros aplicados ──
47
+ const filtrosTexto = [
48
+ filtros.region ? `Región ${filtros.region}` : 'Todas las regiones',
49
+ filtros.q ? `Búsqueda: “${filtros.q}”` : 'Sin filtro de rubro',
50
+ filtros.presupuestoMinimo ? `Presupuesto ≥ ${clp(filtros.presupuestoMinimo)}` : 'Sin mínimo de presupuesto',
51
+ `${filtros.paginasEscaneadas} página(s) escaneada(s)`,
52
+ ].join(' · ');
53
+ // ── Gráfico: top 10 por puntuación ──
54
+ const top = ops.slice(0, 10);
55
+ const grafico = top.length > 0
56
+ ? barChartSVG(top.map((o) => ({
57
+ etiqueta: o.nombre,
58
+ valor: o.puntuacion_caliente,
59
+ valorTexto: `${o.puntuacion_caliente} pts`,
60
+ color: colorScore(o.puntuacion_caliente),
61
+ })))
62
+ : '';
63
+ // ── Tabla principal ──
64
+ const tablaOps = tabla(ops, [
65
+ {
66
+ header: '#',
67
+ ancho: '6mm',
68
+ celda: (_o, i) => `<span class="num">${i + 1}</span>`,
69
+ },
70
+ {
71
+ header: 'Código',
72
+ ancho: '28mm',
73
+ celda: (o) => `<span class="mono">${esc(o.codigo)}</span>`,
74
+ },
75
+ {
76
+ header: 'Proceso',
77
+ celda: (o) => `${esc(o.nombre)}<br><small>${esc(o.organismo)}</small>`,
78
+ },
79
+ {
80
+ header: 'Región',
81
+ ancho: '20mm',
82
+ celda: (o) => esc(o.region),
83
+ },
84
+ {
85
+ header: 'Presupuesto',
86
+ ancho: '22mm',
87
+ numerica: true,
88
+ celda: (o) => clp(o.presupuesto_disponible),
89
+ },
90
+ {
91
+ header: 'Ofertas',
92
+ ancho: '14mm',
93
+ numerica: true,
94
+ celda: (o) => o.ofertas_recibidas === 0
95
+ ? badge('0', 'exito')
96
+ : `${numero(o.ofertas_recibidas)}`,
97
+ },
98
+ {
99
+ header: 'Cierra en',
100
+ ancho: '18mm',
101
+ numerica: true,
102
+ celda: (o) => {
103
+ const txt = horasRestantes(o.horas_restantes);
104
+ return o.horas_restantes <= 12 ? badge(txt, 'critico') : esc(txt);
105
+ },
106
+ },
107
+ {
108
+ header: 'Score',
109
+ ancho: '22mm',
110
+ numerica: true,
111
+ celda: (o) => {
112
+ const { tono, glosa } = tonoScore(o.puntuacion_caliente);
113
+ return `${badge(`${o.puntuacion_caliente} · ${glosa}`, tono)}`;
114
+ },
115
+ },
116
+ ]);
117
+ // ── Fichas detalladas del top 3 ──
118
+ const fichas = ops.slice(0, 3).map((o, i) => {
119
+ const { tono } = tonoScore(o.puntuacion_caliente);
120
+ const cuerpo = `
121
+ <p style="margin-bottom:2mm"><b>${esc(o.organismo)}</b> — ${esc(o.region)}<br>
122
+ <span class="mono">${esc(o.codigo)}</span></p>
123
+ <p style="margin-bottom:2mm">
124
+ Presupuesto <b>${clp(o.presupuesto_disponible)}</b> ·
125
+ Ofertas recibidas: <b>${numero(o.ofertas_recibidas)}</b> ·
126
+ Cierra el <b>${fecha(o.fecha_cierre)}</b> (${esc(horasRestantes(o.horas_restantes))})
127
+ </p>
128
+ <div><small>Factores de puntuación:</small>
129
+ <ul style="margin:1mm 0 0;padding-left:4mm">
130
+ ${o.factores_calificacion.map((f) => `<li><small>${esc(f)}</small></li>`).join('')}
131
+ </ul>
132
+ </div>`;
133
+ return callout(`${i + 1}. ${o.nombre} — ${o.puntuacion_caliente} pts`, cuerpo, tono === 'exito' ? 'neutro' : tono);
134
+ }).join('');
135
+ // ── Ensamblado ──
136
+ const cuerpo = `
137
+ ${portada({
138
+ eyebrow: 'Mercado Público · Compra Ágil',
139
+ titulo: 'Radar de Oportunidades',
140
+ subtitulo: 'Procesos activos priorizados por facilidad de adjudicación',
141
+ meta: [
142
+ { label: 'Generado', valor: fechaLarga(data.generadoEn) },
143
+ { label: 'Alcance', valor: filtros.region ? `Región ${filtros.region}` : 'Nacional' },
144
+ { label: 'Oportunidades', valor: String(ops.length) },
145
+ ],
146
+ })}
147
+
148
+ ${kpis}
149
+
150
+ <p><small>${esc(filtrosTexto)}</small></p>
151
+
152
+ ${ops.length === 0 ? callout('Sin resultados', '<p>No se encontraron Compras Ágiles activas que coincidan con los filtros aplicados.</p>', 'alerta') : ''}
153
+
154
+ ${top.length > 0 ? `<h2>Top ${top.length} por puntuación</h2>${grafico}` : ''}
155
+
156
+ ${fichas ? `<h2>Oportunidades destacadas</h2>${fichas}` : ''}
157
+
158
+ ${ops.length > 0 ? `<h2>Listado completo</h2>${tablaOps}` : ''}
159
+
160
+ ${callout('Cómo se calcula la puntuación', `<p style="margin:0">Fórmula ponderada sobre 105 puntos: baja competencia (hasta 50 pts) + urgencia de cierre (hasta 30 pts) + tamaño de presupuesto (hasta 20 pts) + ausencia de bases adjuntas (5 pts). Una puntuación alta indica un proceso con pocos oferentes, cierre próximo y monto atractivo.</p>`)}
161
+
162
+ ${pieDoc(`Informe generado automáticamente por mcp-compra-agil el ${fecha(data.generadoEn.toISOString())} a partir de datos públicos de la API Compra Ágil v2 de Mercado Público (ChileCompra). Los datos reflejan el estado al momento de la consulta y pueden variar. · Formato de impresión: ${PAPEL[formato].glosa}`)}
163
+ `.trim();
164
+ return renderDocumento({
165
+ titulo: `Radar de Oportunidades — ${fechaLarga(data.generadoEn)}`,
166
+ cuerpo,
167
+ formato,
168
+ });
169
+ }
170
+ //# sourceMappingURL=radar-oportunidades.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"radar-oportunidades.js","sourceRoot":"","sources":["../../../src/reports/templates/radar-oportunidades.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Design system de los informes — print-first.
3
+ *
4
+ * Decisiones de diseño:
5
+ * - El papel es blanco: no hay modo oscuro. Se optimiza contraste, no "look".
6
+ * - Se evitan fondos de página completos (gasto de tinta); el color se usa
7
+ * como acento semántico y en superficies pequeñas (badges, cabeceras de tabla).
8
+ * - Toda la escala (tipografía, espaciado, color) vive aquí: un template nunca
9
+ * debe inventar un color o un tamaño suelto.
10
+ * - Unidades en mm/pt para impresión; rem solo para texto.
11
+ */
12
+ /**
13
+ * Formatos de papel soportados.
14
+ *
15
+ * OJO con el Oficio: en Chile mide 216 × 330 mm. NO equivale al `legal` de CSS
16
+ * (216 × 356 mm, que es el US Legal) — usarlo agregaría 26 mm de alto y descuadraría
17
+ * la caja de texto. Por eso se declara con dimensiones explícitas.
18
+ *
19
+ * Carta es el formato de oficina más habitual en Chile; A4 es el estándar ISO
20
+ * y el default de la mayoría de impresoras; Oficio/Folio se usa en documentos
21
+ * oficiales y legales.
22
+ */
23
+ export type FormatoPapel = 'a4' | 'carta' | 'oficio';
24
+ export interface DefinicionPapel {
25
+ /** Valor para la regla CSS `@page { size: ... }`. */
26
+ size: string;
27
+ ancho: string;
28
+ alto: string;
29
+ glosa: string;
30
+ /** Dimensiones en mm para exportadores (ej. Puppeteer width/height). */
31
+ mm: {
32
+ ancho: number;
33
+ alto: number;
34
+ };
35
+ }
36
+ export declare const PAPEL: Record<FormatoPapel, DefinicionPapel>;
37
+ export declare const FORMATO_POR_DEFECTO: FormatoPapel;
38
+ export declare const TOKENS: {
39
+ readonly color: {
40
+ readonly tinta: "#12263a";
41
+ readonly tintaSuave: "#5b6b7c";
42
+ readonly tintaTenue: "#8a97a5";
43
+ readonly marca: "#1b4965";
44
+ readonly marcaClara: "#e7eef4";
45
+ readonly borde: "#d6dee6";
46
+ readonly exito: "#1b6b4a";
47
+ readonly exitoFondo: "#e6f4ec";
48
+ readonly alerta: "#8a5a00";
49
+ readonly alertaFondo: "#fdf2dd";
50
+ readonly critico: "#9b2226";
51
+ readonly criticoFondo: "#fbe9e9";
52
+ readonly papel: "#ffffff";
53
+ };
54
+ readonly fuente: {
55
+ readonly familia: "'Segoe UI', -apple-system, 'Helvetica Neue', Arial, sans-serif";
56
+ readonly mono: "'Cascadia Mono', 'SF Mono', Consolas, monospace";
57
+ readonly cuerpo: "10.5pt";
58
+ readonly micro: "7.5pt";
59
+ readonly pequena: "8.5pt";
60
+ readonly h3: "11pt";
61
+ readonly h2: "13pt";
62
+ readonly h1: "18pt";
63
+ readonly portada: "26pt";
64
+ };
65
+ readonly espacio: {
66
+ readonly xs: "2mm";
67
+ readonly sm: "3mm";
68
+ readonly md: "5mm";
69
+ readonly lg: "8mm";
70
+ readonly xl: "12mm";
71
+ };
72
+ readonly pagina: {
73
+ readonly margen: "16mm 15mm 18mm 15mm";
74
+ };
75
+ };
76
+ /**
77
+ * Hoja de estilos base del informe. Se inyecta inline en el HTML
78
+ * (los informes deben ser un único archivo autocontenido y portable).
79
+ *
80
+ * @param formato Tamaño de papel. Por defecto Carta (el más usado en oficinas chilenas).
81
+ */
82
+ export declare function baseCSS(formato?: FormatoPapel): string;
83
+ //# sourceMappingURL=theme.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../../src/reports/theme.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH;;;;;;;;;;GAUG;AACH,MAAM,MAAM,YAAY,GAAG,IAAI,GAAG,OAAO,GAAG,QAAQ,CAAC;AAErD,MAAM,WAAW,eAAe;IAC9B,qDAAqD;IACrD,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,wEAAwE;IACxE,EAAE,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CACrC;AAED,eAAO,MAAM,KAAK,EAAE,MAAM,CAAC,YAAY,EAAE,eAAe,CAuBvD,CAAC;AAEF,eAAO,MAAM,mBAAmB,EAAE,YAAsB,CAAC;AAEzD,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuCT,CAAC;AAEX;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,OAAO,GAAE,YAAkC,GAAG,MAAM,CAwM3E"}
@@ -0,0 +1,284 @@
1
+ /**
2
+ * Design system de los informes — print-first.
3
+ *
4
+ * Decisiones de diseño:
5
+ * - El papel es blanco: no hay modo oscuro. Se optimiza contraste, no "look".
6
+ * - Se evitan fondos de página completos (gasto de tinta); el color se usa
7
+ * como acento semántico y en superficies pequeñas (badges, cabeceras de tabla).
8
+ * - Toda la escala (tipografía, espaciado, color) vive aquí: un template nunca
9
+ * debe inventar un color o un tamaño suelto.
10
+ * - Unidades en mm/pt para impresión; rem solo para texto.
11
+ */
12
+ export const PAPEL = {
13
+ a4: {
14
+ size: 'A4',
15
+ ancho: '210mm',
16
+ alto: '297mm',
17
+ glosa: 'A4 (210 × 297 mm)',
18
+ mm: { ancho: 210, alto: 297 },
19
+ },
20
+ carta: {
21
+ size: 'letter',
22
+ ancho: '216mm',
23
+ alto: '279mm',
24
+ glosa: 'Carta (216 × 279 mm)',
25
+ mm: { ancho: 216, alto: 279 },
26
+ },
27
+ oficio: {
28
+ // Oficio/Folio chileno: dimensiones explícitas, NO el `legal` de CSS.
29
+ size: '216mm 330mm',
30
+ ancho: '216mm',
31
+ alto: '330mm',
32
+ glosa: 'Oficio / Folio (216 × 330 mm)',
33
+ mm: { ancho: 216, alto: 330 },
34
+ },
35
+ };
36
+ export const FORMATO_POR_DEFECTO = 'carta';
37
+ export const TOKENS = {
38
+ // Paleta institucional sobria — azul pizarra + acentos semánticos
39
+ color: {
40
+ tinta: '#12263a', // texto principal
41
+ tintaSuave: '#5b6b7c', // texto secundario
42
+ tintaTenue: '#8a97a5', // metadatos
43
+ marca: '#1b4965', // primario (encabezados, líneas)
44
+ marcaClara: '#e7eef4', // superficies suaves
45
+ borde: '#d6dee6',
46
+ exito: '#1b6b4a',
47
+ exitoFondo: '#e6f4ec',
48
+ alerta: '#8a5a00',
49
+ alertaFondo: '#fdf2dd',
50
+ critico: '#9b2226',
51
+ criticoFondo: '#fbe9e9',
52
+ papel: '#ffffff',
53
+ },
54
+ // Escala tipográfica modular (ratio ~1.25) anclada a 10.5pt de cuerpo
55
+ fuente: {
56
+ familia: "'Segoe UI', -apple-system, 'Helvetica Neue', Arial, sans-serif",
57
+ mono: "'Cascadia Mono', 'SF Mono', Consolas, monospace",
58
+ cuerpo: '10.5pt',
59
+ micro: '7.5pt',
60
+ pequena: '8.5pt',
61
+ h3: '11pt',
62
+ h2: '13pt',
63
+ h1: '18pt',
64
+ portada: '26pt',
65
+ },
66
+ espacio: {
67
+ xs: '2mm',
68
+ sm: '3mm',
69
+ md: '5mm',
70
+ lg: '8mm',
71
+ xl: '12mm',
72
+ },
73
+ pagina: {
74
+ margen: '16mm 15mm 18mm 15mm',
75
+ },
76
+ };
77
+ /**
78
+ * Hoja de estilos base del informe. Se inyecta inline en el HTML
79
+ * (los informes deben ser un único archivo autocontenido y portable).
80
+ *
81
+ * @param formato Tamaño de papel. Por defecto Carta (el más usado en oficinas chilenas).
82
+ */
83
+ export function baseCSS(formato = FORMATO_POR_DEFECTO) {
84
+ const t = TOKENS;
85
+ const papel = PAPEL[formato];
86
+ return `
87
+ @page {
88
+ size: ${papel.size};
89
+ margin: ${t.pagina.margen};
90
+ }
91
+
92
+ * { box-sizing: border-box; }
93
+
94
+ html, body {
95
+ margin: 0;
96
+ padding: 0;
97
+ background: ${t.color.papel};
98
+ color: ${t.color.tinta};
99
+ font-family: ${t.fuente.familia};
100
+ font-size: ${t.fuente.cuerpo};
101
+ line-height: 1.45;
102
+ -webkit-print-color-adjust: exact;
103
+ print-color-adjust: exact;
104
+ }
105
+
106
+ /* ── Tipografía ────────────────────────────────────────────── */
107
+ h1, h2, h3 {
108
+ color: ${t.color.marca};
109
+ margin: 0 0 ${t.espacio.sm} 0;
110
+ line-height: 1.2;
111
+ break-after: avoid;
112
+ page-break-after: avoid;
113
+ }
114
+ h1 { font-size: ${t.fuente.h1}; }
115
+ h2 {
116
+ font-size: ${t.fuente.h2};
117
+ margin-top: ${t.espacio.lg};
118
+ padding-bottom: ${t.espacio.xs};
119
+ border-bottom: 1.5pt solid ${t.color.marca};
120
+ }
121
+ h3 { font-size: ${t.fuente.h3}; margin-top: ${t.espacio.md}; }
122
+ p { margin: 0 0 ${t.espacio.sm} 0; orphans: 3; widows: 3; }
123
+ strong { color: ${t.color.tinta}; }
124
+ small { font-size: ${t.fuente.pequena}; color: ${t.color.tintaSuave}; }
125
+
126
+ /* ── Portada ───────────────────────────────────────────────── */
127
+ .portada {
128
+ border-top: 4pt solid ${t.color.marca};
129
+ padding-top: ${t.espacio.md};
130
+ margin-bottom: ${t.espacio.lg};
131
+ }
132
+ .portada .eyebrow {
133
+ font-size: ${t.fuente.micro};
134
+ letter-spacing: 0.12em;
135
+ text-transform: uppercase;
136
+ color: ${t.color.tintaTenue};
137
+ margin-bottom: ${t.espacio.xs};
138
+ }
139
+ .portada .titulo {
140
+ font-size: ${t.fuente.portada};
141
+ font-weight: 600;
142
+ color: ${t.color.marca};
143
+ line-height: 1.15;
144
+ margin: 0 0 ${t.espacio.sm} 0;
145
+ }
146
+ .portada .subtitulo {
147
+ font-size: ${t.fuente.h3};
148
+ color: ${t.color.tintaSuave};
149
+ font-weight: 400;
150
+ margin: 0;
151
+ }
152
+ .portada .meta {
153
+ margin-top: ${t.espacio.md};
154
+ padding-top: ${t.espacio.sm};
155
+ border-top: 0.5pt solid ${t.color.borde};
156
+ font-size: ${t.fuente.pequena};
157
+ color: ${t.color.tintaSuave};
158
+ display: flex;
159
+ flex-wrap: wrap;
160
+ gap: ${t.espacio.md};
161
+ }
162
+ .portada .meta b { color: ${t.color.tinta}; font-weight: 600; }
163
+
164
+ /* ── KPIs ──────────────────────────────────────────────────── */
165
+ .kpi-row {
166
+ display: flex;
167
+ gap: ${t.espacio.sm};
168
+ margin: ${t.espacio.md} 0;
169
+ break-inside: avoid;
170
+ page-break-inside: avoid;
171
+ }
172
+ .kpi {
173
+ flex: 1;
174
+ border: 0.5pt solid ${t.color.borde};
175
+ border-left: 2.5pt solid ${t.color.marca};
176
+ border-radius: 1mm;
177
+ padding: ${t.espacio.sm};
178
+ background: ${t.color.marcaClara};
179
+ }
180
+ .kpi .label {
181
+ font-size: ${t.fuente.micro};
182
+ text-transform: uppercase;
183
+ letter-spacing: 0.06em;
184
+ color: ${t.color.tintaSuave};
185
+ margin-bottom: 1mm;
186
+ }
187
+ .kpi .valor {
188
+ font-size: ${t.fuente.h2};
189
+ font-weight: 600;
190
+ color: ${t.color.marca};
191
+ line-height: 1.1;
192
+ }
193
+ .kpi .nota { font-size: ${t.fuente.micro}; color: ${t.color.tintaTenue}; margin-top: 0.5mm; }
194
+
195
+ /* ── Tablas ────────────────────────────────────────────────── */
196
+ table {
197
+ width: 100%;
198
+ border-collapse: collapse;
199
+ font-size: ${t.fuente.pequena};
200
+ margin: ${t.espacio.sm} 0;
201
+ }
202
+ thead { display: table-header-group; } /* repite cabecera al saltar de página */
203
+ tr { break-inside: avoid; page-break-inside: avoid; }
204
+ th {
205
+ background: ${t.color.marca};
206
+ color: #fff;
207
+ text-align: left;
208
+ padding: 1.8mm 2mm;
209
+ font-size: ${t.fuente.micro};
210
+ text-transform: uppercase;
211
+ letter-spacing: 0.05em;
212
+ font-weight: 600;
213
+ }
214
+ td {
215
+ padding: 1.8mm 2mm;
216
+ border-bottom: 0.5pt solid ${t.color.borde};
217
+ vertical-align: top;
218
+ }
219
+ tbody tr:nth-child(even) td { background: #fafbfc; }
220
+ .num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
221
+ .mono { font-family: ${t.fuente.mono}; font-size: ${t.fuente.micro}; }
222
+
223
+ /* ── Badges ────────────────────────────────────────────────── */
224
+ .badge {
225
+ display: inline-block;
226
+ padding: 0.6mm 1.6mm;
227
+ border-radius: 1mm;
228
+ font-size: ${t.fuente.micro};
229
+ font-weight: 600;
230
+ white-space: nowrap;
231
+ }
232
+ .badge-exito { background: ${t.color.exitoFondo}; color: ${t.color.exito}; }
233
+ .badge-alerta { background: ${t.color.alertaFondo}; color: ${t.color.alerta}; }
234
+ .badge-critico { background: ${t.color.criticoFondo}; color: ${t.color.critico}; }
235
+ .badge-neutro { background: ${t.color.marcaClara}; color: ${t.color.marca}; }
236
+
237
+ /* ── Callouts ──────────────────────────────────────────────── */
238
+ .callout {
239
+ border-left: 2.5pt solid ${t.color.marca};
240
+ background: ${t.color.marcaClara};
241
+ padding: ${t.espacio.sm};
242
+ margin: ${t.espacio.sm} 0;
243
+ border-radius: 0 1mm 1mm 0;
244
+ break-inside: avoid;
245
+ page-break-inside: avoid;
246
+ font-size: ${t.fuente.pequena};
247
+ }
248
+ .callout .titulo { font-weight: 600; color: ${t.color.marca}; margin-bottom: 1mm; }
249
+ .callout-alerta { border-left-color: ${t.color.alerta}; background: ${t.color.alertaFondo}; }
250
+ .callout-alerta .titulo { color: ${t.color.alerta}; }
251
+ .callout-critico { border-left-color: ${t.color.critico}; background: ${t.color.criticoFondo}; }
252
+ .callout-critico .titulo { color: ${t.color.critico}; }
253
+
254
+ /* ── Gráficos ──────────────────────────────────────────────── */
255
+ .chart { margin: ${t.espacio.md} 0; break-inside: avoid; page-break-inside: avoid; }
256
+ .chart svg { width: 100%; height: auto; }
257
+
258
+ /* ── Utilidades de paginación ──────────────────────────────── */
259
+ .salto-pagina { break-before: page; page-break-before: always; }
260
+ .no-cortar { break-inside: avoid; page-break-inside: avoid; }
261
+
262
+ /* ── Pie de documento ──────────────────────────────────────── */
263
+ .pie-doc {
264
+ margin-top: ${t.espacio.lg};
265
+ padding-top: ${t.espacio.sm};
266
+ border-top: 0.5pt solid ${t.color.borde};
267
+ font-size: ${t.fuente.micro};
268
+ color: ${t.color.tintaTenue};
269
+ }
270
+
271
+ /* ── Solo pantalla: simula la hoja al abrir en el navegador ── */
272
+ /* El ancho sigue al formato real (${papel.glosa}) para que lo que se ve
273
+ en pantalla coincida con lo que sale impreso. */
274
+ @media screen {
275
+ body {
276
+ max-width: ${papel.ancho};
277
+ margin: 8mm auto;
278
+ padding: 16mm 15mm;
279
+ box-shadow: 0 0 0 1px #e5e7eb, 0 4px 24px rgba(0,0,0,.07);
280
+ }
281
+ }
282
+ `.trim();
283
+ }
284
+ //# sourceMappingURL=theme.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme.js","sourceRoot":"","sources":["../../src/reports/theme.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"compras-template.d.ts","sourceRoot":"","sources":["../../src/resources/compras-template.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAoB,MAAM,yCAAyC,CAAC;AACtF,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAGhE,wBAAgB,+BAA+B,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAoCjG"}
1
+ {"version":3,"file":"compras-template.d.ts","sourceRoot":"","sources":["../../src/resources/compras-template.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAoB,MAAM,yCAAyC,CAAC;AACtF,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAIhE,wBAAgB,+BAA+B,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAoCjG"}
@@ -6,6 +6,7 @@
6
6
  */
7
7
  import { ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';
8
8
  import { CompraAgilApiError } from '../utils/error-handler.js';
9
+ import { safeError } from '../utils/redact.js';
9
10
  export function registerComprasTemplateResource(server, client) {
10
11
  // Crear plantilla de URI para compra-agil://compras/{codigo}
11
12
  const template = new ResourceTemplate('compra-agil://compras/{codigo}', {
@@ -32,7 +33,7 @@ export function registerComprasTemplateResource(server, client) {
32
33
  catch (error) {
33
34
  const message = error instanceof CompraAgilApiError
34
35
  ? error.actionableMessage
35
- : `Error al leer recurso de Compra Ágil: ${String(error)}`;
36
+ : `Error al leer recurso de Compra Ágil: ${safeError(error)}`;
36
37
  throw new Error(message);
37
38
  }
38
39
  });
@@ -1 +1 @@
1
- {"version":3,"file":"compras-template.js","sourceRoot":"","sources":["../../src/resources/compras-template.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAa,gBAAgB,EAAE,MAAM,yCAAyC,CAAC;AAEtF,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAE/D,MAAM,UAAU,+BAA+B,CAAC,MAAiB,EAAE,MAAwB;IACzF,6DAA6D;IAC7D,MAAM,QAAQ,GAAG,IAAI,gBAAgB,CAAC,gCAAgC,EAAE;QACtE,IAAI,EAAE,SAAS,EAAE,kFAAkF;KACpG,CAAC,CAAC;IAEH,MAAM,CAAC,gBAAgB,CACrB,yBAAyB,EACzB,QAAQ,EACR;QACE,WAAW,EAAE,uIAAuI;QACpJ,QAAQ,EAAE,kBAAkB;KAC7B,EACD,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,EAAE;QACvB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,SAAS,CAAC,MAAgB,CAAC;YAC1C,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;YACnE,CAAC;YAED,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YAC7C,OAAO;gBACL,QAAQ,EAAE,CAAC;wBACT,GAAG,EAAE,GAAG,CAAC,QAAQ,EAAE;wBACnB,QAAQ,EAAE,kBAAkB;wBAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;qBACvC,CAAC;aACH,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,OAAO,GAAG,KAAK,YAAY,kBAAkB;gBACjD,CAAC,CAAC,KAAK,CAAC,iBAAiB;gBACzB,CAAC,CAAC,yCAAyC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;YAC7D,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"compras-template.js","sourceRoot":"","sources":["../../src/resources/compras-template.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAa,gBAAgB,EAAE,MAAM,yCAAyC,CAAC;AAEtF,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C,MAAM,UAAU,+BAA+B,CAAC,MAAiB,EAAE,MAAwB;IACzF,6DAA6D;IAC7D,MAAM,QAAQ,GAAG,IAAI,gBAAgB,CAAC,gCAAgC,EAAE;QACtE,IAAI,EAAE,SAAS,EAAE,kFAAkF;KACpG,CAAC,CAAC;IAEH,MAAM,CAAC,gBAAgB,CACrB,yBAAyB,EACzB,QAAQ,EACR;QACE,WAAW,EAAE,uIAAuI;QACpJ,QAAQ,EAAE,kBAAkB;KAC7B,EACD,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,EAAE;QACvB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,SAAS,CAAC,MAAgB,CAAC;YAC1C,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;YACnE,CAAC;YAED,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YAC7C,OAAO;gBACL,QAAQ,EAAE,CAAC;wBACT,GAAG,EAAE,GAAG,CAAC,QAAQ,EAAE;wBACnB,QAAQ,EAAE,kBAAkB;wBAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;qBACvC,CAAC;aACH,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,OAAO,GAAG,KAAK,YAAY,kBAAkB;gBACjD,CAAC,CAAC,KAAK,CAAC,iBAAiB;gBACzB,CAAC,CAAC,yCAAyC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC;YAChE,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"documentacion.d.ts","sourceRoot":"","sources":["../../src/resources/documentacion.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAoB,MAAM,yCAAyC,CAAC;AAoCtF;;GAEG;AACH,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAsErE"}
1
+ {"version":3,"file":"documentacion.d.ts","sourceRoot":"","sources":["../../src/resources/documentacion.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAoB,MAAM,yCAAyC,CAAC;AAStF;;GAEG;AACH,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAkErE"}
@@ -1,37 +1,10 @@
1
1
  import { ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';
2
2
  import fs from 'fs';
3
3
  import path from 'path';
4
- import { fileURLToPath } from 'url';
5
4
  import { PDFParse } from 'pdf-parse';
6
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
7
- const packageDocsDir = path.resolve(__dirname, '../../docs');
8
- const cwdDocsDir = path.resolve(process.cwd(), 'docs');
9
- let DOCS_DIR = cwdDocsDir;
10
- if (fs.existsSync(packageDocsDir) && fs.readdirSync(packageDocsDir).some(f => f.toLowerCase().endsWith('.pdf'))) {
11
- DOCS_DIR = packageDocsDir;
12
- }
13
- /**
14
- * Obtiene de forma recursiva todos los archivos dentro de un directorio,
15
- * retornando sus rutas relativas formateadas con barras diagonales (/).
16
- */
17
- function getRelativeFilesRecursively(dir, baseDir = dir) {
18
- let results = [];
19
- if (!fs.existsSync(dir))
20
- return [];
21
- const list = fs.readdirSync(dir);
22
- for (const file of list) {
23
- const filePath = path.join(dir, file);
24
- const stat = fs.statSync(filePath);
25
- if (stat && stat.isDirectory()) {
26
- results = results.concat(getRelativeFilesRecursively(filePath, baseDir));
27
- }
28
- else {
29
- const relativePath = path.relative(baseDir, filePath).replace(/\\/g, '/');
30
- results.push(relativePath);
31
- }
32
- }
33
- return results;
34
- }
5
+ import { resolveDocsDir, listSupportedDocs } from '../utils/docs-locator.js';
6
+ import { safeError } from '../utils/redact.js';
7
+ const DOCS_DIR = resolveDocsDir();
35
8
  /**
36
9
  * Registra el recurso dinámico para consultar manuales y guías locales (PDF/TXT/MD).
37
10
  */
@@ -43,11 +16,7 @@ export function registerDocumentacionResource(server) {
43
16
  if (!fs.existsSync(DOCS_DIR)) {
44
17
  fs.mkdirSync(DOCS_DIR, { recursive: true });
45
18
  }
46
- const files = getRelativeFilesRecursively(DOCS_DIR).filter(file => {
47
- const ext = path.extname(file).toLowerCase();
48
- const name = path.basename(file).toLowerCase();
49
- return (ext === '.pdf' || ext === '.txt' || ext === '.md') && name !== 'readme.md';
50
- });
19
+ const files = listSupportedDocs(DOCS_DIR);
51
20
  return {
52
21
  resources: files.map(file => ({
53
22
  uri: `compra-agil://documentacion/${encodeURIComponent(file)}`,
@@ -93,7 +62,7 @@ export function registerDocumentacionResource(server) {
93
62
  };
94
63
  }
95
64
  catch (error) {
96
- throw new Error(`Error al leer el manual local: ${error.message || String(error)}`);
65
+ throw new Error(`Error al leer el manual local: ${safeError(error)}`);
97
66
  }
98
67
  });
99
68
  }