@quantyapp/quanty-mcp-server 1.0.10 → 1.2.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.
@@ -0,0 +1,94 @@
1
+ import { AuthContext } from './auth.js';
2
+ export interface LearningEntry {
3
+ id?: string;
4
+ task_signature: string;
5
+ task_description: string;
6
+ solution_steps: any[];
7
+ context_used?: any;
8
+ success_metrics: {
9
+ execution_time?: number;
10
+ items_processed?: number;
11
+ accuracy?: number;
12
+ };
13
+ confidence_score: number;
14
+ usage_count: number;
15
+ last_used: string;
16
+ created_at: string;
17
+ tenant_id: string;
18
+ }
19
+ export interface OperationPattern {
20
+ id?: string;
21
+ pattern_name: string;
22
+ trigger_keywords: string[];
23
+ preconditions: any;
24
+ action_sequence: any[];
25
+ success_criteria: any;
26
+ variations: any[];
27
+ optimization_hints: string[];
28
+ version: number;
29
+ tenant_id: string;
30
+ }
31
+ export interface KnowledgeContext {
32
+ similar_tasks: LearningEntry[];
33
+ relevant_patterns: OperationPattern[];
34
+ best_practices: string[];
35
+ warnings: string[];
36
+ }
37
+ export declare class QuantyLearningSystem {
38
+ private auth;
39
+ constructor(auth: AuthContext);
40
+ /**
41
+ * Creates a unique signature for a task based on its characteristics
42
+ */
43
+ private createTaskSignature;
44
+ private hashString;
45
+ /**
46
+ * Load knowledge base from Supabase
47
+ */
48
+ loadKnowledgeBase(): Promise<void>;
49
+ /**
50
+ * Find similar tasks from history
51
+ */
52
+ findSimilarTasks(task: string, limit?: number): Promise<LearningEntry[]>;
53
+ /**
54
+ * Get relevant knowledge for a task
55
+ */
56
+ getRelevantKnowledge(task: string): Promise<KnowledgeContext>;
57
+ /**
58
+ * Learn from a successful execution
59
+ */
60
+ learnFromExecution(task: string, steps: any[], result: any, executionTime: number): Promise<void>;
61
+ /**
62
+ * Extract patterns from successful executions
63
+ */
64
+ private extractAndUpdatePatterns;
65
+ private extractKeywords;
66
+ /**
67
+ * Process user feedback on executions
68
+ */
69
+ processFeedback(taskSignature: string, feedbackType: 'success' | 'failure' | 'improvement', details?: string): Promise<void>;
70
+ /**
71
+ * Get learning statistics
72
+ */
73
+ getStatistics(): Promise<any>;
74
+ /**
75
+ * Clean up old or low-confidence entries
76
+ */
77
+ pruneKnowledge(): Promise<void>;
78
+ }
79
+ export declare class ContextBuilder {
80
+ private learning;
81
+ constructor(learning: QuantyLearningSystem);
82
+ /**
83
+ * Build enriched context for a task
84
+ */
85
+ buildContext(task: string): Promise<string>;
86
+ /**
87
+ * Generate system prompt with accumulated knowledge
88
+ */
89
+ generateSystemPrompt(basePrompt: string): Promise<string>;
90
+ }
91
+ export declare function initLearningSystem(auth: AuthContext): void;
92
+ export declare function getLearningSystem(): QuantyLearningSystem;
93
+ export declare function getContextBuilder(): ContextBuilder;
94
+ //# sourceMappingURL=learningService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"learningService.d.ts","sourceRoot":"","sources":["../../src/core/learningService.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,462 @@
1
+ import { supabase } from './supabase.js';
2
+ // ================ CACHE MANAGEMENT ================
3
+ class LearningCache {
4
+ cache = new Map();
5
+ patterns = new Map();
6
+ lastSync = new Date();
7
+ CACHE_TTL = 5 * 60 * 1000; // 5 minutes
8
+ isStale() {
9
+ return Date.now() - this.lastSync.getTime() > this.CACHE_TTL;
10
+ }
11
+ clear() {
12
+ this.cache.clear();
13
+ this.patterns.clear();
14
+ }
15
+ addEntry(entry) {
16
+ if (entry.task_signature) {
17
+ this.cache.set(entry.task_signature, entry);
18
+ }
19
+ }
20
+ addPattern(pattern) {
21
+ this.patterns.set(pattern.pattern_name, pattern);
22
+ }
23
+ getEntry(signature) {
24
+ return this.cache.get(signature);
25
+ }
26
+ getPattern(name) {
27
+ return this.patterns.get(name);
28
+ }
29
+ getAllEntries() {
30
+ return Array.from(this.cache.values());
31
+ }
32
+ getAllPatterns() {
33
+ return Array.from(this.patterns.values());
34
+ }
35
+ updateSyncTime() {
36
+ this.lastSync = new Date();
37
+ }
38
+ }
39
+ const learningCache = new LearningCache();
40
+ // ================ CORE LEARNING SYSTEM ================
41
+ export class QuantyLearningSystem {
42
+ auth;
43
+ constructor(auth) {
44
+ this.auth = auth;
45
+ }
46
+ /**
47
+ * Creates a unique signature for a task based on its characteristics
48
+ */
49
+ createTaskSignature(task) {
50
+ // Extract key components from task
51
+ const normalized = task.toLowerCase()
52
+ .replace(/['"]/g, '')
53
+ .replace(/\s+/g, ' ')
54
+ .trim();
55
+ // Extract operation type
56
+ let operationType = 'unknown';
57
+ if (normalized.includes('criar') || normalized.includes('novo'))
58
+ operationType = 'create';
59
+ else if (normalized.includes('adicionar') || normalized.includes('incluir'))
60
+ operationType = 'add';
61
+ else if (normalized.includes('buscar') || normalized.includes('pesquisar'))
62
+ operationType = 'search';
63
+ else if (normalized.includes('analisar') || normalized.includes('análise'))
64
+ operationType = 'analyze';
65
+ else if (normalized.includes('importar'))
66
+ operationType = 'import';
67
+ else if (normalized.includes('excluir') || normalized.includes('remover'))
68
+ operationType = 'delete';
69
+ // Extract entity type
70
+ let entityType = 'unknown';
71
+ if (normalized.includes('orçamento'))
72
+ entityType = 'budget';
73
+ else if (normalized.includes('item') || normalized.includes('insumo'))
74
+ entityType = 'item';
75
+ else if (normalized.includes('composição'))
76
+ entityType = 'composition';
77
+ else if (normalized.includes('banco'))
78
+ entityType = 'bank';
79
+ // Create signature
80
+ return `${operationType}:${entityType}:${this.hashString(normalized)}`;
81
+ }
82
+ hashString(str) {
83
+ let hash = 0;
84
+ for (let i = 0; i < str.length; i++) {
85
+ const char = str.charCodeAt(i);
86
+ hash = ((hash << 5) - hash) + char;
87
+ hash = hash & hash; // Convert to 32-bit integer
88
+ }
89
+ return Math.abs(hash).toString(36);
90
+ }
91
+ /**
92
+ * Load knowledge base from Supabase
93
+ */
94
+ async loadKnowledgeBase() {
95
+ if (!learningCache.isStale())
96
+ return;
97
+ try {
98
+ // Load learning entries
99
+ const { data: entries, error: entriesError } = await supabase
100
+ .from('ai_learnings')
101
+ .select('*')
102
+ .eq('tenant_id', this.auth.tenantId)
103
+ .order('confidence_score', { ascending: false })
104
+ .limit(100);
105
+ if (!entriesError && entries) {
106
+ learningCache.clear();
107
+ entries.forEach((e) => learningCache.addEntry(e));
108
+ }
109
+ // Load patterns
110
+ const { data: patterns, error: patternsError } = await supabase
111
+ .from('ai_patterns')
112
+ .select('*')
113
+ .eq('tenant_id', this.auth.tenantId)
114
+ .order('version', { ascending: false });
115
+ if (!patternsError && patterns) {
116
+ patterns.forEach((p) => learningCache.addPattern(p));
117
+ }
118
+ learningCache.updateSyncTime();
119
+ }
120
+ catch (error) {
121
+ console.error('Failed to load knowledge base:', error);
122
+ }
123
+ }
124
+ /**
125
+ * Find similar tasks from history
126
+ */
127
+ async findSimilarTasks(task, limit = 5) {
128
+ await this.loadKnowledgeBase();
129
+ const taskLower = task.toLowerCase();
130
+ const taskWords = new Set(taskLower.split(/\s+/));
131
+ const scoredEntries = learningCache.getAllEntries().map(entry => {
132
+ const descWords = new Set(entry.task_description.toLowerCase().split(/\s+/));
133
+ const intersection = new Set([...taskWords].filter(x => descWords.has(x)));
134
+ const union = new Set([...taskWords, ...descWords]);
135
+ // Jaccard similarity
136
+ const similarity = intersection.size / union.size;
137
+ // Boost score based on confidence and usage
138
+ const score = similarity * entry.confidence_score * Math.log(entry.usage_count + 1);
139
+ return { entry, score };
140
+ });
141
+ return scoredEntries
142
+ .sort((a, b) => b.score - a.score)
143
+ .slice(0, limit)
144
+ .map(s => s.entry);
145
+ }
146
+ /**
147
+ * Get relevant knowledge for a task
148
+ */
149
+ async getRelevantKnowledge(task) {
150
+ await this.loadKnowledgeBase();
151
+ const similarTasks = await this.findSimilarTasks(task);
152
+ const taskLower = task.toLowerCase();
153
+ // Find relevant patterns
154
+ const relevantPatterns = learningCache.getAllPatterns().filter(pattern => {
155
+ return pattern.trigger_keywords.some(keyword => taskLower.includes(keyword.toLowerCase()));
156
+ });
157
+ // Extract best practices from successful similar tasks
158
+ const bestPractices = [];
159
+ const warnings = [];
160
+ for (const similar of similarTasks) {
161
+ if (similar.confidence_score > 0.8) {
162
+ if (similar.success_metrics.execution_time && similar.success_metrics.execution_time < 1000) {
163
+ // Fast execution hints could be added here
164
+ }
165
+ }
166
+ }
167
+ // Extract optimization hints from patterns
168
+ for (const pattern of relevantPatterns) {
169
+ if (pattern.optimization_hints) {
170
+ bestPractices.push(...pattern.optimization_hints);
171
+ }
172
+ }
173
+ return {
174
+ similar_tasks: similarTasks,
175
+ relevant_patterns: relevantPatterns,
176
+ best_practices: [...new Set(bestPractices)],
177
+ warnings
178
+ };
179
+ }
180
+ /**
181
+ * Learn from a successful execution
182
+ */
183
+ async learnFromExecution(task, steps, result, executionTime) {
184
+ const signature = this.createTaskSignature(task);
185
+ // Check if we already have this task
186
+ const existing = learningCache.getEntry(signature);
187
+ if (existing) {
188
+ // Update existing entry
189
+ const updatedEntry = {
190
+ ...existing,
191
+ usage_count: existing.usage_count + 1,
192
+ confidence_score: Math.min(1, existing.confidence_score + 0.05),
193
+ last_used: new Date().toISOString(),
194
+ success_metrics: {
195
+ ...existing.success_metrics,
196
+ execution_time: (existing.success_metrics.execution_time + executionTime) / 2
197
+ }
198
+ };
199
+ await supabase
200
+ .from('ai_learnings')
201
+ .update(updatedEntry)
202
+ .eq('id', existing.id);
203
+ learningCache.addEntry(updatedEntry);
204
+ }
205
+ else {
206
+ // Create new entry
207
+ const newEntry = {
208
+ task_signature: signature,
209
+ task_description: task,
210
+ solution_steps: steps,
211
+ success_metrics: {
212
+ execution_time: executionTime,
213
+ items_processed: result.items_processed || 0,
214
+ accuracy: 1.0
215
+ },
216
+ confidence_score: 0.7,
217
+ usage_count: 1,
218
+ last_used: new Date().toISOString(),
219
+ created_at: new Date().toISOString(),
220
+ tenant_id: this.auth.tenantId
221
+ };
222
+ const { data, error } = await supabase
223
+ .from('ai_learnings')
224
+ .insert(newEntry)
225
+ .select()
226
+ .single();
227
+ if (!error && data) {
228
+ learningCache.addEntry(data);
229
+ }
230
+ }
231
+ // Extract and update patterns
232
+ await this.extractAndUpdatePatterns(task, steps, result);
233
+ }
234
+ /**
235
+ * Extract patterns from successful executions
236
+ */
237
+ async extractAndUpdatePatterns(task, steps, result) {
238
+ // Extract keywords from task
239
+ const keywords = this.extractKeywords(task);
240
+ // Try to find existing pattern
241
+ const existingPattern = learningCache.getAllPatterns().find(p => p.trigger_keywords.some(k => keywords.includes(k)));
242
+ if (existingPattern) {
243
+ // Add variation to existing pattern
244
+ const variation = {
245
+ task,
246
+ steps,
247
+ result,
248
+ timestamp: new Date().toISOString()
249
+ };
250
+ const variations = existingPattern.variations || [];
251
+ const updatedPattern = {
252
+ ...existingPattern,
253
+ variations: [...variations, variation].slice(-10), // Keep last 10 variations
254
+ version: existingPattern.version + 1
255
+ };
256
+ await supabase
257
+ .from('ai_patterns')
258
+ .update(updatedPattern)
259
+ .eq('id', existingPattern.id);
260
+ learningCache.addPattern(updatedPattern);
261
+ }
262
+ else if (keywords.length > 0) {
263
+ // Create new pattern
264
+ const newPattern = {
265
+ pattern_name: `pattern_${this.hashString(task)}`,
266
+ trigger_keywords: keywords,
267
+ preconditions: {},
268
+ action_sequence: steps,
269
+ success_criteria: result,
270
+ variations: [],
271
+ optimization_hints: [],
272
+ version: 1,
273
+ tenant_id: this.auth.tenantId
274
+ };
275
+ const { data, error } = await supabase
276
+ .from('ai_patterns')
277
+ .insert(newPattern)
278
+ .select()
279
+ .single();
280
+ if (!error && data) {
281
+ learningCache.addPattern(data);
282
+ }
283
+ }
284
+ }
285
+ extractKeywords(text) {
286
+ const stopWords = new Set(['o', 'a', 'de', 'para', 'com', 'em', 'do', 'da', 'um', 'uma']);
287
+ const words = text.toLowerCase()
288
+ .split(/\s+/)
289
+ .filter(w => w.length > 3 && !stopWords.has(w));
290
+ // Return unique significant words
291
+ return [...new Set(words)];
292
+ }
293
+ /**
294
+ * Process user feedback on executions
295
+ */
296
+ async processFeedback(taskSignature, feedbackType, details) {
297
+ const entry = learningCache.getEntry(taskSignature);
298
+ if (!entry)
299
+ return;
300
+ // Adjust confidence based on feedback
301
+ let confidenceAdjustment = 0;
302
+ switch (feedbackType) {
303
+ case 'success':
304
+ confidenceAdjustment = 0.1;
305
+ break;
306
+ case 'failure':
307
+ confidenceAdjustment = -0.2;
308
+ break;
309
+ case 'improvement':
310
+ confidenceAdjustment = 0.05;
311
+ break;
312
+ }
313
+ const updatedEntry = {
314
+ ...entry,
315
+ confidence_score: Math.max(0, Math.min(1, entry.confidence_score + confidenceAdjustment))
316
+ };
317
+ await supabase
318
+ .from('ai_learnings')
319
+ .update(updatedEntry)
320
+ .eq('id', entry.id);
321
+ // Store feedback record
322
+ await supabase
323
+ .from('ai_feedback')
324
+ .insert({
325
+ learning_id: entry.id,
326
+ feedback_type: feedbackType,
327
+ details,
328
+ created_at: new Date().toISOString(),
329
+ tenant_id: this.auth.tenantId
330
+ });
331
+ learningCache.addEntry(updatedEntry);
332
+ }
333
+ /**
334
+ * Get learning statistics
335
+ */
336
+ async getStatistics() {
337
+ await this.loadKnowledgeBase();
338
+ const entries = learningCache.getAllEntries();
339
+ const patterns = learningCache.getAllPatterns();
340
+ return {
341
+ total_learnings: entries.length,
342
+ total_patterns: patterns.length,
343
+ average_confidence: entries.length > 0 ? entries.reduce((sum, e) => sum + e.confidence_score, 0) / entries.length : 0,
344
+ most_used_tasks: entries
345
+ .sort((a, b) => b.usage_count - a.usage_count)
346
+ .slice(0, 5)
347
+ .map(e => ({ task: e.task_description, count: e.usage_count })),
348
+ recent_learnings: entries
349
+ .sort((a, b) => new Date(b.last_used).getTime() - new Date(a.last_used).getTime())
350
+ .slice(0, 5)
351
+ .map(e => ({ task: e.task_description, date: e.last_used }))
352
+ };
353
+ }
354
+ /**
355
+ * Clean up old or low-confidence entries
356
+ */
357
+ async pruneKnowledge() {
358
+ const thirtyDaysAgo = new Date();
359
+ thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);
360
+ // Remove entries with low confidence that haven't been used recently
361
+ await supabase
362
+ .from('ai_learnings')
363
+ .delete()
364
+ .eq('tenant_id', this.auth.tenantId)
365
+ .lt('confidence_score', 0.3)
366
+ .lt('last_used', thirtyDaysAgo.toISOString());
367
+ // Refresh cache
368
+ learningCache.clear();
369
+ await this.loadKnowledgeBase();
370
+ }
371
+ }
372
+ // ================ CONTEXT BUILDER ================
373
+ export class ContextBuilder {
374
+ learning;
375
+ constructor(learning) {
376
+ this.learning = learning;
377
+ }
378
+ /**
379
+ * Build enriched context for a task
380
+ */
381
+ async buildContext(task) {
382
+ const knowledge = await this.learning.getRelevantKnowledge(task);
383
+ let context = '';
384
+ // Add similar tasks context
385
+ if (knowledge.similar_tasks.length > 0) {
386
+ context += 'EXPERIÊNCIAS ANTERIORES SIMILARES:\n';
387
+ for (const similar of knowledge.similar_tasks.slice(0, 3)) {
388
+ context += `- ${similar.task_description}\n`;
389
+ if (similar.solution_steps.length > 0) {
390
+ context += ` Passos: ${JSON.stringify(similar.solution_steps.slice(0, 3))}\n`;
391
+ }
392
+ context += ` Confiança: ${(similar.confidence_score * 100).toFixed(0)}%\n`;
393
+ }
394
+ context += '\n';
395
+ }
396
+ // Add patterns
397
+ if (knowledge.relevant_patterns.length > 0) {
398
+ context += 'PADRÕES IDENTIFICADOS:\n';
399
+ for (const pattern of knowledge.relevant_patterns) {
400
+ context += `- ${pattern.pattern_name}: `;
401
+ context += `${JSON.stringify(pattern.action_sequence.slice(0, 3))}\n`;
402
+ }
403
+ context += '\n';
404
+ }
405
+ // Add best practices
406
+ if (knowledge.best_practices.length > 0) {
407
+ context += 'MELHORES PRÁTICAS:\n';
408
+ for (const practice of knowledge.best_practices) {
409
+ context += `- ${practice}\n`;
410
+ }
411
+ context += '\n';
412
+ }
413
+ // Add warnings
414
+ if (knowledge.warnings.length > 0) {
415
+ context += 'AVISOS:\n';
416
+ for (const warning of knowledge.warnings) {
417
+ context += `⚠️ ${warning}\n`;
418
+ }
419
+ context += '\n';
420
+ }
421
+ return context;
422
+ }
423
+ /**
424
+ * Generate system prompt with accumulated knowledge
425
+ */
426
+ async generateSystemPrompt(basePrompt) {
427
+ const stats = await this.learning.getStatistics();
428
+ let enhancedPrompt = basePrompt + '\n\n';
429
+ enhancedPrompt += '=== CONHECIMENTO ACUMULADO DO QUANTY ===\n\n';
430
+ if (stats.most_used_tasks.length > 0) {
431
+ enhancedPrompt += 'OPERAÇÕES MAIS COMUNS:\n';
432
+ for (const task of stats.most_used_tasks) {
433
+ enhancedPrompt += `- ${task.task}: ${task.count} vezes\n`;
434
+ }
435
+ enhancedPrompt += '\n';
436
+ }
437
+ enhancedPrompt += `Total de aprendizados: ${stats.total_learnings}\n`;
438
+ enhancedPrompt += `Padrões identificados: ${stats.total_patterns}\n`;
439
+ enhancedPrompt += `Confiança média: ${(stats.average_confidence * 100).toFixed(0)}%\n\n`;
440
+ enhancedPrompt += 'Use este conhecimento acumulado para fornecer respostas mais precisas e eficientes.\n';
441
+ return enhancedPrompt;
442
+ }
443
+ }
444
+ // ================ EXPORT SINGLETON ================
445
+ let learningSystemInstance = null;
446
+ let contextBuilderInstance = null;
447
+ export function initLearningSystem(auth) {
448
+ learningSystemInstance = new QuantyLearningSystem(auth);
449
+ contextBuilderInstance = new ContextBuilder(learningSystemInstance);
450
+ }
451
+ export function getLearningSystem() {
452
+ if (!learningSystemInstance) {
453
+ throw new Error('Learning system not initialized. Call initLearningSystem first.');
454
+ }
455
+ return learningSystemInstance;
456
+ }
457
+ export function getContextBuilder() {
458
+ if (!contextBuilderInstance) {
459
+ throw new Error('Context builder not initialized. Call initLearningSystem first.');
460
+ }
461
+ return contextBuilderInstance;
462
+ }
@@ -0,0 +1,76 @@
1
+ import { AuthContext } from './auth.js';
2
+ /**
3
+ * Calcula similaridade combinada (ensemble)
4
+ */
5
+ export declare function calculateSimilarity(a: string, b: string): {
6
+ overall: number;
7
+ fuzzy: number;
8
+ keyword: number;
9
+ tfidf: number;
10
+ category: {
11
+ a: string;
12
+ b: string;
13
+ match: boolean;
14
+ };
15
+ };
16
+ export interface MatchResult {
17
+ id: string;
18
+ code: string;
19
+ description: string;
20
+ unit: string;
21
+ unitCost: number;
22
+ source: string;
23
+ sourceId: string;
24
+ sourceName: string;
25
+ similarity: number;
26
+ similarityDetails: {
27
+ fuzzy: number;
28
+ keyword: number;
29
+ tfidf: number;
30
+ };
31
+ }
32
+ /**
33
+ * Busca itens similares em outros orçamentos
34
+ */
35
+ export declare function findSimilarInBudgets(auth: AuthContext, description: string, excludeBudgetId?: string, limit?: number, minSimilarity?: number): Promise<MatchResult[]>;
36
+ /**
37
+ * Busca itens similares em bancos de composições
38
+ */
39
+ export declare function findSimilarInBanks(auth: AuthContext, description: string, bankIds?: string[], limit?: number, minSimilarity?: number): Promise<MatchResult[]>;
40
+ /**
41
+ * Busca unificada em orçamentos e bancos
42
+ */
43
+ export declare function findSimilarItems(auth: AuthContext, description: string, options?: {
44
+ searchBudgets?: boolean;
45
+ searchBanks?: boolean;
46
+ excludeBudgetId?: string;
47
+ bankIds?: string[];
48
+ limit?: number;
49
+ minSimilarity?: number;
50
+ }): Promise<{
51
+ budgetResults: MatchResult[];
52
+ bankResults: MatchResult[];
53
+ topMatches: MatchResult[];
54
+ }>;
55
+ /**
56
+ * Compara preços de itens similares
57
+ */
58
+ export declare function comparePrices(auth: AuthContext, description: string, currentPrice: number, options?: {
59
+ excludeBudgetId?: string;
60
+ limit?: number;
61
+ minSimilarity?: number;
62
+ }): Promise<{
63
+ currentPrice: number;
64
+ matches: Array<MatchResult & {
65
+ priceDiff: number;
66
+ priceDiffPercent: number;
67
+ }>;
68
+ statistics: {
69
+ minPrice: number;
70
+ maxPrice: number;
71
+ avgPrice: number;
72
+ medianPrice: number;
73
+ recommendation: string;
74
+ };
75
+ }>;
76
+ //# sourceMappingURL=matchingService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"matchingService.d.ts","sourceRoot":"","sources":["../../src/core/matchingService.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAwPxC;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG;IACvD,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC;CACtD,CAkCA;AAID,MAAM,WAAW,WAAW;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE;QACf,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,EAAE,MAAM,CAAC;KACjB,CAAC;CACL;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CACtC,IAAI,EAAE,WAAW,EACjB,WAAW,EAAE,MAAM,EACnB,eAAe,CAAC,EAAE,MAAM,EACxB,KAAK,GAAE,MAAW,EAClB,aAAa,GAAE,MAAW,GAC3B,OAAO,CAAC,WAAW,EAAE,CAAC,CAgDxB;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACpC,IAAI,EAAE,WAAW,EACjB,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE,MAAM,EAAE,EAClB,KAAK,GAAE,MAAW,EAClB,aAAa,GAAE,MAAW,GAC3B,OAAO,CAAC,WAAW,EAAE,CAAC,CAqExB;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAClC,IAAI,EAAE,WAAW,EACjB,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE;IACL,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;CACrB,GACP,OAAO,CAAC;IACP,aAAa,EAAE,WAAW,EAAE,CAAC;IAC7B,WAAW,EAAE,WAAW,EAAE,CAAC;IAC3B,UAAU,EAAE,WAAW,EAAE,CAAC;CAC7B,CAAC,CA0BD;AAED;;GAEG;AACH,wBAAsB,aAAa,CAC/B,IAAI,EAAE,WAAW,EACjB,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,EACpB,OAAO,GAAE;IACL,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;CACrB,GACP,OAAO,CAAC;IACP,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,KAAK,CAAC,WAAW,GAAG;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,gBAAgB,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC9E,UAAU,EAAE;QACR,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;QACjB,WAAW,EAAE,MAAM,CAAC;QACpB,cAAc,EAAE,MAAM,CAAC;KAC1B,CAAC;CACL,CAAC,CAqED"}