@semanticintent/semantic-chirp-intelligence-mcp 3.0.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,246 @@
1
+ // @ts-nocheck
2
+ /**
3
+ * StreamingAnalysis - Template Method Pattern Implementation
4
+ *
5
+ * Recommends waiver wire pickups based on schedule advantages and player trends.
6
+ */
7
+ import { AnalysisTemplate } from '../template/AnalysisTemplate.js';
8
+ import { ChirpIntelligence } from '../services/ChirpIntelligence.js';
9
+ export class StreamingAnalysis extends AnalysisTemplate {
10
+ apiClient;
11
+ leagueId;
12
+ teamId;
13
+ constructor(apiClient, leagueId, teamId) {
14
+ super("get_streaming_recommendations", "streaming_strategy");
15
+ this.apiClient = apiClient;
16
+ this.leagueId = leagueId;
17
+ this.teamId = teamId;
18
+ }
19
+ /**
20
+ * Hook 1: Fetch raw data from Yahoo API
21
+ */
22
+ async fetchData(args) {
23
+ try {
24
+ // Fetch trending players (hot pickups)
25
+ // Note: apiClient.request() already includes /fantasy/v2 base
26
+ const cleanLeagueId = this.leagueId.replace(/^nhl\.l\./, '');
27
+ const trendingData = await this.apiClient.request(`/league/nhl.l.${cleanLeagueId}/players;status=A;sort=AR`);
28
+ // Fetch your current roster to avoid recommending owned players
29
+ const rosterData = await this.apiClient.getTeamRoster(this.leagueId, this.teamId);
30
+ // Fetch league scoreboard for schedule data
31
+ const scoreboardData = await this.apiClient.getLeagueScoreboard(this.leagueId);
32
+ return {
33
+ trending: trendingData,
34
+ roster: rosterData,
35
+ scoreboard: scoreboardData
36
+ };
37
+ }
38
+ catch (error) {
39
+ throw new Error(`Failed to fetch streaming data: ${error}`);
40
+ }
41
+ }
42
+ /**
43
+ * Hook 2: Prepare data into FantasyData structure
44
+ */
45
+ async prepareData(rawData, args) {
46
+ const { trending, roster, scoreboard } = rawData;
47
+ // Parse current roster to filter out owned players
48
+ const ownedPlayerIds = new Set();
49
+ const rosterPlayers = roster.fantasy_content?.team?.[1]?.roster?.['0']?.players?.['0']?.player || [];
50
+ for (const playerData of rosterPlayers) {
51
+ const player = playerData.player?.[0] || playerData;
52
+ ownedPlayerIds.add(player.player_id);
53
+ }
54
+ // Parse available trending players
55
+ const availablePlayers = [];
56
+ const trendingPlayers = trending.fantasy_content?.league?.[1]?.players?.['0']?.player || [];
57
+ for (const playerData of trendingPlayers) {
58
+ const player = playerData.player?.[0] || playerData;
59
+ const playerId = player.player_id;
60
+ // Skip if already owned
61
+ if (ownedPlayerIds.has(playerId)) {
62
+ continue;
63
+ }
64
+ // Apply position filter if specified
65
+ const position = player.display_position || player.primary_positions?.[0] || 'Unknown';
66
+ if (args.position_filter && args.position_filter.length > 0) {
67
+ if (!args.position_filter.includes(position)) {
68
+ continue;
69
+ }
70
+ }
71
+ availablePlayers.push({
72
+ player_id: playerId,
73
+ name: player.name?.full || 'Unknown',
74
+ position: position,
75
+ team: player.editorial_team_abbr || '',
76
+ selected_position: ['FA'], // Free agent
77
+ status: player.status,
78
+ percent_owned: parseFloat(player.percent_owned?.value || '0'),
79
+ stats: this.parsePlayerStats(player)
80
+ });
81
+ // Limit to top available players
82
+ if (availablePlayers.length >= (args.max_recommendations || 10) * 2) {
83
+ break;
84
+ }
85
+ }
86
+ return {
87
+ availablePlayers,
88
+ roster: this.parseRoster(roster),
89
+ scoreboard: scoreboard
90
+ };
91
+ }
92
+ /**
93
+ * Hook 3: Analyze data to generate streaming recommendations
94
+ */
95
+ async analyzeData(data, args) {
96
+ const lookAheadDays = args.look_ahead_days || 7;
97
+ const maxRecommendations = args.max_recommendations || 5;
98
+ const streamingRecommendations = [];
99
+ // Analyze each available player
100
+ for (const player of data.availablePlayers || []) {
101
+ // Calculate games this week (simplified - would use actual schedule in production)
102
+ const gamesThisWeek = this.estimateGamesThisWeek(player, lookAheadDays);
103
+ // Determine pickup priority based on games and ownership
104
+ let pickupPriority;
105
+ let reasoning;
106
+ if (gamesThisWeek >= 4 && (player.percent_owned || 0) < 20) {
107
+ pickupPriority = 'HIGH';
108
+ reasoning = `${gamesThisWeek} games this week, low ownership (${player.percent_owned?.toFixed(1)}%)`;
109
+ }
110
+ else if (gamesThisWeek >= 3) {
111
+ pickupPriority = 'MEDIUM';
112
+ reasoning = `${gamesThisWeek} games this week, good volume play`;
113
+ }
114
+ else if ((player.percent_owned || 0) > 50) {
115
+ pickupPriority = 'HIGH';
116
+ reasoning = `High ownership (${player.percent_owned?.toFixed(1)}%) trending player`;
117
+ }
118
+ else {
119
+ pickupPriority = 'LOW';
120
+ reasoning = `${gamesThisWeek} games this week, speculative add`;
121
+ }
122
+ streamingRecommendations.push({
123
+ player,
124
+ games_this_week: gamesThisWeek,
125
+ recent_performance: this.describePerformance(player),
126
+ pickup_priority: pickupPriority,
127
+ reasoning
128
+ });
129
+ }
130
+ // Sort by priority and games
131
+ streamingRecommendations.sort((a, b) => {
132
+ const priorityOrder = { CRITICAL: 0, HIGH: 1, MEDIUM: 2, LOW: 3 };
133
+ const priorityDiff = priorityOrder[a.pickup_priority] - priorityOrder[b.pickup_priority];
134
+ if (priorityDiff !== 0)
135
+ return priorityDiff;
136
+ return b.games_this_week - a.games_this_week;
137
+ });
138
+ return streamingRecommendations.slice(0, maxRecommendations);
139
+ }
140
+ /**
141
+ * Hook 4: Generate chirp-enhanced response
142
+ */
143
+ async generateChirp(analysisResults, semanticContract, data) {
144
+ return ChirpIntelligence.enhance(this.toolName, { streaming_recommendations: analysisResults }, semanticContract);
145
+ }
146
+ /**
147
+ * Hook 5: Format final response
148
+ */
149
+ async formatResponse(chirpEnhanced, data) {
150
+ const streamingData = chirpEnhanced.streaming_recommendations;
151
+ // Convert to standard Recommendation format
152
+ const recommendations = streamingData.map(analysis => ({
153
+ priority: analysis.pickup_priority,
154
+ action: 'pickup',
155
+ pickup: analysis.player,
156
+ reasoning: analysis.reasoning
157
+ }));
158
+ const analysisInsights = {
159
+ streaming_summary: {
160
+ total_recommendations: streamingData.length,
161
+ high_priority_count: streamingData.filter(s => s.pickup_priority === 'HIGH' || s.pickup_priority === 'CRITICAL').length,
162
+ average_games_per_player: streamingData.reduce((sum, s) => sum + s.games_this_week, 0) / streamingData.length || 0
163
+ },
164
+ top_targets: streamingData.slice(0, 3).map(s => ({
165
+ player: s.player.name,
166
+ games: s.games_this_week,
167
+ reasoning: s.reasoning
168
+ }))
169
+ };
170
+ const metadata = {
171
+ analysis_type: this.analysisType,
172
+ timestamp: new Date().toISOString(),
173
+ team_context: {
174
+ team_name: data.roster?.team_name || 'Your Team'
175
+ },
176
+ semantic_contract_applied: true
177
+ };
178
+ return {
179
+ analysis_insights: analysisInsights,
180
+ recommendations,
181
+ chirp_intelligence: chirpEnhanced.chirp_intelligence,
182
+ metadata
183
+ };
184
+ }
185
+ /**
186
+ * Helper: Parse roster data
187
+ */
188
+ parseRoster(rosterData) {
189
+ const team = rosterData.fantasy_content?.team?.[0] || {};
190
+ const rosterPlayers = rosterData.fantasy_content?.team?.[1]?.roster?.['0']?.players?.['0']?.player || [];
191
+ const players = rosterPlayers.map((playerData) => {
192
+ const player = playerData.player?.[0] || playerData;
193
+ return {
194
+ player_id: player.player_id,
195
+ name: player.name?.full || 'Unknown',
196
+ position: player.display_position || player.primary_positions?.[0] || 'Unknown',
197
+ team: player.editorial_team_abbr || '',
198
+ selected_position: player.selected_position || [],
199
+ status: player.status
200
+ };
201
+ });
202
+ return {
203
+ team_key: team.team_key || '',
204
+ team_name: team.name || 'Your Team',
205
+ players
206
+ };
207
+ }
208
+ /**
209
+ * Helper: Parse player stats from API response
210
+ */
211
+ parsePlayerStats(player) {
212
+ // Simplified - would parse actual stats in production
213
+ return {
214
+ percent_owned: player.percent_owned?.value || 0,
215
+ display_position: player.display_position
216
+ };
217
+ }
218
+ /**
219
+ * Helper: Estimate games this week for a player
220
+ */
221
+ estimateGamesThisWeek(player, lookAheadDays) {
222
+ // Simplified calculation - in production would use actual NHL schedule
223
+ // Average NHL team plays 3-4 games per week
224
+ const gamesPerWeek = 3.5;
225
+ return Math.round((lookAheadDays / 7) * gamesPerWeek);
226
+ }
227
+ /**
228
+ * Helper: Describe recent performance
229
+ */
230
+ describePerformance(player) {
231
+ // Simplified - would analyze actual recent stats in production
232
+ const ownership = player.percent_owned || 0;
233
+ if (ownership > 70) {
234
+ return "Widely owned hot player";
235
+ }
236
+ else if (ownership > 40) {
237
+ return "Trending upward";
238
+ }
239
+ else if (ownership > 20) {
240
+ return "Under-the-radar option";
241
+ }
242
+ else {
243
+ return "Deep league sleeper";
244
+ }
245
+ }
246
+ }