@ssolis-ti/mcp-compra-agil 1.0.3 → 2.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 (110) hide show
  1. package/README.md +110 -23
  2. package/dist/api/compra-agil-client.d.ts +2 -1
  3. package/dist/api/compra-agil-client.d.ts.map +1 -1
  4. package/dist/api/compra-agil-client.js +7 -1
  5. package/dist/api/compra-agil-client.js.map +1 -1
  6. package/dist/index.js +31 -7
  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 +37 -2
  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 +64 -46
  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.d.ts.map +1 -1
  57. package/dist/tools/detalle-oc.js +6 -5
  58. package/dist/tools/detalle-oc.js.map +1 -1
  59. package/dist/tools/documentos.d.ts.map +1 -1
  60. package/dist/tools/documentos.js +7 -44
  61. package/dist/tools/documentos.js.map +1 -1
  62. package/dist/tools/generar-borrador.d.ts.map +1 -1
  63. package/dist/tools/generar-borrador.js +37 -26
  64. package/dist/tools/generar-borrador.js.map +1 -1
  65. package/dist/tools/generar-informe.d.ts +13 -0
  66. package/dist/tools/generar-informe.d.ts.map +1 -0
  67. package/dist/tools/generar-informe.js +111 -0
  68. package/dist/tools/generar-informe.js.map +1 -0
  69. package/dist/tools/monitorear-cambios.d.ts +32 -2
  70. package/dist/tools/monitorear-cambios.d.ts.map +1 -1
  71. package/dist/tools/monitorear-cambios.js +79 -10
  72. package/dist/tools/monitorear-cambios.js.map +1 -1
  73. package/dist/tools/radar-oportunidades.d.ts +42 -1
  74. package/dist/tools/radar-oportunidades.d.ts.map +1 -1
  75. package/dist/tools/radar-oportunidades.js +123 -103
  76. package/dist/tools/radar-oportunidades.js.map +1 -1
  77. package/dist/tools/recomendar-precio.d.ts +13 -0
  78. package/dist/tools/recomendar-precio.d.ts.map +1 -1
  79. package/dist/tools/recomendar-precio.js +53 -57
  80. package/dist/tools/recomendar-precio.js.map +1 -1
  81. package/dist/tools/verificar-oc.d.ts.map +1 -1
  82. package/dist/tools/verificar-oc.js +9 -7
  83. package/dist/tools/verificar-oc.js.map +1 -1
  84. package/dist/tools/verificar-ticket.d.ts +13 -0
  85. package/dist/tools/verificar-ticket.d.ts.map +1 -0
  86. package/dist/tools/verificar-ticket.js +79 -0
  87. package/dist/tools/verificar-ticket.js.map +1 -0
  88. package/dist/utils/docs-locator.d.ts +41 -0
  89. package/dist/utils/docs-locator.d.ts.map +1 -0
  90. package/dist/utils/docs-locator.js +82 -0
  91. package/dist/utils/docs-locator.js.map +1 -0
  92. package/dist/utils/error-handler.d.ts.map +1 -1
  93. package/dist/utils/error-handler.js +4 -1
  94. package/dist/utils/error-handler.js.map +1 -1
  95. package/dist/utils/logger.d.ts.map +1 -1
  96. package/dist/utils/logger.js +9 -6
  97. package/dist/utils/logger.js.map +1 -1
  98. package/dist/utils/quotation.d.ts +71 -0
  99. package/dist/utils/quotation.d.ts.map +1 -0
  100. package/dist/utils/quotation.js +140 -0
  101. package/dist/utils/quotation.js.map +1 -0
  102. package/dist/utils/rate-limiter.d.ts +8 -1
  103. package/dist/utils/rate-limiter.d.ts.map +1 -1
  104. package/dist/utils/rate-limiter.js +25 -1
  105. package/dist/utils/rate-limiter.js.map +1 -1
  106. package/dist/utils/redact.d.ts +48 -0
  107. package/dist/utils/redact.d.ts.map +1 -0
  108. package/dist/utils/redact.js +100 -0
  109. package/dist/utils/redact.js.map +1 -0
  110. package/package.json +55 -53
@@ -1,10 +1,40 @@
1
1
  /**
2
2
  * Tool: monitorear_cambios_recientes
3
3
  *
4
- * Detecta procesos de Compra Ágil que hayan sido creados o modificados
5
- * recientemente. Ideal para alertas y monitoreo de oportunidades.
4
+ * Detecta procesos de Compra Ágil creados o modificados dentro de una ventana
5
+ * de cambios: relativa (últimos N minutos) o absoluta (rango de fechas
6
+ * arbitrario). Ideal para alertas, monitoreo de oportunidades y sincronización
7
+ * incremental de un período pasado.
6
8
  */
7
9
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
8
10
  import { CompraAgilClient } from '../api/compra-agil-client.js';
11
+ /** Ventana de cambios ya resuelta y lista para enviar a la API. */
12
+ export interface VentanaCambios {
13
+ /** Parámetros de la API que definen la ventana (uno u otro grupo, nunca ambos). */
14
+ params: {
15
+ ttl_cambio_ms?: number;
16
+ cambio_desde?: string;
17
+ cambio_hasta?: string;
18
+ };
19
+ /** Glosa legible para el reporte de salida. */
20
+ descripcion: string;
21
+ }
22
+ /**
23
+ * Resuelve la ventana de cambios a partir de los argumentos de la herramienta.
24
+ *
25
+ * La API expone dos formas mutuamente excluyentes de acotar los cambios
26
+ * (Guía API Compra Ágil v2 §5.1, Grupo 1): `ttl_cambio_ms` (opción A) o el par
27
+ * `cambio_desde`/`cambio_hasta` (opción B). Enviar ambas a la vez es un 400,
28
+ * así que se decide aquí y se falla localmente para no gastar cuota.
29
+ *
30
+ * Retorna un string con el error de validación, o la ventana resuelta.
31
+ */
32
+ export declare function resolverVentanaCambios(args: {
33
+ minutos?: number;
34
+ cambio_desde?: string;
35
+ cambio_hasta?: string;
36
+ }): VentanaCambios | {
37
+ error: string;
38
+ };
9
39
  export declare function registerMonitorearCambios(server: McpServer, client: CompraAgilClient): void;
10
40
  //# sourceMappingURL=monitorear-cambios.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"monitorear-cambios.d.ts","sourceRoot":"","sources":["../../src/tools/monitorear-cambios.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AA4BhE,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAqD3F"}
1
+ {"version":3,"file":"monitorear-cambios.d.ts","sourceRoot":"","sources":["../../src/tools/monitorear-cambios.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAyChE,mEAAmE;AACnE,MAAM,WAAW,cAAc;IAC7B,mFAAmF;IACnF,MAAM,EAAE;QAAE,aAAa,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACjF,+CAA+C;IAC/C,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE;IAC3C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,GAAG,cAAc,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CA+CrC;AAED,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,gBAAgB,GAAG,IAAI,CA4D3F"}
@@ -1,31 +1,100 @@
1
1
  /**
2
2
  * Tool: monitorear_cambios_recientes
3
3
  *
4
- * Detecta procesos de Compra Ágil que hayan sido creados o modificados
5
- * recientemente. Ideal para alertas y monitoreo de oportunidades.
4
+ * Detecta procesos de Compra Ágil creados o modificados dentro de una ventana
5
+ * de cambios: relativa (últimos N minutos) o absoluta (rango de fechas
6
+ * arbitrario). Ideal para alertas, monitoreo de oportunidades y sincronización
7
+ * incremental de un período pasado.
6
8
  */
7
9
  import { z } from 'zod';
8
10
  import { CompraAgilApiError } from '../utils/error-handler.js';
11
+ import { safeError } from '../utils/redact.js';
9
12
  const TOOL_NAME = 'monitorear_cambios_recientes';
10
- const TOOL_DESCRIPTION = `Busca Compras Ágiles que hayan sido creadas o modificadas en los últimos N minutos.
11
- Ideal para monitoreo de nuevas oportunidades de negocio y alertas en tiempo real.
12
- Internamente convierte los minutos a milisegundos para el parámetro ttl_cambio_ms de la API.
13
+ const TOOL_DESCRIPTION = `Busca Compras Ágiles que hayan sido creadas o modificadas dentro de una ventana de cambios.
14
+ Ideal para monitoreo de nuevas oportunidades de negocio, alertas en tiempo real y sincronización incremental.
15
+ La ventana se define de UNA de dos formas, mutuamente excluyentes:
16
+ • Relativa: 'minutos' (últimos N minutos, máx 1440 = 24h). Es el modo por defecto (60 min).
17
+ • Absoluta: 'cambio_desde' + 'cambio_hasta' (rango ISO-8601 arbitrario), para resincronizar un período pasado
18
+ o retomar desde el último timestamp procesado, sin el techo de 24 horas.
13
19
  Puede combinarse con filtros de estado y región para acotar los resultados.`;
20
+ /** Acepta ISO-8601 con 'Z' o con offset (±HH:MM). Los segundos son opcionales. */
21
+ const ISO_8601 = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(:\d{2})?(\.\d+)?(Z|[+-]\d{2}:\d{2})$/;
14
22
  const inputSchema = {
15
- minutos: z.number().min(1).max(1440).default(60).describe('Buscar cambios en los últimos N minutos. Ej: 60 = última hora, 1440 = últimas 24 horas. Máximo 1440 (24h).'),
23
+ minutos: z.number().min(1).max(1440).optional().describe('Ventana RELATIVA: buscar cambios en los últimos N minutos. Ej: 60 = última hora, 1440 = últimas 24 horas. Máximo 1440 (24h). Se usa 60 por defecto si no se indica ni "minutos" ni un rango. No combinar con "cambio_desde"/"cambio_hasta".'),
24
+ cambio_desde: z.string().optional().describe('Ventana ABSOLUTA: fecha/hora ISO-8601 de inicio del rango de cambios. Ej: "2026-09-01T00:00:00Z". Úsala para sincronización incremental de un período arbitrario (sin el límite de 24h de "minutos"). No combinar con "minutos".'),
25
+ cambio_hasta: z.string().optional().describe('Ventana ABSOLUTA: fecha/hora ISO-8601 de fin del rango de cambios. Ej: "2026-09-02T00:00:00Z". Requiere "cambio_desde". No combinar con "minutos".'),
16
26
  estado: z.string().optional().describe('Filtrar por estado(s), separados por coma. Ej: "publicada" para solo oportunidades abiertas.'),
17
27
  region: z.string().optional().describe('Código(s) de región, separados por coma. Ej: "13" para Metropolitana.'),
18
28
  tamano_pagina: z.number().min(10).max(50).default(50).describe('Resultados por página (10-50, default 50).'),
19
29
  numero_pagina: z.number().min(1).optional().describe('Número de página a consultar (comienza en 1).'),
20
30
  };
31
+ /**
32
+ * Resuelve la ventana de cambios a partir de los argumentos de la herramienta.
33
+ *
34
+ * La API expone dos formas mutuamente excluyentes de acotar los cambios
35
+ * (Guía API Compra Ágil v2 §5.1, Grupo 1): `ttl_cambio_ms` (opción A) o el par
36
+ * `cambio_desde`/`cambio_hasta` (opción B). Enviar ambas a la vez es un 400,
37
+ * así que se decide aquí y se falla localmente para no gastar cuota.
38
+ *
39
+ * Retorna un string con el error de validación, o la ventana resuelta.
40
+ */
41
+ export function resolverVentanaCambios(args) {
42
+ const usaRango = Boolean(args.cambio_desde || args.cambio_hasta);
43
+ if (usaRango && args.minutos !== undefined) {
44
+ return {
45
+ error: 'Error de validación: "minutos" (ventana relativa) y "cambio_desde"/"cambio_hasta" (ventana absoluta) son mutuamente excluyentes. Usa solo uno de los dos modos.',
46
+ };
47
+ }
48
+ if (usaRango) {
49
+ if (!args.cambio_desde) {
50
+ return {
51
+ error: 'Error de validación: "cambio_hasta" requiere también "cambio_desde" para delimitar el rango.',
52
+ };
53
+ }
54
+ for (const [nombre, valor] of [
55
+ ['cambio_desde', args.cambio_desde],
56
+ ['cambio_hasta', args.cambio_hasta],
57
+ ]) {
58
+ if (valor && !ISO_8601.test(valor)) {
59
+ return {
60
+ error: `Error de validación: "${nombre}" debe estar en formato ISO-8601 con zona horaria. Ej: "2026-09-01T00:00:00Z". Recibido: "${valor}".`,
61
+ };
62
+ }
63
+ }
64
+ if (args.cambio_hasta && args.cambio_desde > args.cambio_hasta) {
65
+ return {
66
+ error: `Error de validación: "cambio_desde" (${args.cambio_desde}) es posterior a "cambio_hasta" (${args.cambio_hasta}). El rango quedaría vacío.`,
67
+ };
68
+ }
69
+ return {
70
+ params: { cambio_desde: args.cambio_desde, cambio_hasta: args.cambio_hasta },
71
+ descripcion: args.cambio_hasta
72
+ ? `Cambios entre ${args.cambio_desde} y ${args.cambio_hasta}`
73
+ : `Cambios desde ${args.cambio_desde}`,
74
+ };
75
+ }
76
+ // Modo relativo (por defecto): 60 minutos si no se indicó nada.
77
+ const minutos = args.minutos ?? 60;
78
+ return {
79
+ params: { ttl_cambio_ms: minutos * 60 * 1000 },
80
+ descripcion: `Últimos ${minutos} minutos`,
81
+ };
82
+ }
21
83
  export function registerMonitorearCambios(server, client) {
22
84
  server.registerTool(TOOL_NAME, {
23
85
  description: TOOL_DESCRIPTION,
24
86
  inputSchema: inputSchema,
25
87
  }, async (args) => {
26
88
  try {
27
- const ttlMs = args.minutos * 60 * 1000;
28
- const response = await client.cambiosRecientes(ttlMs, {
89
+ const ventana = resolverVentanaCambios(args);
90
+ if ('error' in ventana) {
91
+ return {
92
+ content: [{ type: 'text', text: ventana.error }],
93
+ isError: true,
94
+ };
95
+ }
96
+ const response = await client.buscar({
97
+ ...ventana.params,
29
98
  estado: args.estado,
30
99
  region: args.region,
31
100
  tamano_pagina: args.tamano_pagina,
@@ -42,7 +111,7 @@ export function registerMonitorearCambios(server, client) {
42
111
  ultimo_cambio: item.fechas.fecha_ultimo_cambio,
43
112
  }));
44
113
  const result = {
45
- ventana_temporal: `Últimos ${args.minutos} minutos`,
114
+ ventana_temporal: ventana.descripcion,
46
115
  total_resultados: response.paginacion.total_resultados,
47
116
  pagina: `${response.paginacion.numero_pagina} de ${response.paginacion.total_paginas}`,
48
117
  resultados: summary,
@@ -57,7 +126,7 @@ export function registerMonitorearCambios(server, client) {
57
126
  catch (error) {
58
127
  const message = error instanceof CompraAgilApiError
59
128
  ? error.actionableMessage
60
- : `Error inesperado: ${String(error)}`;
129
+ : `Error inesperado: ${safeError(error)}`;
61
130
  return {
62
131
  content: [{ type: 'text', text: message }],
63
132
  isError: true,
@@ -1 +1 @@
1
- {"version":3,"file":"monitorear-cambios.js","sourceRoot":"","sources":["../../src/tools/monitorear-cambios.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"monitorear-cambios.js","sourceRoot":"","sources":["../../src/tools/monitorear-cambios.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,45 @@
1
1
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
- import { CompraAgilClient } from '../api/compra-agil-client.js';
2
+ import { CompraAgilClient, CompraAgilItem } from '../api/compra-agil-client.js';
3
+ export interface OportunidadRadar {
4
+ codigo: string;
5
+ nombre: string;
6
+ organismo: string;
7
+ region: string;
8
+ presupuesto_disponible: number;
9
+ ofertas_recibidas: number;
10
+ horas_restantes: number;
11
+ fecha_cierre: string;
12
+ puntuacion_caliente: number;
13
+ factores_calificacion: string[];
14
+ }
15
+ /**
16
+ * Calcula el "Hot Score" de una oportunidad de forma pura (sin efectos secundarios).
17
+ * Retorna null si el proceso debe omitirse (ya cerrado o bajo el presupuesto mínimo).
18
+ * Ponderación: baja competencia (máx 50) + urgencia (máx 30) + presupuesto (máx 20) + facilidad (máx 5).
19
+ */
20
+ export declare function evaluarOportunidad(item: CompraAgilItem, now: number, minBudget?: number): OportunidadRadar | null;
21
+ export interface RadarParams {
22
+ region?: string;
23
+ q?: string;
24
+ presupuesto_minimo?: number;
25
+ limite_resultados?: number;
26
+ max_paginas?: number;
27
+ }
28
+ export interface RadarDatos {
29
+ /** Oportunidades vigentes ya rankeadas y recortadas al límite pedido. */
30
+ oportunidades: OportunidadRadar[];
31
+ /** Total de oportunidades vigentes encontradas antes de aplicar el límite. */
32
+ totalAnalizadas: number;
33
+ limite: number;
34
+ paginasEscaneadas: number;
35
+ }
36
+ /**
37
+ * Recolecta y rankea las oportunidades del radar.
38
+ *
39
+ * Función pura de datos (sin formato de salida): la comparten la tool
40
+ * `radar_oportunidades_calientes` (que emite JSON para el LLM) y el informe
41
+ * HTML/PDF, garantizando que ambos muestren exactamente lo mismo.
42
+ */
43
+ export declare function recolectarDatosRadar(client: CompraAgilClient, params: RadarParams, now?: number): Promise<RadarDatos>;
3
44
  export declare function registerRadarOportunidades(server: McpServer, client: CompraAgilClient): void;
4
45
  //# sourceMappingURL=radar-oportunidades.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"radar-oportunidades.d.ts","sourceRoot":"","sources":["../../src/tools/radar-oportunidades.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AA6BhE,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAoJ5F"}
1
+ {"version":3,"file":"radar-oportunidades.d.ts","sourceRoot":"","sources":["../../src/tools/radar-oportunidades.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAkBhF,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,sBAAsB,EAAE,MAAM,CAAC;IAC/B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,qBAAqB,EAAE,MAAM,EAAE,CAAC;CACjC;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,cAAc,EACpB,GAAG,EAAE,MAAM,EACX,SAAS,SAAI,GACZ,gBAAgB,GAAG,IAAI,CAyEzB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,yEAAyE;IACzE,aAAa,EAAE,gBAAgB,EAAE,CAAC;IAClC,8EAA8E;IAC9E,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;GAMG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,gBAAgB,EACxB,MAAM,EAAE,WAAW,EACnB,GAAG,GAAE,MAAmB,GACvB,OAAO,CAAC,UAAU,CAAC,CA6BrB;AAED,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,gBAAgB,GAAG,IAAI,CA4C5F"}
@@ -1,6 +1,7 @@
1
1
  import { z } from 'zod';
2
2
  import { CompraAgilApiError } from '../utils/error-handler.js';
3
3
  import { logger } from '../utils/logger.js';
4
+ import { safeError } from '../utils/redact.js';
4
5
  const TOOL_NAME = 'radar_oportunidades_calientes';
5
6
  const TOOL_DESCRIPTION = `Escanea, califica y clasifica de forma priorizada los procesos de Compra Ágil activos (publicados).
6
7
  Utiliza una fórmula ponderada (Hot Score) basada en la falta de oferentes, el presupuesto disponible y las horas restantes de cierre para destacar los llamados más convenientes y fáciles de ganar.`;
@@ -9,23 +10,131 @@ const inputSchema = {
9
10
  q: z.string().optional().describe('Término de búsqueda opcional para acotar a un rubro o producto específico (ej: "licencias").'),
10
11
  presupuesto_minimo: z.number().optional().describe('Filtrar solo procesos con presupuesto disponible mayor o igual a este monto en CLP.'),
11
12
  limite_resultados: z.number().min(1).max(20).default(10).optional().describe('Cantidad máxima de oportunidades destacadas a retornar (1-20, default 10).'),
13
+ max_paginas: z.number().min(1).max(10).default(3).optional().describe('Cuántas páginas de 50 resultados escanear antes de rankear (1-10, default 3 = hasta 150 procesos). Más páginas = más cobertura pero más consumo de cuota.'),
12
14
  };
15
+ /**
16
+ * Calcula el "Hot Score" de una oportunidad de forma pura (sin efectos secundarios).
17
+ * Retorna null si el proceso debe omitirse (ya cerrado o bajo el presupuesto mínimo).
18
+ * Ponderación: baja competencia (máx 50) + urgencia (máx 30) + presupuesto (máx 20) + facilidad (máx 5).
19
+ */
20
+ export function evaluarOportunidad(item, now, minBudget = 0) {
21
+ const budget = item.montos?.monto_disponible_clp || item.montos?.monto_disponible || 0;
22
+ if (budget < minBudget)
23
+ return null;
24
+ let hoursLeft = 0;
25
+ if (item.fechas?.fecha_cierre) {
26
+ const cierreTime = new Date(item.fechas.fecha_cierre).getTime();
27
+ hoursLeft = (cierreTime - now) / (1000 * 60 * 60);
28
+ }
29
+ if (hoursLeft <= 0)
30
+ return null;
31
+ let score = 0;
32
+ const factors = [];
33
+ // Factor 1: Baja Competencia — Máx 50 pts
34
+ const bids = item.resumen?.total_ofertas_recibidas ?? 0;
35
+ if (bids === 0) {
36
+ score += 50;
37
+ factors.push('Sin oferentes activos (+50 pts)');
38
+ }
39
+ else if (bids === 1) {
40
+ score += 30;
41
+ factors.push('Baja competencia: solo 1 oferente (+30 pts)');
42
+ }
43
+ else if (bids === 2) {
44
+ score += 15;
45
+ factors.push('Competencia moderada: 2 oferentes (+15 pts)');
46
+ }
47
+ // Factor 2: Urgencia del Cierre — Máx 30 pts
48
+ if (hoursLeft <= 4) {
49
+ score += 30;
50
+ factors.push('Urgencia crítica: cierra en menos de 4 horas (+30 pts)');
51
+ }
52
+ else if (hoursLeft <= 12) {
53
+ score += 20;
54
+ factors.push('Cierre inminente: cierra en menos de 12 horas (+20 pts)');
55
+ }
56
+ else if (hoursLeft <= 24) {
57
+ score += 10;
58
+ factors.push('Cierre cercano: cierra en menos de 24 horas (+10 pts)');
59
+ }
60
+ // Factor 3: Tamaño de Presupuesto — Máx 20 pts
61
+ if (budget >= 5000000) {
62
+ score += 20;
63
+ factors.push('Presupuesto de alto valor (>= $5.000.000 CLP) (+20 pts)');
64
+ }
65
+ else if (budget >= 2000000) {
66
+ score += 15;
67
+ factors.push('Presupuesto medio-alto (>= $2.000.000 CLP) (+15 pts)');
68
+ }
69
+ else if (budget >= 500000) {
70
+ score += 10;
71
+ factors.push('Presupuesto medio (>= $500.000 CLP) (+10 pts)');
72
+ }
73
+ else {
74
+ score += 5;
75
+ factors.push('Presupuesto bajo (< $500.000 CLP) (+5 pts)');
76
+ }
77
+ // Factor 4: Facilidad de Postulación — Máx 5 pts
78
+ const docsCount = item.documentos?.length || 0;
79
+ if (docsCount === 0) {
80
+ score += 5;
81
+ factors.push('Sin documentos adjuntos (postulación rápida sin leer bases) (+5 pts)');
82
+ }
83
+ return {
84
+ codigo: item.codigo,
85
+ nombre: item.nombre,
86
+ organismo: item.institucion?.organismo_comprador || 'No especificado',
87
+ region: item.institucion?.nombre_region || 'No especificada',
88
+ presupuesto_disponible: budget,
89
+ ofertas_recibidas: bids,
90
+ horas_restantes: Math.round(hoursLeft * 10) / 10,
91
+ fecha_cierre: item.fechas?.fecha_cierre,
92
+ puntuacion_caliente: score,
93
+ factores_calificacion: factors,
94
+ };
95
+ }
96
+ /**
97
+ * Recolecta y rankea las oportunidades del radar.
98
+ *
99
+ * Función pura de datos (sin formato de salida): la comparten la tool
100
+ * `radar_oportunidades_calientes` (que emite JSON para el LLM) y el informe
101
+ * HTML/PDF, garantizando que ambos muestren exactamente lo mismo.
102
+ */
103
+ export async function recolectarDatosRadar(client, params, now = Date.now()) {
104
+ const maxPaginas = params.max_paginas || 3;
105
+ logger.info(`radar: escaneando procesos activos (hasta ${maxPaginas} pág.) region="${params.region || 'Todas'}" q="${params.q || 'Todos'}"`);
106
+ // Auto-paginación: escanear varias páginas para no perder oportunidades en páginas 2+
107
+ const items = await client.buscarTodo({
108
+ estado: 'publicada',
109
+ region: params.region || undefined,
110
+ q: params.q || undefined,
111
+ tamano_pagina: 50,
112
+ }, maxPaginas);
113
+ const minBudget = params.presupuesto_minimo || 0;
114
+ const opportunities = [];
115
+ for (const item of items) {
116
+ const evaluada = evaluarOportunidad(item, now, minBudget);
117
+ if (evaluada)
118
+ opportunities.push(evaluada);
119
+ }
120
+ // Ordenar descendentemente por puntuación caliente
121
+ opportunities.sort((a, b) => b.puntuacion_caliente - a.puntuacion_caliente);
122
+ const limite = params.limite_resultados || 10;
123
+ return {
124
+ oportunidades: opportunities.slice(0, limite),
125
+ totalAnalizadas: opportunities.length,
126
+ limite,
127
+ paginasEscaneadas: maxPaginas,
128
+ };
129
+ }
13
130
  export function registerRadarOportunidades(server, client) {
14
131
  server.registerTool(TOOL_NAME, {
15
132
  description: TOOL_DESCRIPTION,
16
133
  inputSchema: inputSchema,
17
134
  }, async (args) => {
18
135
  try {
19
- const queryParams = {
20
- estado: 'publicada',
21
- region: args.region || undefined,
22
- q: args.q || undefined,
23
- tamano_pagina: 50, // Obtener un lote amplio de 50 para poder rankear
24
- numero_pagina: 1,
25
- };
26
- logger.info(`radar_oportunidades_calientes: Escaneando procesos activos para region="${args.region || 'Todas'}" q="${args.q || 'Todos'}"`);
27
- const searchResponse = await client.buscar(queryParams);
28
- if (!searchResponse.items || searchResponse.items.length === 0) {
136
+ const datos = await recolectarDatosRadar(client, args);
137
+ if (datos.totalAnalizadas === 0) {
29
138
  return {
30
139
  content: [{
31
140
  type: 'text',
@@ -33,99 +142,10 @@ export function registerRadarOportunidades(server, client) {
33
142
  }],
34
143
  };
35
144
  }
36
- const now = Date.now();
37
- const opportunities = [];
38
- const minBudget = args.presupuesto_minimo || 0;
39
- for (const item of searchResponse.items) {
40
- const budget = item.montos?.monto_disponible_clp || item.montos?.monto_disponible || 0;
41
- // Filtrar por presupuesto mínimo si corresponde
42
- if (budget < minBudget) {
43
- continue;
44
- }
45
- // Calcular tiempo restante en horas
46
- let hoursLeft = 0;
47
- if (item.fechas?.fecha_cierre) {
48
- const cierreTime = new Date(item.fechas.fecha_cierre).getTime();
49
- hoursLeft = (cierreTime - now) / (1000 * 60 * 60);
50
- }
51
- // Omitir procesos que ya cerraron o están en negativo por zona horaria
52
- if (hoursLeft <= 0) {
53
- continue;
54
- }
55
- let score = 0;
56
- const factors = [];
57
- // Factor 1: Baja Competencia (total_ofertas_recibidas) - Máx 50 pts
58
- const bids = item.resumen?.total_ofertas_recibidas ?? 0;
59
- if (bids === 0) {
60
- score += 50;
61
- factors.push('Sin oferentes activos (+50 pts)');
62
- }
63
- else if (bids === 1) {
64
- score += 30;
65
- factors.push('Baja competencia: solo 1 oferente (+30 pts)');
66
- }
67
- else if (bids === 2) {
68
- score += 15;
69
- factors.push('Competencia moderada: 2 oferentes (+15 pts)');
70
- }
71
- // Factor 2: Urgencia del Cierre (horas restantes) - Máx 30 pts
72
- if (hoursLeft <= 4) {
73
- score += 30;
74
- factors.push('Urgencia crítica: cierra en menos de 4 horas (+30 pts)');
75
- }
76
- else if (hoursLeft <= 12) {
77
- score += 20;
78
- factors.push('Cierre inminente: cierra en menos de 12 horas (+20 pts)');
79
- }
80
- else if (hoursLeft <= 24) {
81
- score += 10;
82
- factors.push('Cierre cercano: cierra en menos de 24 horas (+10 pts)');
83
- }
84
- // Factor 3: Tamaño de Presupuesto - Máx 20 pts
85
- if (budget >= 5000000) {
86
- score += 20;
87
- factors.push('Presupuesto de alto valor (>= $5.000.000 CLP) (+20 pts)');
88
- }
89
- else if (budget >= 2000000) {
90
- score += 15;
91
- factors.push('Presupuesto medio-alto (>= $2.000.000 CLP) (+15 pts)');
92
- }
93
- else if (budget >= 500000) {
94
- score += 10;
95
- factors.push('Presupuesto medio (>= $500.000 CLP) (+10 pts)');
96
- }
97
- else {
98
- score += 5;
99
- factors.push('Presupuesto bajo (< $500.000 CLP) (+5 pts)');
100
- }
101
- // Factor 4: Facilidad de Postulación - Máx 5 pts
102
- const docsCount = item.documentos?.length || 0;
103
- if (docsCount === 0) {
104
- score += 5;
105
- factors.push('Sin documentos adjuntos (postulación rápida sin leer bases) (+5 pts)');
106
- }
107
- opportunities.push({
108
- codigo: item.codigo,
109
- nombre: item.nombre,
110
- organismo: item.institucion?.organismo_comprador || 'No especificado',
111
- region: item.institucion?.nombre_region || 'No especificada',
112
- presupuesto_disponible: budget,
113
- ofertas_recibidas: bids,
114
- horas_restantes: Math.round(hoursLeft * 10) / 10,
115
- fecha_cierre: item.fechas?.fecha_cierre,
116
- puntuacion_caliente: score,
117
- factores_calificacion: factors,
118
- });
119
- }
120
- // Ordenar descendentemente por puntuación caliente
121
- opportunities.sort((a, b) => b.puntuacion_caliente - a.puntuacion_caliente);
122
- // Aplicar límite
123
- const limit = args.limite_resultados || 10;
124
- const rankedOpportunities = opportunities.slice(0, limit);
125
145
  const result = {
126
- total_oportunidades_analizadas: opportunities.length,
127
- radar_limite_resultados: limit,
128
- oportunidades_calientes: rankedOpportunities,
146
+ total_oportunidades_analizadas: datos.totalAnalizadas,
147
+ radar_limite_resultados: datos.limite,
148
+ oportunidades_calientes: datos.oportunidades,
129
149
  };
130
150
  return {
131
151
  content: [{
@@ -137,7 +157,7 @@ export function registerRadarOportunidades(server, client) {
137
157
  catch (error) {
138
158
  const message = error instanceof CompraAgilApiError
139
159
  ? error.actionableMessage
140
- : `Error inesperado en radar de oportunidades: ${String(error)}`;
160
+ : `Error inesperado en radar de oportunidades: ${safeError(error)}`;
141
161
  return {
142
162
  content: [{ type: 'text', text: message }],
143
163
  isError: true,
@@ -1 +1 @@
1
- {"version":3,"file":"radar-oportunidades.js","sourceRoot":"","sources":["../../src/tools/radar-oportunidades.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C,MAAM,SAAS,GAAG,+BAA+B,CAAC;AAElD,MAAM,gBAAgB,GAAG;qMAC4K,CAAC;AAEtM,MAAM,WAAW,GAAG;IAClB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,uEAAuE,CAAC;IAC/G,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,8FAA8F,CAAC;IACjI,kBAAkB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,qFAAqF,CAAC;IACzI,iBAAiB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,4EAA4E,CAAC;CAC3J,CAAC;AAeF,MAAM,UAAU,0BAA0B,CAAC,MAAiB,EAAE,MAAwB;IACpF,MAAM,CAAC,YAAY,CACjB,SAAS,EACT;QACE,WAAW,EAAE,gBAAgB;QAC7B,WAAW,EAAE,WAAW;KACzB,EACD,KAAK,EAAE,IAAI,EAAE,EAAE;QACb,IAAI,CAAC;YACH,MAAM,WAAW,GAAG;gBAClB,MAAM,EAAE,WAAW;gBACnB,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,SAAS;gBAChC,CAAC,EAAE,IAAI,CAAC,CAAC,IAAI,SAAS;gBACtB,aAAa,EAAE,EAAE,EAAE,kDAAkD;gBACrE,aAAa,EAAE,CAAC;aACjB,CAAC;YAEF,MAAM,CAAC,IAAI,CAAC,2EAA2E,IAAI,CAAC,MAAM,IAAI,OAAO,QAAQ,IAAI,CAAC,CAAC,IAAI,OAAO,GAAG,CAAC,CAAC;YAC3I,MAAM,cAAc,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;YAExD,IAAI,CAAC,cAAc,CAAC,KAAK,IAAI,cAAc,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC/D,OAAO;oBACL,OAAO,EAAE,CAAC;4BACR,IAAI,EAAE,MAAe;4BACrB,IAAI,EAAE,qFAAqF;yBAC5F,CAAC;iBACH,CAAC;YACJ,CAAC;YAED,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACvB,MAAM,aAAa,GAAuB,EAAE,CAAC;YAC7C,MAAM,SAAS,GAAG,IAAI,CAAC,kBAAkB,IAAI,CAAC,CAAC;YAE/C,KAAK,MAAM,IAAI,IAAI,cAAc,CAAC,KAAK,EAAE,CAAC;gBACxC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,oBAAoB,IAAI,IAAI,CAAC,MAAM,EAAE,gBAAgB,IAAI,CAAC,CAAC;gBAEvF,gDAAgD;gBAChD,IAAI,MAAM,GAAG,SAAS,EAAE,CAAC;oBACvB,SAAS;gBACX,CAAC;gBAED,oCAAoC;gBACpC,IAAI,SAAS,GAAG,CAAC,CAAC;gBAClB,IAAI,IAAI,CAAC,MAAM,EAAE,YAAY,EAAE,CAAC;oBAC9B,MAAM,UAAU,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,OAAO,EAAE,CAAC;oBAChE,SAAS,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC,GAAG,CAAC,IAAI,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC;gBACpD,CAAC;gBAED,uEAAuE;gBACvE,IAAI,SAAS,IAAI,CAAC,EAAE,CAAC;oBACnB,SAAS;gBACX,CAAC;gBAED,IAAI,KAAK,GAAG,CAAC,CAAC;gBACd,MAAM,OAAO,GAAa,EAAE,CAAC;gBAE7B,oEAAoE;gBACpE,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,uBAAuB,IAAI,CAAC,CAAC;gBACxD,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;oBACf,KAAK,IAAI,EAAE,CAAC;oBACZ,OAAO,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC;gBAClD,CAAC;qBAAM,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;oBACtB,KAAK,IAAI,EAAE,CAAC;oBACZ,OAAO,CAAC,IAAI,CAAC,6CAA6C,CAAC,CAAC;gBAC9D,CAAC;qBAAM,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;oBACtB,KAAK,IAAI,EAAE,CAAC;oBACZ,OAAO,CAAC,IAAI,CAAC,6CAA6C,CAAC,CAAC;gBAC9D,CAAC;gBAED,+DAA+D;gBAC/D,IAAI,SAAS,IAAI,CAAC,EAAE,CAAC;oBACnB,KAAK,IAAI,EAAE,CAAC;oBACZ,OAAO,CAAC,IAAI,CAAC,wDAAwD,CAAC,CAAC;gBACzE,CAAC;qBAAM,IAAI,SAAS,IAAI,EAAE,EAAE,CAAC;oBAC3B,KAAK,IAAI,EAAE,CAAC;oBACZ,OAAO,CAAC,IAAI,CAAC,yDAAyD,CAAC,CAAC;gBAC1E,CAAC;qBAAM,IAAI,SAAS,IAAI,EAAE,EAAE,CAAC;oBAC3B,KAAK,IAAI,EAAE,CAAC;oBACZ,OAAO,CAAC,IAAI,CAAC,uDAAuD,CAAC,CAAC;gBACxE,CAAC;gBAED,+CAA+C;gBAC/C,IAAI,MAAM,IAAI,OAAO,EAAE,CAAC;oBACtB,KAAK,IAAI,EAAE,CAAC;oBACZ,OAAO,CAAC,IAAI,CAAC,yDAAyD,CAAC,CAAC;gBAC1E,CAAC;qBAAM,IAAI,MAAM,IAAI,OAAO,EAAE,CAAC;oBAC7B,KAAK,IAAI,EAAE,CAAC;oBACZ,OAAO,CAAC,IAAI,CAAC,sDAAsD,CAAC,CAAC;gBACvE,CAAC;qBAAM,IAAI,MAAM,IAAI,MAAM,EAAE,CAAC;oBAC5B,KAAK,IAAI,EAAE,CAAC;oBACZ,OAAO,CAAC,IAAI,CAAC,+CAA+C,CAAC,CAAC;gBAChE,CAAC;qBAAM,CAAC;oBACN,KAAK,IAAI,CAAC,CAAC;oBACX,OAAO,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC;gBAC7D,CAAC;gBAED,iDAAiD;gBACjD,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,EAAE,MAAM,IAAI,CAAC,CAAC;gBAC/C,IAAI,SAAS,KAAK,CAAC,EAAE,CAAC;oBACpB,KAAK,IAAI,CAAC,CAAC;oBACX,OAAO,CAAC,IAAI,CAAC,sEAAsE,CAAC,CAAC;gBACvF,CAAC;gBAED,aAAa,CAAC,IAAI,CAAC;oBACjB,MAAM,EAAE,IAAI,CAAC,MAAM;oBACnB,MAAM,EAAE,IAAI,CAAC,MAAM;oBACnB,SAAS,EAAE,IAAI,CAAC,WAAW,EAAE,mBAAmB,IAAI,iBAAiB;oBACrE,MAAM,EAAE,IAAI,CAAC,WAAW,EAAE,aAAa,IAAI,iBAAiB;oBAC5D,sBAAsB,EAAE,MAAM;oBAC9B,iBAAiB,EAAE,IAAI;oBACvB,eAAe,EAAE,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,EAAE,CAAC,GAAG,EAAE;oBAChD,YAAY,EAAE,IAAI,CAAC,MAAM,EAAE,YAAY;oBACvC,mBAAmB,EAAE,KAAK;oBAC1B,qBAAqB,EAAE,OAAO;iBAC/B,CAAC,CAAC;YACL,CAAC;YAED,mDAAmD;YACnD,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,mBAAmB,GAAG,CAAC,CAAC,mBAAmB,CAAC,CAAC;YAE5E,iBAAiB;YACjB,MAAM,KAAK,GAAG,IAAI,CAAC,iBAAiB,IAAI,EAAE,CAAC;YAC3C,MAAM,mBAAmB,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;YAE1D,MAAM,MAAM,GAAG;gBACb,8BAA8B,EAAE,aAAa,CAAC,MAAM;gBACpD,uBAAuB,EAAE,KAAK;gBAC9B,uBAAuB,EAAE,mBAAmB;aAC7C,CAAC;YAEF,OAAO;gBACL,OAAO,EAAE,CAAC;wBACR,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;qBACtC,CAAC;aACH,CAAC;QAEJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,OAAO,GAAG,KAAK,YAAY,kBAAkB;gBACjD,CAAC,CAAC,KAAK,CAAC,iBAAiB;gBACzB,CAAC,CAAC,+CAA+C,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;YACnE,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;gBACnD,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"radar-oportunidades.js","sourceRoot":"","sources":["../../src/tools/radar-oportunidades.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,17 @@
1
1
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
2
  import { CompraAgilClient } from '../api/compra-agil-client.js';
3
3
  export declare function registerRecomendarPrecio(server: McpServer, client: CompraAgilClient): void;
4
+ interface EstadisticasPrecio {
5
+ muestras: number;
6
+ minimo: number;
7
+ maximo: number;
8
+ promedio: number;
9
+ mediana: number;
10
+ }
11
+ /**
12
+ * Calcula min/max/promedio/mediana de una serie de precios.
13
+ * Retorna null si la serie está vacía (para poder distinguir "sin datos").
14
+ */
15
+ export declare function calcularEstadisticas(valores: number[]): EstadisticasPrecio | null;
16
+ export {};
4
17
  //# sourceMappingURL=recomendar-precio.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"recomendar-precio.d.ts","sourceRoot":"","sources":["../../src/tools/recomendar-precio.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAiBhE,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,gBAAgB,GAAG,IAAI,CA0L1F"}
1
+ {"version":3,"file":"recomendar-precio.d.ts","sourceRoot":"","sources":["../../src/tools/recomendar-precio.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAoBhE,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAgK1F;AAED,UAAU,kBAAkB;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,kBAAkB,GAAG,IAAI,CAWjF"}