@gotza02/sequential-thinking 10000.1.0 → 10000.1.2
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.
- package/dist/dashboard/server.d.ts +0 -34
- package/dist/dashboard/server.js +50 -269
- package/dist/tools/sports/core/alert-manager.d.ts +1 -50
- package/dist/tools/sports/core/alert-manager.js +62 -123
- package/dist/tools/sports/core/data-quality.d.ts +0 -44
- package/dist/tools/sports/core/data-quality.js +49 -266
- package/dist/tools/sports/core/historical-analyzer.d.ts +0 -54
- package/dist/tools/sports/core/historical-analyzer.js +56 -256
- package/dist/tools/sports/core/index.d.ts +1 -1
- package/dist/tools/sports/core/index.js +1 -1
- package/dist/tools/sports/core/ml-prediction.d.ts +7 -65
- package/dist/tools/sports/core/ml-prediction.js +43 -185
- package/dist/tools/sports/core/realtime-manager.d.ts +1 -52
- package/dist/tools/sports/core/realtime-manager.js +18 -127
- package/package.json +1 -1
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ALERT MANAGER
|
|
3
|
-
* Real-time alert system with rule engine
|
|
3
|
+
* Real-time alert system with rule engine
|
|
4
4
|
*/
|
|
5
5
|
import { EventEmitter } from 'events';
|
|
6
|
-
import { logger } from '../../../utils.js';
|
|
7
6
|
import { ALERT_CONFIG } from './constants.js';
|
|
7
|
+
// Simple logger fallback
|
|
8
|
+
const logger = {
|
|
9
|
+
info: (...args) => console.error('[INFO]', ...args),
|
|
10
|
+
warn: (...args) => console.warn('[WARN]', ...args),
|
|
11
|
+
error: (...args) => console.error('[ERROR]', ...args),
|
|
12
|
+
debug: (...args) => { }
|
|
13
|
+
};
|
|
8
14
|
export class AlertManager extends EventEmitter {
|
|
9
15
|
rules = new Map();
|
|
10
16
|
checkInterval;
|
|
@@ -14,9 +20,6 @@ export class AlertManager extends EventEmitter {
|
|
|
14
20
|
super();
|
|
15
21
|
this.setMaxListeners(100);
|
|
16
22
|
}
|
|
17
|
-
/**
|
|
18
|
-
* Start the alert manager
|
|
19
|
-
*/
|
|
20
23
|
start() {
|
|
21
24
|
if (this.checkInterval)
|
|
22
25
|
return;
|
|
@@ -25,9 +28,6 @@ export class AlertManager extends EventEmitter {
|
|
|
25
28
|
}, ALERT_CONFIG.CHECK_INTERVAL);
|
|
26
29
|
logger.info('[AlertManager] Started');
|
|
27
30
|
}
|
|
28
|
-
/**
|
|
29
|
-
* Stop the alert manager
|
|
30
|
-
*/
|
|
31
31
|
stop() {
|
|
32
32
|
if (this.checkInterval) {
|
|
33
33
|
clearInterval(this.checkInterval);
|
|
@@ -35,9 +35,6 @@ export class AlertManager extends EventEmitter {
|
|
|
35
35
|
}
|
|
36
36
|
logger.info('[AlertManager] Stopped');
|
|
37
37
|
}
|
|
38
|
-
/**
|
|
39
|
-
* Add a new alert rule
|
|
40
|
-
*/
|
|
41
38
|
addRule(rule) {
|
|
42
39
|
const newRule = {
|
|
43
40
|
...rule,
|
|
@@ -50,9 +47,6 @@ export class AlertManager extends EventEmitter {
|
|
|
50
47
|
this.emit('rule_added', newRule);
|
|
51
48
|
return newRule;
|
|
52
49
|
}
|
|
53
|
-
/**
|
|
54
|
-
* Remove an alert rule
|
|
55
|
-
*/
|
|
56
50
|
removeRule(ruleId) {
|
|
57
51
|
const removed = this.rules.delete(ruleId);
|
|
58
52
|
if (removed) {
|
|
@@ -61,21 +55,12 @@ export class AlertManager extends EventEmitter {
|
|
|
61
55
|
}
|
|
62
56
|
return removed;
|
|
63
57
|
}
|
|
64
|
-
/**
|
|
65
|
-
* Get all rules
|
|
66
|
-
*/
|
|
67
58
|
getRules() {
|
|
68
59
|
return Array.from(this.rules.values());
|
|
69
60
|
}
|
|
70
|
-
/**
|
|
71
|
-
* Get a specific rule
|
|
72
|
-
*/
|
|
73
61
|
getRule(ruleId) {
|
|
74
62
|
return this.rules.get(ruleId);
|
|
75
63
|
}
|
|
76
|
-
/**
|
|
77
|
-
* Enable/disable a rule
|
|
78
|
-
*/
|
|
79
64
|
toggleRule(ruleId, enabled) {
|
|
80
65
|
const rule = this.rules.get(ruleId);
|
|
81
66
|
if (rule) {
|
|
@@ -85,29 +70,19 @@ export class AlertManager extends EventEmitter {
|
|
|
85
70
|
}
|
|
86
71
|
return false;
|
|
87
72
|
}
|
|
88
|
-
/**
|
|
89
|
-
* Process a live event and check for alerts
|
|
90
|
-
*/
|
|
91
73
|
processEvent(event) {
|
|
92
74
|
for (const rule of this.rules.values()) {
|
|
93
75
|
if (!rule.enabled)
|
|
94
76
|
continue;
|
|
95
|
-
|
|
96
|
-
if (rule.lastTriggered && Date.now() - rule.lastTriggered < rule.cooldown) {
|
|
77
|
+
if (rule.lastTriggered && Date.now() - rule.lastTriggered < rule.cooldown)
|
|
97
78
|
continue;
|
|
98
|
-
|
|
99
|
-
// Check rate limit
|
|
100
|
-
if (rule.triggerCount && rule.triggerCount >= ALERT_CONFIG.MAX_ALERTS_PER_HOUR) {
|
|
79
|
+
if (rule.triggerCount && rule.triggerCount >= ALERT_CONFIG.MAX_ALERTS_PER_HOUR)
|
|
101
80
|
continue;
|
|
102
|
-
}
|
|
103
81
|
if (this.evaluateCondition(rule.condition, event)) {
|
|
104
82
|
this.triggerAlert(rule, event);
|
|
105
83
|
}
|
|
106
84
|
}
|
|
107
85
|
}
|
|
108
|
-
/**
|
|
109
|
-
* Evaluate an alert condition against an event
|
|
110
|
-
*/
|
|
111
86
|
evaluateCondition(condition, event) {
|
|
112
87
|
switch (condition.type) {
|
|
113
88
|
case 'odds_drop':
|
|
@@ -127,13 +102,10 @@ export class AlertManager extends EventEmitter {
|
|
|
127
102
|
return false;
|
|
128
103
|
const oddsEvent = event;
|
|
129
104
|
const { newOdds, change } = oddsEvent.data;
|
|
130
|
-
// Check match filter
|
|
131
105
|
if (condition.matchId && event.matchId !== condition.matchId)
|
|
132
106
|
return false;
|
|
133
|
-
// Check threshold
|
|
134
107
|
if (newOdds > condition.threshold)
|
|
135
108
|
return false;
|
|
136
|
-
// Check percentage drop
|
|
137
109
|
return Math.abs(change) >= condition.percentage;
|
|
138
110
|
}
|
|
139
111
|
evaluateOddsValue(condition, event) {
|
|
@@ -141,21 +113,15 @@ export class AlertManager extends EventEmitter {
|
|
|
141
113
|
return false;
|
|
142
114
|
const oddsEvent = event;
|
|
143
115
|
const { newOdds } = oddsEvent.data;
|
|
144
|
-
// Check match filter
|
|
145
116
|
if (condition.matchId && event.matchId !== condition.matchId)
|
|
146
117
|
return false;
|
|
147
|
-
// Check max odds
|
|
148
118
|
if (condition.maxOdds && newOdds > condition.maxOdds)
|
|
149
119
|
return false;
|
|
150
|
-
// Calculate value (would need probability data)
|
|
151
|
-
// For now, simplified check
|
|
152
120
|
return true;
|
|
153
121
|
}
|
|
154
122
|
evaluateEventCondition(condition, event) {
|
|
155
|
-
// Check match filter
|
|
156
123
|
if (condition.matchId && event.matchId !== condition.matchId)
|
|
157
124
|
return false;
|
|
158
|
-
// Check event type
|
|
159
125
|
return condition.eventTypes.includes(event.type);
|
|
160
126
|
}
|
|
161
127
|
evaluateCompositeCondition(condition, event) {
|
|
@@ -164,19 +130,14 @@ export class AlertManager extends EventEmitter {
|
|
|
164
130
|
? results.every(r => r)
|
|
165
131
|
: results.some(r => r);
|
|
166
132
|
}
|
|
167
|
-
/**
|
|
168
|
-
* Trigger an alert
|
|
169
|
-
*/
|
|
170
133
|
async triggerAlert(rule, event) {
|
|
171
134
|
rule.lastTriggered = Date.now();
|
|
172
135
|
rule.triggerCount = (rule.triggerCount || 0) + 1;
|
|
173
136
|
const message = this.createAlertMessage(rule, event);
|
|
174
|
-
// Store in history
|
|
175
137
|
this.alertHistory.push(message);
|
|
176
138
|
if (this.alertHistory.length > this.maxHistorySize) {
|
|
177
139
|
this.alertHistory.shift();
|
|
178
140
|
}
|
|
179
|
-
// Send notifications
|
|
180
141
|
for (const channel of rule.channels) {
|
|
181
142
|
try {
|
|
182
143
|
await this.sendNotification(channel, message);
|
|
@@ -185,13 +146,9 @@ export class AlertManager extends EventEmitter {
|
|
|
185
146
|
logger.error(`[AlertManager] Failed to send notification: ${error}`);
|
|
186
147
|
}
|
|
187
148
|
}
|
|
188
|
-
// Emit event
|
|
189
149
|
this.emit('alert', message);
|
|
190
150
|
logger.info(`[AlertManager] Alert triggered: ${rule.name} (${rule.id})`);
|
|
191
151
|
}
|
|
192
|
-
/**
|
|
193
|
-
* Create an alert message
|
|
194
|
-
*/
|
|
195
152
|
createAlertMessage(rule, event) {
|
|
196
153
|
const severity = this.determineSeverity(rule.type, event);
|
|
197
154
|
return {
|
|
@@ -201,10 +158,7 @@ export class AlertManager extends EventEmitter {
|
|
|
201
158
|
severity,
|
|
202
159
|
title: this.formatAlertTitle(rule, event),
|
|
203
160
|
body: this.formatAlertBody(rule, event),
|
|
204
|
-
data: {
|
|
205
|
-
event,
|
|
206
|
-
rule,
|
|
207
|
-
},
|
|
161
|
+
data: { event, rule },
|
|
208
162
|
timestamp: Date.now(),
|
|
209
163
|
};
|
|
210
164
|
}
|
|
@@ -223,15 +177,15 @@ export class AlertManager extends EventEmitter {
|
|
|
223
177
|
formatAlertTitle(rule, event) {
|
|
224
178
|
switch (rule.type) {
|
|
225
179
|
case 'odds_drop':
|
|
226
|
-
return
|
|
180
|
+
return `Odds Drop Alert: ${event.matchId}`;
|
|
227
181
|
case 'odds_value':
|
|
228
|
-
return
|
|
182
|
+
return `Value Bet Alert: ${event.matchId}`;
|
|
229
183
|
case 'goal':
|
|
230
|
-
return
|
|
184
|
+
return `GOAL! ${event.matchId}`;
|
|
231
185
|
case 'red_card':
|
|
232
|
-
return
|
|
186
|
+
return `RED CARD! ${event.matchId}`;
|
|
233
187
|
default:
|
|
234
|
-
return
|
|
188
|
+
return rule.name;
|
|
235
189
|
}
|
|
236
190
|
}
|
|
237
191
|
formatAlertBody(rule, event) {
|
|
@@ -240,9 +194,8 @@ export class AlertManager extends EventEmitter {
|
|
|
240
194
|
lines.push(`Type: ${rule.type}`);
|
|
241
195
|
lines.push(`Match: ${event.matchId}`);
|
|
242
196
|
lines.push(`Time: ${new Date(event.timestamp).toLocaleString()}`);
|
|
243
|
-
if (event.minute)
|
|
197
|
+
if (event.minute)
|
|
244
198
|
lines.push(`Minute: ${event.minute}'`);
|
|
245
|
-
}
|
|
246
199
|
if (event.data) {
|
|
247
200
|
lines.push('');
|
|
248
201
|
lines.push('Details:');
|
|
@@ -250,9 +203,6 @@ export class AlertManager extends EventEmitter {
|
|
|
250
203
|
}
|
|
251
204
|
return lines.join('\n');
|
|
252
205
|
}
|
|
253
|
-
/**
|
|
254
|
-
* Send notification to a channel
|
|
255
|
-
*/
|
|
256
206
|
async sendNotification(channel, message) {
|
|
257
207
|
switch (channel.type) {
|
|
258
208
|
case 'webhook':
|
|
@@ -265,52 +215,57 @@ export class AlertManager extends EventEmitter {
|
|
|
265
215
|
await this.sendDiscord(channel.config.webhook, message);
|
|
266
216
|
break;
|
|
267
217
|
case 'email':
|
|
268
|
-
|
|
218
|
+
logger.info(`[AlertManager] Would send email to ${channel.config.to}: ${message.title}`);
|
|
269
219
|
break;
|
|
270
220
|
case 'console':
|
|
271
|
-
console.
|
|
272
|
-
console.
|
|
273
|
-
console.
|
|
274
|
-
console.
|
|
275
|
-
console.
|
|
221
|
+
console.error(`\n${'='.repeat(50)}`);
|
|
222
|
+
console.error(`ALERT: ${message.title}`);
|
|
223
|
+
console.error(`${'='.repeat(50)}`);
|
|
224
|
+
console.error(message.body);
|
|
225
|
+
console.error(`${'='.repeat(50)}\n`);
|
|
276
226
|
break;
|
|
277
227
|
}
|
|
278
228
|
}
|
|
279
229
|
async sendWebhook(url, message) {
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
230
|
+
try {
|
|
231
|
+
const response = await fetch(url, {
|
|
232
|
+
method: 'POST',
|
|
233
|
+
headers: { 'Content-Type': 'application/json' },
|
|
234
|
+
body: JSON.stringify(message),
|
|
235
|
+
});
|
|
236
|
+
if (!response.ok)
|
|
237
|
+
throw new Error(`Webhook failed: ${response.status}`);
|
|
238
|
+
}
|
|
239
|
+
catch (error) {
|
|
240
|
+
logger.error('[AlertManager] Webhook failed:', error);
|
|
287
241
|
}
|
|
288
242
|
}
|
|
289
243
|
async sendSlack(webhook, message) {
|
|
290
|
-
const emoji = message.severity === 'critical' ? '
|
|
291
|
-
message.severity === 'warning' ? '⚠️' : 'ℹ️';
|
|
244
|
+
const emoji = message.severity === 'critical' ? '' : message.severity === 'warning' ? '⚠️' : 'ℹ️';
|
|
292
245
|
const payload = {
|
|
293
246
|
text: `${emoji} *${message.title}*`,
|
|
294
247
|
attachments: [{
|
|
295
|
-
color: message.severity === 'critical' ? 'danger' :
|
|
296
|
-
message.severity === 'warning' ? 'warning' : 'good',
|
|
248
|
+
color: message.severity === 'critical' ? 'danger' : message.severity === 'warning' ? 'warning' : 'good',
|
|
297
249
|
text: message.body,
|
|
298
250
|
footer: 'Football Alert System',
|
|
299
251
|
ts: Math.floor(message.timestamp / 1000),
|
|
300
252
|
}],
|
|
301
253
|
};
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
254
|
+
try {
|
|
255
|
+
const response = await fetch(webhook, {
|
|
256
|
+
method: 'POST',
|
|
257
|
+
headers: { 'Content-Type': 'application/json' },
|
|
258
|
+
body: JSON.stringify(payload),
|
|
259
|
+
});
|
|
260
|
+
if (!response.ok)
|
|
261
|
+
throw new Error(`Slack webhook failed: ${response.status}`);
|
|
262
|
+
}
|
|
263
|
+
catch (error) {
|
|
264
|
+
logger.error('[AlertManager] Slack webhook failed:', error);
|
|
309
265
|
}
|
|
310
266
|
}
|
|
311
267
|
async sendDiscord(webhook, message) {
|
|
312
|
-
const color = message.severity === 'critical' ? 0xff0000 :
|
|
313
|
-
message.severity === 'warning' ? 0xffa500 : 0x00ff00;
|
|
268
|
+
const color = message.severity === 'critical' ? 0xff0000 : message.severity === 'warning' ? 0xffa500 : 0x00ff00;
|
|
314
269
|
const payload = {
|
|
315
270
|
embeds: [{
|
|
316
271
|
title: message.title,
|
|
@@ -319,42 +274,29 @@ export class AlertManager extends EventEmitter {
|
|
|
319
274
|
timestamp: new Date(message.timestamp).toISOString(),
|
|
320
275
|
}],
|
|
321
276
|
};
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
277
|
+
try {
|
|
278
|
+
const response = await fetch(webhook, {
|
|
279
|
+
method: 'POST',
|
|
280
|
+
headers: { 'Content-Type': 'application/json' },
|
|
281
|
+
body: JSON.stringify(payload),
|
|
282
|
+
});
|
|
283
|
+
if (!response.ok)
|
|
284
|
+
throw new Error(`Discord webhook failed: ${response.status}`);
|
|
285
|
+
}
|
|
286
|
+
catch (error) {
|
|
287
|
+
logger.error('[AlertManager] Discord webhook failed:', error);
|
|
329
288
|
}
|
|
330
289
|
}
|
|
331
|
-
async sendEmail(config, message) {
|
|
332
|
-
// Would integrate with email service like SendGrid, AWS SES, etc.
|
|
333
|
-
logger.info(`[AlertManager] Would send email to ${config.to}: ${message.title}`);
|
|
334
|
-
}
|
|
335
|
-
/**
|
|
336
|
-
* Check scheduled alerts (for time-based alerts)
|
|
337
|
-
*/
|
|
338
290
|
checkScheduledAlerts() {
|
|
339
|
-
//
|
|
340
|
-
// e.g., check for upcoming matches, etc.
|
|
291
|
+
// Time-based alerts
|
|
341
292
|
}
|
|
342
|
-
/**
|
|
343
|
-
* Get alert history
|
|
344
|
-
*/
|
|
345
293
|
getAlertHistory(limit) {
|
|
346
294
|
const history = [...this.alertHistory].reverse();
|
|
347
295
|
return limit ? history.slice(0, limit) : history;
|
|
348
296
|
}
|
|
349
|
-
/**
|
|
350
|
-
* Clear alert history
|
|
351
|
-
*/
|
|
352
297
|
clearHistory() {
|
|
353
298
|
this.alertHistory = [];
|
|
354
299
|
}
|
|
355
|
-
/**
|
|
356
|
-
* Get statistics
|
|
357
|
-
*/
|
|
358
300
|
getStats() {
|
|
359
301
|
const rules = Array.from(this.rules.values());
|
|
360
302
|
return {
|
|
@@ -364,17 +306,14 @@ export class AlertManager extends EventEmitter {
|
|
|
364
306
|
};
|
|
365
307
|
}
|
|
366
308
|
}
|
|
367
|
-
// Singleton instance
|
|
368
309
|
let globalAlertManager = null;
|
|
369
310
|
export function getAlertManager() {
|
|
370
|
-
if (!globalAlertManager)
|
|
311
|
+
if (!globalAlertManager)
|
|
371
312
|
globalAlertManager = new AlertManager();
|
|
372
|
-
}
|
|
373
313
|
return globalAlertManager;
|
|
374
314
|
}
|
|
375
315
|
export function resetAlertManager() {
|
|
376
|
-
if (globalAlertManager)
|
|
316
|
+
if (globalAlertManager)
|
|
377
317
|
globalAlertManager.stop();
|
|
378
|
-
}
|
|
379
318
|
globalAlertManager = null;
|
|
380
319
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* DATA QUALITY VALIDATOR
|
|
3
|
-
* Validates and scores data quality for football matches
|
|
4
3
|
*/
|
|
5
4
|
import type { Match, Team, MatchOdds } from './types.js';
|
|
6
5
|
export interface DataQualityReport {
|
|
@@ -21,60 +20,17 @@ export interface DataQualityIssue {
|
|
|
21
20
|
value?: any;
|
|
22
21
|
}
|
|
23
22
|
export declare class DataQualityValidator {
|
|
24
|
-
private knownTeams;
|
|
25
|
-
private knownLeagues;
|
|
26
|
-
constructor();
|
|
27
|
-
/**
|
|
28
|
-
* Validate match data and return quality report
|
|
29
|
-
*/
|
|
30
23
|
validateMatchData(data: Partial<Match>): DataQualityReport;
|
|
31
|
-
/**
|
|
32
|
-
* Validate team data
|
|
33
|
-
*/
|
|
34
24
|
validateTeamData(data: Partial<Team>): DataQualityReport;
|
|
35
|
-
/**
|
|
36
|
-
* Validate odds data
|
|
37
|
-
*/
|
|
38
25
|
validateOddsData(odds: MatchOdds): DataQualityReport;
|
|
39
|
-
/**
|
|
40
|
-
* Check data completeness
|
|
41
|
-
*/
|
|
42
26
|
private checkCompleteness;
|
|
43
|
-
/**
|
|
44
|
-
* Check data accuracy
|
|
45
|
-
*/
|
|
46
27
|
private checkAccuracy;
|
|
47
|
-
/**
|
|
48
|
-
* Check data freshness
|
|
49
|
-
*/
|
|
50
28
|
private checkFreshness;
|
|
51
|
-
/**
|
|
52
|
-
* Check data consistency
|
|
53
|
-
*/
|
|
54
29
|
private checkConsistency;
|
|
55
|
-
/**
|
|
56
|
-
* Validate team stats
|
|
57
|
-
*/
|
|
58
|
-
private validateTeamStats;
|
|
59
|
-
/**
|
|
60
|
-
* Generate improvement suggestions
|
|
61
|
-
*/
|
|
62
30
|
private generateSuggestions;
|
|
63
|
-
/**
|
|
64
|
-
* Calculate freshness score from timestamp
|
|
65
|
-
*/
|
|
66
31
|
private calculateFreshness;
|
|
67
|
-
/**
|
|
68
|
-
* Calculate overall score from issues and warnings
|
|
69
|
-
*/
|
|
70
32
|
private calculateScore;
|
|
71
|
-
/**
|
|
72
|
-
* Quick validation - returns true if data passes basic checks
|
|
73
|
-
*/
|
|
74
33
|
isValid(data: Partial<Match>): boolean;
|
|
75
|
-
/**
|
|
76
|
-
* Get quality grade (A-F)
|
|
77
|
-
*/
|
|
78
34
|
getGrade(score: number): string;
|
|
79
35
|
}
|
|
80
36
|
export declare function getDataQualityValidator(): DataQualityValidator;
|