@sparkleideas/plugins 3.0.0-alpha.10

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 (80) hide show
  1. package/README.md +401 -0
  2. package/__tests__/collection-manager.test.ts +332 -0
  3. package/__tests__/dependency-graph.test.ts +434 -0
  4. package/__tests__/enhanced-plugin-registry.test.ts +488 -0
  5. package/__tests__/plugin-registry.test.ts +368 -0
  6. package/__tests__/ruvector-bridge.test.ts +2429 -0
  7. package/__tests__/ruvector-integration.test.ts +1602 -0
  8. package/__tests__/ruvector-migrations.test.ts +1099 -0
  9. package/__tests__/ruvector-quantization.test.ts +846 -0
  10. package/__tests__/ruvector-streaming.test.ts +1088 -0
  11. package/__tests__/sdk.test.ts +325 -0
  12. package/__tests__/security.test.ts +348 -0
  13. package/__tests__/utils/ruvector-test-utils.ts +860 -0
  14. package/examples/plugin-creator/index.ts +636 -0
  15. package/examples/plugin-creator/plugin-creator.test.ts +312 -0
  16. package/examples/ruvector/README.md +288 -0
  17. package/examples/ruvector/attention-patterns.ts +394 -0
  18. package/examples/ruvector/basic-usage.ts +288 -0
  19. package/examples/ruvector/docker-compose.yml +75 -0
  20. package/examples/ruvector/gnn-analysis.ts +501 -0
  21. package/examples/ruvector/hyperbolic-hierarchies.ts +557 -0
  22. package/examples/ruvector/init-db.sql +119 -0
  23. package/examples/ruvector/quantization.ts +680 -0
  24. package/examples/ruvector/self-learning.ts +447 -0
  25. package/examples/ruvector/semantic-search.ts +576 -0
  26. package/examples/ruvector/streaming-large-data.ts +507 -0
  27. package/examples/ruvector/transactions.ts +594 -0
  28. package/examples/ruvector-plugins/hook-pattern-library.ts +486 -0
  29. package/examples/ruvector-plugins/index.ts +79 -0
  30. package/examples/ruvector-plugins/intent-router.ts +354 -0
  31. package/examples/ruvector-plugins/mcp-tool-optimizer.ts +424 -0
  32. package/examples/ruvector-plugins/reasoning-bank.ts +657 -0
  33. package/examples/ruvector-plugins/ruvector-plugins.test.ts +518 -0
  34. package/examples/ruvector-plugins/semantic-code-search.ts +498 -0
  35. package/examples/ruvector-plugins/shared/index.ts +20 -0
  36. package/examples/ruvector-plugins/shared/vector-utils.ts +257 -0
  37. package/examples/ruvector-plugins/sona-learning.ts +445 -0
  38. package/package.json +97 -0
  39. package/src/collections/collection-manager.ts +661 -0
  40. package/src/collections/index.ts +56 -0
  41. package/src/collections/official/index.ts +1040 -0
  42. package/src/core/base-plugin.ts +416 -0
  43. package/src/core/plugin-interface.ts +215 -0
  44. package/src/hooks/index.ts +685 -0
  45. package/src/index.ts +378 -0
  46. package/src/integrations/agentic-flow.ts +743 -0
  47. package/src/integrations/index.ts +88 -0
  48. package/src/integrations/ruvector/ARCHITECTURE.md +1245 -0
  49. package/src/integrations/ruvector/attention-advanced.ts +1040 -0
  50. package/src/integrations/ruvector/attention-executor.ts +782 -0
  51. package/src/integrations/ruvector/attention-mechanisms.ts +757 -0
  52. package/src/integrations/ruvector/attention.ts +1063 -0
  53. package/src/integrations/ruvector/gnn.ts +3050 -0
  54. package/src/integrations/ruvector/hyperbolic.ts +1948 -0
  55. package/src/integrations/ruvector/index.ts +394 -0
  56. package/src/integrations/ruvector/migrations/001_create_extension.sql +135 -0
  57. package/src/integrations/ruvector/migrations/002_create_vector_tables.sql +259 -0
  58. package/src/integrations/ruvector/migrations/003_create_indices.sql +328 -0
  59. package/src/integrations/ruvector/migrations/004_create_functions.sql +598 -0
  60. package/src/integrations/ruvector/migrations/005_create_attention_functions.sql +654 -0
  61. package/src/integrations/ruvector/migrations/006_create_gnn_functions.sql +728 -0
  62. package/src/integrations/ruvector/migrations/007_create_hyperbolic_functions.sql +762 -0
  63. package/src/integrations/ruvector/migrations/index.ts +35 -0
  64. package/src/integrations/ruvector/migrations/migrations.ts +647 -0
  65. package/src/integrations/ruvector/quantization.ts +2036 -0
  66. package/src/integrations/ruvector/ruvector-bridge.ts +2000 -0
  67. package/src/integrations/ruvector/self-learning.ts +2376 -0
  68. package/src/integrations/ruvector/streaming.ts +1737 -0
  69. package/src/integrations/ruvector/types.ts +1945 -0
  70. package/src/providers/index.ts +643 -0
  71. package/src/registry/dependency-graph.ts +568 -0
  72. package/src/registry/enhanced-plugin-registry.ts +994 -0
  73. package/src/registry/plugin-registry.ts +604 -0
  74. package/src/sdk/index.ts +563 -0
  75. package/src/security/index.ts +594 -0
  76. package/src/types/index.ts +446 -0
  77. package/src/workers/index.ts +700 -0
  78. package/tmp.json +0 -0
  79. package/tsconfig.json +25 -0
  80. package/vitest.config.ts +23 -0
@@ -0,0 +1,447 @@
1
+ /**
2
+ * RuVector PostgreSQL Bridge - Self-Learning Example
3
+ *
4
+ * This example demonstrates:
5
+ * - Enabling the self-optimization learning loop
6
+ * - Monitoring query patterns and performance
7
+ * - Auto-tuning HNSW index parameters
8
+ * - Pattern recognition and anomaly detection
9
+ *
10
+ * Run with: npx ts-node examples/ruvector/self-learning.ts
11
+ *
12
+ * @module @sparkleideas/plugins/examples/ruvector/self-learning
13
+ */
14
+
15
+ import {
16
+ createRuVectorBridge,
17
+ type RuVectorBridge,
18
+ } from '../../src/integrations/ruvector/index.js';
19
+
20
+ import {
21
+ createSelfLearningSystem,
22
+ LearningLoop,
23
+ QueryOptimizer,
24
+ IndexTuner,
25
+ PatternRecognizer,
26
+ DEFAULT_LEARNING_CONFIG,
27
+ HIGH_ACCURACY_LEARNING_CONFIG,
28
+ type LearningConfig,
29
+ type QueryHistory,
30
+ type Pattern,
31
+ type WorkloadAnalysis,
32
+ } from '../../src/integrations/ruvector/self-learning.js';
33
+
34
+ // ============================================================================
35
+ // Configuration
36
+ // ============================================================================
37
+
38
+ const config = {
39
+ connection: {
40
+ host: process.env.POSTGRES_HOST || 'localhost',
41
+ port: parseInt(process.env.POSTGRES_PORT || '5432', 10),
42
+ database: process.env.POSTGRES_DB || 'vectors',
43
+ user: process.env.POSTGRES_USER || 'postgres',
44
+ password: process.env.POSTGRES_PASSWORD || 'postgres',
45
+ },
46
+ dimensions: 384,
47
+ learningEnabled: true,
48
+ };
49
+
50
+ // ============================================================================
51
+ // Simulated Query Workload
52
+ // ============================================================================
53
+
54
+ /**
55
+ * Simulated queries representing a realistic workload.
56
+ */
57
+ const workloadQueries = [
58
+ // Vector similarity searches (frequent)
59
+ "SELECT id, embedding <-> $1 as distance FROM documents ORDER BY distance LIMIT 10",
60
+ "SELECT id, embedding <=> $1 as distance FROM documents WHERE category = 'tech' ORDER BY distance LIMIT 5",
61
+ "SELECT id, metadata FROM documents WHERE embedding <-> $1 < 0.5 LIMIT 20",
62
+
63
+ // Analytical queries
64
+ "SELECT category, COUNT(*) FROM documents GROUP BY category",
65
+ "SELECT DATE(created_at), COUNT(*) FROM documents GROUP BY DATE(created_at)",
66
+
67
+ // CRUD operations
68
+ "INSERT INTO documents (id, embedding, metadata) VALUES ($1, $2, $3)",
69
+ "UPDATE documents SET metadata = $1 WHERE id = $2",
70
+ "DELETE FROM documents WHERE created_at < $1",
71
+
72
+ // Complex joins
73
+ "SELECT d.id, d.metadata, c.name FROM documents d JOIN categories c ON d.category_id = c.id WHERE d.embedding <-> $1 < 0.3",
74
+ ];
75
+
76
+ /**
77
+ * Generate realistic query history.
78
+ */
79
+ function generateQueryHistory(queries: string[], count: number): QueryHistory[] {
80
+ const history: QueryHistory[] = [];
81
+ const now = Date.now();
82
+
83
+ for (let i = 0; i < count; i++) {
84
+ const query = queries[Math.floor(Math.random() * queries.length)];
85
+ const isVectorSearch = query.includes('<->') || query.includes('<=>');
86
+
87
+ // Simulate realistic durations
88
+ let baseDuration = isVectorSearch ? 50 : 10;
89
+ if (query.includes('GROUP BY')) baseDuration = 100;
90
+ if (query.includes('JOIN')) baseDuration = 150;
91
+
92
+ // Add some variance
93
+ const duration = baseDuration * (0.5 + Math.random());
94
+
95
+ // Simulate periodic pattern (business hours)
96
+ const hour = Math.floor((i / count) * 24);
97
+ const isPeakHour = hour >= 9 && hour <= 17;
98
+ const timestamp = new Date(now - (count - i) * 60000 + (isPeakHour ? 0 : Math.random() * 300000));
99
+
100
+ history.push({
101
+ fingerprint: `qf_${Math.abs(hashCode(query)).toString(16)}`,
102
+ sql: query,
103
+ timestamp,
104
+ durationMs: duration,
105
+ rowCount: Math.floor(Math.random() * 100) + 1,
106
+ success: Math.random() > 0.02, // 2% error rate
107
+ sessionId: `session_${i % 10}`,
108
+ });
109
+ }
110
+
111
+ return history;
112
+ }
113
+
114
+ /**
115
+ * Simple hash function for query fingerprinting.
116
+ */
117
+ function hashCode(str: string): number {
118
+ let hash = 0;
119
+ for (let i = 0; i < str.length; i++) {
120
+ const char = str.charCodeAt(i);
121
+ hash = ((hash << 5) - hash) + char;
122
+ hash = hash & hash;
123
+ }
124
+ return hash;
125
+ }
126
+
127
+ /**
128
+ * Print workload analysis summary.
129
+ */
130
+ function printWorkloadAnalysis(analysis: WorkloadAnalysis): void {
131
+ console.log('\n Workload Analysis Summary');
132
+ console.log(' ' + '-'.repeat(50));
133
+ console.log(` Total queries analyzed: ${analysis.totalQueries}`);
134
+ console.log(` Analysis duration: ${analysis.durationMs.toFixed(2)}ms`);
135
+
136
+ console.log('\n Query type distribution:');
137
+ analysis.queryDistribution.forEach((count, type) => {
138
+ const pct = ((count / analysis.totalQueries) * 100).toFixed(1);
139
+ console.log(` ${type}: ${count} (${pct}%)`);
140
+ });
141
+
142
+ console.log('\n Workload characteristics:');
143
+ console.log(` Read/Write ratio: ${analysis.characteristics.readWriteRatio.toFixed(2)}`);
144
+ console.log(` Vector search %: ${analysis.characteristics.vectorSearchPercentage.toFixed(1)}%`);
145
+ console.log(` Avg complexity: ${analysis.characteristics.avgComplexity.toFixed(3)}`);
146
+ console.log(` Type: ${analysis.characteristics.isOLTP ? 'OLTP' : analysis.characteristics.isOLAP ? 'OLAP' : 'Hybrid'}`);
147
+
148
+ console.log('\n Top query patterns:');
149
+ analysis.topPatterns.slice(0, 5).forEach((pattern, i) => {
150
+ console.log(` ${i + 1}. Frequency: ${pattern.frequency}, Avg: ${pattern.avgDurationMs.toFixed(2)}ms`);
151
+ console.log(` ${pattern.example.slice(0, 60)}...`);
152
+ });
153
+
154
+ console.log('\n Hot tables:');
155
+ analysis.hotTables.slice(0, 3).forEach(table => {
156
+ console.log(` ${table.tableName}: reads=${table.reads}, writes=${table.writes}, vector=${table.vectorSearches}`);
157
+ });
158
+
159
+ console.log('\n Recommendations:');
160
+ analysis.recommendations.forEach(rec => {
161
+ console.log(` [P${rec.priority}] ${rec.description}`);
162
+ console.log(` Impact: ${rec.estimatedImpact}`);
163
+ });
164
+ }
165
+
166
+ // ============================================================================
167
+ // Main Example
168
+ // ============================================================================
169
+
170
+ async function main(): Promise<void> {
171
+ console.log('RuVector PostgreSQL Bridge - Self-Learning Example');
172
+ console.log('====================================================\n');
173
+
174
+ const bridge: RuVectorBridge = createRuVectorBridge({
175
+ connectionString: `postgresql://${config.connection.user}:${config.connection.password}@${config.connection.host}:${config.connection.port}/${config.connection.database}`,
176
+ });
177
+
178
+ // Create self-learning system with custom configuration
179
+ const learningConfig: Partial<LearningConfig> = {
180
+ enableMicroLearning: true,
181
+ microLearningThresholdMs: 0.1,
182
+ enableBackgroundLearning: true,
183
+ backgroundLearningIntervalMs: 5000, // 5 seconds for demo
184
+ enableEWC: true,
185
+ ewcLambda: 0.5,
186
+ maxPatterns: 1000,
187
+ patternExpiryMs: 3600000, // 1 hour
188
+ };
189
+
190
+ const { learningLoop, queryOptimizer, indexTuner, patternRecognizer } =
191
+ createSelfLearningSystem(learningConfig);
192
+
193
+ try {
194
+ await bridge.connect();
195
+ console.log('Connected to PostgreSQL');
196
+
197
+ // ========================================================================
198
+ // 1. Enable Learning Loop
199
+ // ========================================================================
200
+ console.log('\n1. Starting Self-Learning Loop');
201
+ console.log(' ' + '-'.repeat(50));
202
+
203
+ learningLoop.start();
204
+ console.log(' Learning loop started');
205
+ console.log(` Configuration:`);
206
+ console.log(` - Micro-learning: ${learningConfig.enableMicroLearning ? 'enabled' : 'disabled'}`);
207
+ console.log(` - Background learning interval: ${learningConfig.backgroundLearningIntervalMs}ms`);
208
+ console.log(` - EWC protection: ${learningConfig.enableEWC ? 'enabled' : 'disabled'}`);
209
+ console.log(` - Max patterns: ${learningConfig.maxPatterns}`);
210
+
211
+ // ========================================================================
212
+ // 2. Simulate Query Workload
213
+ // ========================================================================
214
+ console.log('\n2. Simulating Query Workload');
215
+ console.log(' ' + '-'.repeat(50));
216
+
217
+ const queryHistory = generateQueryHistory(workloadQueries, 500);
218
+ console.log(` Generated ${queryHistory.length} simulated queries`);
219
+
220
+ // Feed queries to the learning system
221
+ console.log(' Processing queries through micro-learning...');
222
+ const startProcess = performance.now();
223
+
224
+ for (const history of queryHistory) {
225
+ // Micro-learning: process each query
226
+ learningLoop.microLearn(history.sql, history.durationMs, history.rowCount);
227
+
228
+ // Record in index tuner
229
+ indexTuner.recordQuery(history);
230
+ }
231
+
232
+ const processTime = performance.now() - startProcess;
233
+ console.log(` Processed ${queryHistory.length} queries in ${processTime.toFixed(2)}ms`);
234
+ console.log(` Throughput: ${(queryHistory.length / (processTime / 1000)).toFixed(0)} queries/second`);
235
+
236
+ // ========================================================================
237
+ // 3. Analyze Workload Patterns
238
+ // ========================================================================
239
+ console.log('\n3. Analyzing Workload Patterns');
240
+ console.log(' ' + '-'.repeat(50));
241
+
242
+ const workloadAnalysis = indexTuner.analyzeWorkload();
243
+ printWorkloadAnalysis(workloadAnalysis);
244
+
245
+ // ========================================================================
246
+ // 4. Query Optimization Suggestions
247
+ // ========================================================================
248
+ console.log('\n4. Query Optimization Suggestions');
249
+ console.log(' ' + '-'.repeat(50));
250
+
251
+ // Analyze a slow query
252
+ const slowQuery = "SELECT * FROM documents WHERE embedding <-> $1 < 0.5";
253
+ console.log(`\n Analyzing: "${slowQuery}"`);
254
+
255
+ const analysis = queryOptimizer.analyzeQuery(slowQuery);
256
+ console.log(`\n Analysis results:`);
257
+ console.log(` Query type: ${analysis.queryType}`);
258
+ console.log(` Complexity: ${(analysis.complexity * 100).toFixed(1)}%`);
259
+ console.log(` Parse time: ${analysis.parseTimeMs.toFixed(3)}ms`);
260
+
261
+ console.log('\n Vector operations:');
262
+ analysis.vectorOperations.forEach(op => {
263
+ console.log(` - ${op.type} on ${op.table}.${op.column} (metric: ${op.metric})`);
264
+ });
265
+
266
+ console.log('\n Bottlenecks:');
267
+ analysis.bottlenecks.forEach(b => {
268
+ console.log(` - [${b.type}] ${b.description} (severity: ${b.severity})`);
269
+ console.log(` Suggestion: ${b.suggestion}`);
270
+ });
271
+
272
+ const optimizations = queryOptimizer.suggestOptimizations(analysis);
273
+ console.log('\n Suggested optimizations:');
274
+ optimizations.forEach(opt => {
275
+ console.log(` - [${opt.type}] ${opt.description}`);
276
+ console.log(` Expected improvement: ${opt.expectedImprovement}%`);
277
+ console.log(` Confidence: ${(opt.confidence * 100).toFixed(0)}%, Risk: ${opt.risk}`);
278
+ });
279
+
280
+ // ========================================================================
281
+ // 5. Auto-Tune HNSW Parameters
282
+ // ========================================================================
283
+ console.log('\n5. Auto-Tuning HNSW Index Parameters');
284
+ console.log(' ' + '-'.repeat(50));
285
+
286
+ const hnswParams = indexTuner.tuneHNSW('documents');
287
+ console.log(' Recommended HNSW parameters for "documents" table:');
288
+ console.log(` M: ${hnswParams.m}`);
289
+ console.log(` ef_construction: ${hnswParams.efConstruction}`);
290
+ console.log(` ef_search: ${hnswParams.efSearch}`);
291
+ console.log(` Optimized for: ${hnswParams.optimizedFor}`);
292
+ console.log(` Confidence: ${(hnswParams.confidence * 100).toFixed(1)}%`);
293
+ console.log(` Estimated recall: ${(hnswParams.estimatedRecall * 100).toFixed(1)}%`);
294
+ console.log(` Estimated QPS: ${hnswParams.estimatedQps}`);
295
+
296
+ // Get index suggestions
297
+ const indexSuggestions = indexTuner.suggestIndexes();
298
+ console.log('\n Index suggestions:');
299
+ indexSuggestions.slice(0, 3).forEach(suggestion => {
300
+ console.log(` - ${suggestion.tableName}.${suggestion.columnName}`);
301
+ console.log(` Type: ${suggestion.indexType}, Metric: ${suggestion.metric}`);
302
+ console.log(` Confidence: ${(suggestion.confidence * 100).toFixed(1)}%`);
303
+ console.log(` SQL: ${suggestion.createSql}`);
304
+ });
305
+
306
+ // ========================================================================
307
+ // 6. Pattern Recognition
308
+ // ========================================================================
309
+ console.log('\n6. Pattern Recognition');
310
+ console.log(' ' + '-'.repeat(50));
311
+
312
+ // Learn patterns from history
313
+ patternRecognizer.learnFromHistory(queryHistory);
314
+
315
+ const patterns = patternRecognizer.detectPatterns();
316
+ console.log(` Detected ${patterns.length} patterns`);
317
+
318
+ console.log('\n Top patterns by occurrence:');
319
+ patterns.slice(0, 5).forEach((pattern, i) => {
320
+ console.log(` ${i + 1}. ${pattern.type} (${pattern.occurrences} occurrences)`);
321
+ console.log(` Confidence: ${(pattern.confidence * 100).toFixed(1)}%`);
322
+ if (pattern.temporal) {
323
+ console.log(` Periodic: ${pattern.temporal.isPeriodic}`);
324
+ console.log(` Peak hours: ${pattern.temporal.peakHours.join(', ')}`);
325
+ }
326
+ console.log(` Performance trend: ${pattern.performance.responseTrend}`);
327
+ });
328
+
329
+ // ========================================================================
330
+ // 7. Anomaly Detection
331
+ // ========================================================================
332
+ console.log('\n7. Anomaly Detection');
333
+ console.log(' ' + '-'.repeat(50));
334
+
335
+ // Simulate some anomalous queries
336
+ const anomalousQueries = [
337
+ "SELECT * FROM documents", // No limit - potential full scan
338
+ "SELECT * FROM documents d1, documents d2", // Cartesian product
339
+ ];
340
+
341
+ const anomalies = patternRecognizer.detectAnomalies(anomalousQueries);
342
+
343
+ if (anomalies.length > 0) {
344
+ console.log(` Detected ${anomalies.length} anomalies:`);
345
+ anomalies.forEach((anomaly, i) => {
346
+ console.log(`\n ${i + 1}. ${anomaly.type}`);
347
+ console.log(` Query: ${anomaly.query.slice(0, 50)}...`);
348
+ console.log(` Severity: ${anomaly.severity}/10`);
349
+ console.log(` Description: ${anomaly.description}`);
350
+ console.log(` Possible causes:`);
351
+ anomaly.possibleCauses.forEach(cause => console.log(` - ${cause}`));
352
+ console.log(` Recommendations:`);
353
+ anomaly.recommendations.forEach(rec => console.log(` - ${rec}`));
354
+ });
355
+ } else {
356
+ console.log(' No anomalies detected in the analyzed queries');
357
+ }
358
+
359
+ // ========================================================================
360
+ // 8. Learning Statistics
361
+ // ========================================================================
362
+ console.log('\n8. Learning Statistics');
363
+ console.log(' ' + '-'.repeat(50));
364
+
365
+ const stats = learningLoop.getStats();
366
+ console.log(' Current learning state:');
367
+ console.log(` Total patterns: ${stats.totalPatterns}`);
368
+ console.log(` Active patterns: ${stats.activePatterns}`);
369
+ console.log(` Micro-learning events: ${stats.microLearningEvents}`);
370
+ console.log(` Background learning cycles: ${stats.backgroundLearningCycles}`);
371
+ console.log(` EWC consolidations: ${stats.ewcConsolidations}`);
372
+ console.log(` Avg learning time: ${stats.avgLearningTimeMs.toFixed(3)}ms`);
373
+ console.log(` Memory usage: ${(stats.memoryUsageBytes / 1024).toFixed(2)} KB`);
374
+ console.log(` Last learning: ${stats.lastLearningTimestamp.toISOString()}`);
375
+
376
+ // EWC state
377
+ const ewcState = learningLoop.getEWCState();
378
+ console.log('\n EWC++ Protection State:');
379
+ console.log(` Protected patterns: ${ewcState.protectedPatterns.size}`);
380
+ console.log(` Consolidation count: ${ewcState.consolidationCount}`);
381
+ console.log(` Fisher matrix entries: ${ewcState.fisherDiagonal.size}`);
382
+
383
+ // ========================================================================
384
+ // 9. Query Statistics
385
+ // ========================================================================
386
+ console.log('\n9. Query Statistics');
387
+ console.log(' ' + '-'.repeat(50));
388
+
389
+ const queryStats = queryOptimizer.getQueryStats() as Array<{
390
+ fingerprint: string;
391
+ sql: string;
392
+ executionCount: number;
393
+ avgDurationMs: number;
394
+ p95DurationMs: number;
395
+ }>;
396
+
397
+ if (Array.isArray(queryStats) && queryStats.length > 0) {
398
+ console.log(` Tracked ${queryStats.length} unique query patterns`);
399
+
400
+ // Sort by execution count
401
+ const topQueries = queryStats
402
+ .sort((a, b) => b.executionCount - a.executionCount)
403
+ .slice(0, 5);
404
+
405
+ console.log('\n Top queries by frequency:');
406
+ topQueries.forEach((stat, i) => {
407
+ console.log(` ${i + 1}. ${stat.sql.slice(0, 50)}...`);
408
+ console.log(` Executions: ${stat.executionCount}`);
409
+ console.log(` Avg duration: ${stat.avgDurationMs.toFixed(2)}ms`);
410
+ console.log(` P95 duration: ${stat.p95DurationMs.toFixed(2)}ms`);
411
+ });
412
+ }
413
+
414
+ // ========================================================================
415
+ // 10. Stop Learning Loop
416
+ // ========================================================================
417
+ console.log('\n10. Stopping Learning Loop');
418
+ console.log(' ' + '-'.repeat(50));
419
+
420
+ learningLoop.stop();
421
+ console.log(' Learning loop stopped');
422
+ console.log(` Final stats:`);
423
+ console.log(` - Total patterns learned: ${learningLoop.getStats().totalPatterns}`);
424
+ console.log(` - Total micro-learning events: ${learningLoop.getStats().microLearningEvents}`);
425
+
426
+ // ========================================================================
427
+ // Done
428
+ // ========================================================================
429
+ console.log('\n' + '='.repeat(55));
430
+ console.log('Self-learning example completed!');
431
+ console.log('='.repeat(55));
432
+
433
+ } catch (error) {
434
+ console.error('Error:', error);
435
+ throw error;
436
+ } finally {
437
+ // Ensure learning loop is stopped
438
+ if (learningLoop.isActive()) {
439
+ learningLoop.stop();
440
+ }
441
+
442
+ await bridge.disconnect();
443
+ console.log('\nDisconnected from PostgreSQL.');
444
+ }
445
+ }
446
+
447
+ main().catch(console.error);