@gotza02/sequential-thinking 2026.2.40 → 2026.2.41

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 (36) hide show
  1. package/dist/tools/sports/core/base.d.ts +169 -0
  2. package/dist/tools/sports/core/base.js +289 -0
  3. package/dist/tools/sports/core/cache.d.ts +106 -0
  4. package/dist/tools/sports/core/cache.js +305 -0
  5. package/dist/tools/sports/core/constants.d.ts +179 -0
  6. package/dist/tools/sports/core/constants.js +149 -0
  7. package/dist/tools/sports/core/types.d.ts +379 -0
  8. package/dist/tools/sports/core/types.js +5 -0
  9. package/dist/tools/sports/index.d.ts +34 -0
  10. package/dist/tools/sports/index.js +50 -0
  11. package/dist/tools/sports/providers/api.d.ts +73 -0
  12. package/dist/tools/sports/providers/api.js +517 -0
  13. package/dist/tools/sports/providers/scraper.d.ts +66 -0
  14. package/dist/tools/sports/providers/scraper.js +186 -0
  15. package/dist/tools/sports/providers/search.d.ts +54 -0
  16. package/dist/tools/sports/providers/search.js +224 -0
  17. package/dist/tools/sports/tools/betting.d.ts +6 -0
  18. package/dist/tools/sports/tools/betting.js +251 -0
  19. package/dist/tools/sports/tools/league.d.ts +11 -0
  20. package/dist/tools/sports/tools/league.js +12 -0
  21. package/dist/tools/sports/tools/live.d.ts +9 -0
  22. package/dist/tools/sports/tools/live.js +235 -0
  23. package/dist/tools/sports/tools/match.d.ts +6 -0
  24. package/dist/tools/sports/tools/match.js +323 -0
  25. package/dist/tools/sports/tools/player.d.ts +6 -0
  26. package/dist/tools/sports/tools/player.js +152 -0
  27. package/dist/tools/sports/tools/team.d.ts +6 -0
  28. package/dist/tools/sports/tools/team.js +370 -0
  29. package/dist/tools/sports/utils/calculator.d.ts +69 -0
  30. package/dist/tools/sports/utils/calculator.js +156 -0
  31. package/dist/tools/sports/utils/formatter.d.ts +57 -0
  32. package/dist/tools/sports/utils/formatter.js +206 -0
  33. package/dist/tools/sports.d.ts +7 -0
  34. package/dist/tools/sports.js +27 -6
  35. package/package.json +1 -1
  36. package/system_instruction.md +155 -0
@@ -0,0 +1,169 @@
1
+ /**
2
+ * SPORTS MODULE BASE CLASSES
3
+ * Abstract base classes and interfaces for data providers
4
+ */
5
+ import { Match, Team, Player, TableEntry, APIResponse, ProviderStatus, ProviderType } from './types.js';
6
+ import { CacheService } from './cache.js';
7
+ /**
8
+ * Base interface for all data providers
9
+ */
10
+ export interface IDataProvider {
11
+ /**
12
+ * Provider name/type
13
+ */
14
+ readonly type: ProviderType;
15
+ /**
16
+ * Check if provider is available
17
+ */
18
+ isAvailable(): boolean;
19
+ /**
20
+ * Get provider status
21
+ */
22
+ getStatus(): ProviderStatus;
23
+ /**
24
+ * Fetch a match by ID
25
+ */
26
+ getMatch(matchId: string): Promise<APIResponse<Match>>;
27
+ /**
28
+ * Fetch live matches for a league
29
+ */
30
+ getLiveMatches(leagueId?: string): Promise<APIResponse<Match[]>>;
31
+ /**
32
+ * Fetch league standings
33
+ */
34
+ getStandings(leagueId: string, season?: string): Promise<APIResponse<TableEntry[]>>;
35
+ /**
36
+ * Fetch team information
37
+ */
38
+ getTeam(teamId: string): Promise<APIResponse<Team>>;
39
+ /**
40
+ * Fetch player information
41
+ */
42
+ getPlayer(playerId: string): Promise<APIResponse<Player>>;
43
+ /**
44
+ * Search for teams
45
+ */
46
+ searchTeams(query: string): Promise<APIResponse<Team[]>>;
47
+ /**
48
+ * Search for players
49
+ */
50
+ searchPlayers(query: string): Promise<APIResponse<Player[]>>;
51
+ }
52
+ /**
53
+ * Abstract base class for API-based providers
54
+ */
55
+ export declare abstract class APIProviderBase implements IDataProvider {
56
+ readonly type: ProviderType;
57
+ protected apiKey: string;
58
+ protected baseUrl: string;
59
+ protected rateLimit: number;
60
+ protected cache: CacheService;
61
+ protected rateLimitUntil: Date | null;
62
+ protected lastCall: Date | null;
63
+ protected callCount: number;
64
+ constructor(type: ProviderType, apiKey: string, baseUrl: string, rateLimit?: number);
65
+ /**
66
+ * Check if provider has valid credentials
67
+ */
68
+ isAvailable(): boolean;
69
+ /**
70
+ * Check if currently rate limited
71
+ */
72
+ isRateLimited(): boolean;
73
+ /**
74
+ * Get current provider status
75
+ */
76
+ getStatus(): ProviderStatus;
77
+ /**
78
+ * Abstract methods to be implemented by concrete providers
79
+ */
80
+ abstract getMatch(matchId: string): Promise<APIResponse<Match>>;
81
+ abstract getLiveMatches(leagueId?: string): Promise<APIResponse<Match[]>>;
82
+ abstract getStandings(leagueId: string, season?: string): Promise<APIResponse<TableEntry[]>>;
83
+ abstract getTeam(teamId: string): Promise<APIResponse<Team>>;
84
+ abstract getPlayer(playerId: string): Promise<APIResponse<Player>>;
85
+ abstract searchTeams(query: string): Promise<APIResponse<Team[]>>;
86
+ abstract searchPlayers(query: string): Promise<APIResponse<Player[]>>;
87
+ /**
88
+ * Make a rate-limited API call
89
+ */
90
+ protected callAPI<T>(endpoint: string, options?: RequestInit): Promise<APIResponse<T>>;
91
+ /**
92
+ * Get authentication headers for the API
93
+ */
94
+ protected abstract getAuthHeaders(): Record<string, string>;
95
+ /**
96
+ * Transform raw API response to standard format
97
+ */
98
+ protected abstract transformResponse<T>(data: any): T;
99
+ /**
100
+ * Reset rate limit tracking (for testing)
101
+ */
102
+ resetRateLimit(): void;
103
+ }
104
+ /**
105
+ * Abstract base class for scraper-based providers
106
+ */
107
+ export declare abstract class ScraperProviderBase implements IDataProvider {
108
+ protected cache: CacheService;
109
+ readonly type: ProviderType;
110
+ constructor();
111
+ isAvailable(): boolean;
112
+ getStatus(): ProviderStatus;
113
+ abstract getMatch(matchId: string): Promise<APIResponse<Match>>;
114
+ abstract getLiveMatches(leagueId?: string): Promise<APIResponse<Match[]>>;
115
+ abstract getStandings(leagueId: string, season?: string): Promise<APIResponse<TableEntry[]>>;
116
+ abstract getTeam(teamId: string): Promise<APIResponse<Team>>;
117
+ abstract getPlayer(playerId: string): Promise<APIResponse<Player>>;
118
+ abstract searchTeams(query: string): Promise<APIResponse<Team[]>>;
119
+ abstract searchPlayers(query: string): Promise<APIResponse<Player[]>>;
120
+ /**
121
+ * Scrape a webpage and extract structured data
122
+ */
123
+ protected scrape<T>(url: string, extractor: (html: string) => T): Promise<APIResponse<T>>;
124
+ }
125
+ /**
126
+ * Fallback provider that tries multiple sources in order
127
+ */
128
+ export declare class FallbackProvider implements IDataProvider {
129
+ private providers;
130
+ private cache;
131
+ readonly type: ProviderType;
132
+ constructor(providers: IDataProvider[], cache?: CacheService);
133
+ isAvailable(): boolean;
134
+ getStatus(): ProviderStatus;
135
+ /**
136
+ * Try each provider in sequence until one succeeds
137
+ */
138
+ private tryProviders;
139
+ getMatch(matchId: string): Promise<APIResponse<Match>>;
140
+ getLiveMatches(leagueId?: string): Promise<APIResponse<Match[]>>;
141
+ getStandings(leagueId: string, season?: string): Promise<APIResponse<TableEntry[]>>;
142
+ getTeam(teamId: string): Promise<APIResponse<Team>>;
143
+ getPlayer(playerId: string): Promise<APIResponse<Player>>;
144
+ searchTeams(query: string): Promise<APIResponse<Team[]>>;
145
+ searchPlayers(query: string): Promise<APIResponse<Player[]>>;
146
+ }
147
+ /**
148
+ * Base class for sports tools
149
+ */
150
+ export declare abstract class SportsToolBase {
151
+ protected cache: CacheService;
152
+ constructor(cache?: CacheService);
153
+ /**
154
+ * Format error message for user
155
+ */
156
+ protected formatError(error: unknown, context: string): string;
157
+ /**
158
+ * Sanitize user input
159
+ */
160
+ protected sanitizeInput(input: string): string;
161
+ /**
162
+ * Format a team name for search
163
+ */
164
+ protected formatTeamName(name: string): string;
165
+ /**
166
+ * Format date to readable string
167
+ */
168
+ protected formatDate(date: Date): string;
169
+ }
@@ -0,0 +1,289 @@
1
+ /**
2
+ * SPORTS MODULE BASE CLASSES
3
+ * Abstract base classes and interfaces for data providers
4
+ */
5
+ import { CacheService } from './cache.js';
6
+ import { logger } from '../../../utils.js';
7
+ /**
8
+ * Abstract base class for API-based providers
9
+ */
10
+ export class APIProviderBase {
11
+ type;
12
+ apiKey;
13
+ baseUrl;
14
+ rateLimit;
15
+ cache;
16
+ rateLimitUntil = null;
17
+ lastCall = null;
18
+ callCount = 0;
19
+ constructor(type, apiKey, baseUrl, rateLimit = 10 // calls per minute
20
+ ) {
21
+ this.type = type;
22
+ this.apiKey = apiKey;
23
+ this.baseUrl = baseUrl;
24
+ this.rateLimit = rateLimit;
25
+ this.cache = new CacheService();
26
+ }
27
+ /**
28
+ * Check if provider has valid credentials
29
+ */
30
+ isAvailable() {
31
+ return !!this.apiKey && !this.isRateLimited();
32
+ }
33
+ /**
34
+ * Check if currently rate limited
35
+ */
36
+ isRateLimited() {
37
+ if (!this.rateLimitUntil)
38
+ return false;
39
+ return new Date() < this.rateLimitUntil;
40
+ }
41
+ /**
42
+ * Get current provider status
43
+ */
44
+ getStatus() {
45
+ return {
46
+ name: this.type,
47
+ available: this.isAvailable(),
48
+ quotaRemaining: Math.max(0, this.rateLimit - this.callCount),
49
+ quotaLimit: this.rateLimit,
50
+ rateLimitUntil: this.rateLimitUntil || undefined,
51
+ lastCall: this.lastCall || undefined,
52
+ };
53
+ }
54
+ /**
55
+ * Make a rate-limited API call
56
+ */
57
+ async callAPI(endpoint, options = {}) {
58
+ // Check rate limit
59
+ if (this.isRateLimited()) {
60
+ return {
61
+ success: false,
62
+ error: `Rate limited until ${this.rateLimitUntil}`,
63
+ rateLimited: true,
64
+ };
65
+ }
66
+ // Check availability
67
+ if (!this.isAvailable()) {
68
+ return {
69
+ success: false,
70
+ error: 'Provider not available (missing API key)',
71
+ };
72
+ }
73
+ try {
74
+ const url = `${this.baseUrl}${endpoint}`;
75
+ const response = await fetch(url, {
76
+ ...options,
77
+ headers: {
78
+ 'Content-Type': 'application/json',
79
+ ...this.getAuthHeaders(),
80
+ ...options.headers,
81
+ },
82
+ });
83
+ this.lastCall = new Date();
84
+ this.callCount++;
85
+ if (!response.ok) {
86
+ // Handle rate limiting
87
+ if (response.status === 429) {
88
+ const retryAfter = response.headers.get('Retry-After');
89
+ this.rateLimitUntil = new Date(Date.now() + (retryAfter ? parseInt(retryAfter) * 1000 : 60000));
90
+ return {
91
+ success: false,
92
+ error: 'Rate limited',
93
+ rateLimited: true,
94
+ };
95
+ }
96
+ return {
97
+ success: false,
98
+ error: `HTTP ${response.status}: ${response.statusText}`,
99
+ };
100
+ }
101
+ const data = await response.json();
102
+ return {
103
+ success: true,
104
+ data: this.transformResponse(data),
105
+ provider: this.type,
106
+ };
107
+ }
108
+ catch (error) {
109
+ logger.error(`${this.type} API error: ${error}`);
110
+ return {
111
+ success: false,
112
+ error: error instanceof Error ? error.message : String(error),
113
+ };
114
+ }
115
+ }
116
+ /**
117
+ * Reset rate limit tracking (for testing)
118
+ */
119
+ resetRateLimit() {
120
+ this.rateLimitUntil = null;
121
+ this.callCount = 0;
122
+ }
123
+ }
124
+ /**
125
+ * Abstract base class for scraper-based providers
126
+ */
127
+ export class ScraperProviderBase {
128
+ cache;
129
+ type = 'scraper';
130
+ constructor() {
131
+ this.cache = new CacheService();
132
+ }
133
+ isAvailable() {
134
+ return true; // Scraping is always "available"
135
+ }
136
+ getStatus() {
137
+ return {
138
+ name: this.type,
139
+ available: true,
140
+ quotaRemaining: Infinity,
141
+ quotaLimit: Infinity,
142
+ };
143
+ }
144
+ /**
145
+ * Scrape a webpage and extract structured data
146
+ */
147
+ async scrape(url, extractor) {
148
+ try {
149
+ const { fetchWithRetry } = await import('../../../utils.js');
150
+ const response = await fetchWithRetry(url);
151
+ const html = await response.text();
152
+ const data = extractor(html);
153
+ return {
154
+ success: true,
155
+ data,
156
+ provider: 'scraper',
157
+ };
158
+ }
159
+ catch (error) {
160
+ logger.error(`Scraping error for ${url}: ${error}`);
161
+ return {
162
+ success: false,
163
+ error: error instanceof Error ? error.message : String(error),
164
+ };
165
+ }
166
+ }
167
+ }
168
+ /**
169
+ * Fallback provider that tries multiple sources in order
170
+ */
171
+ export class FallbackProvider {
172
+ providers;
173
+ cache;
174
+ type = 'scraper';
175
+ constructor(providers, cache = new CacheService()) {
176
+ this.providers = providers;
177
+ this.cache = cache;
178
+ }
179
+ isAvailable() {
180
+ return this.providers.some(p => p.isAvailable());
181
+ }
182
+ getStatus() {
183
+ const available = this.providers.filter(p => p.isAvailable());
184
+ return {
185
+ name: this.type,
186
+ available: available.length > 0,
187
+ quotaRemaining: available.length,
188
+ quotaLimit: this.providers.length,
189
+ };
190
+ }
191
+ /**
192
+ * Try each provider in sequence until one succeeds
193
+ */
194
+ async tryProviders(fn) {
195
+ const errors = [];
196
+ for (const provider of this.providers) {
197
+ if (!provider.isAvailable()) {
198
+ continue;
199
+ }
200
+ const result = await fn(provider);
201
+ if (result.success) {
202
+ return result;
203
+ }
204
+ errors.push(`${provider.type}: ${result.error || 'Unknown error'}`);
205
+ }
206
+ return {
207
+ success: false,
208
+ error: `All providers failed:\n${errors.join('\n')}`,
209
+ };
210
+ }
211
+ async getMatch(matchId) {
212
+ const cacheKey = CacheService.generateKey('match', matchId);
213
+ return this.cache.getOrSet(cacheKey, () => this.tryProviders(p => p.getMatch(matchId)), 5 * 60 * 1000 // 5 minutes
214
+ );
215
+ }
216
+ async getLiveMatches(leagueId) {
217
+ const cacheKey = CacheService.generateKey('live', leagueId || 'all');
218
+ return this.cache.getOrSet(cacheKey, () => this.tryProviders(p => p.getLiveMatches(leagueId)), 60 * 1000 // 1 minute
219
+ );
220
+ }
221
+ async getStandings(leagueId, season) {
222
+ const cacheKey = CacheService.generateKey('standings', leagueId, season || 'current');
223
+ return this.cache.getOrSet(cacheKey, () => this.tryProviders(p => p.getStandings(leagueId, season)), 30 * 60 * 1000 // 30 minutes
224
+ );
225
+ }
226
+ async getTeam(teamId) {
227
+ const cacheKey = CacheService.generateKey('team', teamId);
228
+ return this.cache.getOrSet(cacheKey, () => this.tryProviders(p => p.getTeam(teamId)), 60 * 60 * 1000 // 1 hour
229
+ );
230
+ }
231
+ async getPlayer(playerId) {
232
+ const cacheKey = CacheService.generateKey('player', playerId);
233
+ return this.cache.getOrSet(cacheKey, () => this.tryProviders(p => p.getPlayer(playerId)), 60 * 60 * 1000 // 1 hour
234
+ );
235
+ }
236
+ async searchTeams(query) {
237
+ const cacheKey = CacheService.generateKey('search', 'team', query);
238
+ return this.cache.getOrSet(cacheKey, () => this.tryProviders(p => p.searchTeams(query)), 60 * 60 * 1000 // 1 hour
239
+ );
240
+ }
241
+ async searchPlayers(query) {
242
+ const cacheKey = CacheService.generateKey('search', 'player', query);
243
+ return this.cache.getOrSet(cacheKey, () => this.tryProviders(p => p.searchPlayers(query)), 60 * 60 * 1000 // 1 hour
244
+ );
245
+ }
246
+ }
247
+ /**
248
+ * Base class for sports tools
249
+ */
250
+ export class SportsToolBase {
251
+ cache;
252
+ constructor(cache) {
253
+ this.cache = cache || new CacheService();
254
+ }
255
+ /**
256
+ * Format error message for user
257
+ */
258
+ formatError(error, context) {
259
+ if (error instanceof Error) {
260
+ return `Error in ${context}: ${error.message}`;
261
+ }
262
+ return `Unknown error in ${context}`;
263
+ }
264
+ /**
265
+ * Sanitize user input
266
+ */
267
+ sanitizeInput(input) {
268
+ return input.trim().replace(/[<>]/g, '');
269
+ }
270
+ /**
271
+ * Format a team name for search
272
+ */
273
+ formatTeamName(name) {
274
+ return this.sanitizeInput(name).toLowerCase();
275
+ }
276
+ /**
277
+ * Format date to readable string
278
+ */
279
+ formatDate(date) {
280
+ return date.toLocaleDateString('en-US', {
281
+ weekday: 'short',
282
+ year: 'numeric',
283
+ month: 'short',
284
+ day: 'numeric',
285
+ hour: '2-digit',
286
+ minute: '2-digit',
287
+ });
288
+ }
289
+ }
@@ -0,0 +1,106 @@
1
+ /**
2
+ * SPORTS MODULE CACHE SERVICE
3
+ * TTL-based caching with file persistence for the football intelligence system
4
+ */
5
+ /**
6
+ * CacheService - Thread-safe TTL-based caching with persistence
7
+ */
8
+ export declare class CacheService {
9
+ private cache;
10
+ private cachePath;
11
+ private maxAge;
12
+ private maxSize;
13
+ private savePending;
14
+ private saveTimer;
15
+ constructor(cachePath?: string, maxAge?: number, maxSize?: number);
16
+ /**
17
+ * Generate a cache key from components
18
+ */
19
+ static generateKey(...parts: (string | number)[]): string;
20
+ /**
21
+ * Get a value from cache
22
+ */
23
+ get<T>(key: string): T | null;
24
+ /**
25
+ * Set a value in cache
26
+ */
27
+ set<T>(key: string, data: T, ttl?: number): void;
28
+ /**
29
+ * Check if a key exists and is not expired
30
+ */
31
+ has(key: string): boolean;
32
+ /**
33
+ * Delete a specific key
34
+ */
35
+ delete(key: string): boolean;
36
+ /**
37
+ * Clear all cache entries
38
+ */
39
+ clear(): void;
40
+ /**
41
+ * Get cache statistics
42
+ */
43
+ getStats(): {
44
+ size: number;
45
+ maxSize: number;
46
+ hits: number;
47
+ entries: Array<{
48
+ key: string;
49
+ hits: number;
50
+ age: number;
51
+ ttl: number;
52
+ }>;
53
+ };
54
+ /**
55
+ * Clean up expired entries
56
+ */
57
+ cleanup(): number;
58
+ /**
59
+ * Evict the oldest entry (LRU)
60
+ */
61
+ private evictOldest;
62
+ /**
63
+ * Schedule a save operation (debounced)
64
+ */
65
+ private scheduleSave;
66
+ /**
67
+ * Save cache to file
68
+ */
69
+ private saveToFile;
70
+ /**
71
+ * Load cache from file
72
+ */
73
+ private loadFromFile;
74
+ /**
75
+ * Force save cache to file immediately
76
+ */
77
+ flush(): Promise<void>;
78
+ /**
79
+ * Get or set pattern - returns cached value or computes and caches it
80
+ */
81
+ getOrSet<T>(key: string, factory: () => T | Promise<T>, ttl?: number): Promise<T>;
82
+ /**
83
+ * Get multiple keys at once
84
+ */
85
+ getMultiple<T>(keys: string[]): Map<string, T>;
86
+ /**
87
+ * Set multiple keys at once
88
+ */
89
+ setMultiple<T>(entries: Map<string, T>, ttl?: number): void;
90
+ /**
91
+ * Invalidate cache by pattern
92
+ */
93
+ invalidatePattern(pattern: string): number;
94
+ /**
95
+ * Get cache size breakdown by key prefix
96
+ */
97
+ getBreakdown(): Record<string, number>;
98
+ }
99
+ /**
100
+ * Get or create the global cache instance
101
+ */
102
+ export declare function getGlobalCache(): CacheService;
103
+ /**
104
+ * Reset the global cache instance
105
+ */
106
+ export declare function resetGlobalCache(): void;