@semanticintent/semantic-chirp-intelligence-mcp 3.1.0 → 4.0.1
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/.chirp-data/opponent.json +24 -0
- package/.chirp-data/roster.json +34 -0
- package/.chirp-data/standings.json +17 -0
- package/.nhl-schedule-cache/20262027.json +1 -0
- package/.nhl-schedule-cache/players-20262027-20252026.json +1 -0
- package/README.md +132 -86
- package/build/analyses/BreakoutAnalysis.js +25 -36
- package/build/analyses/DraftPickAnalysis.js +431 -0
- package/build/analyses/GamesInHandAnalysis.js +52 -121
- package/build/analyses/IceAnalysis.js +66 -57
- package/build/analyses/LineupAnalysis.js +26 -46
- package/build/analyses/ScheduleValueAnalysis.js +279 -0
- package/build/analyses/StreamingAnalysis.js +40 -76
- package/build/analyses/WeekendStreamAnalysis.js +130 -66
- package/build/config/tool-metadata.js +54 -0
- package/build/domain/nhl-teams.js +67 -0
- package/build/index.js +561 -653
- package/build/services/LeagueDataService.js +130 -0
- package/build/services/NhlScheduleService.js +357 -0
- package/build/services/NhlStatsService.js +297 -0
- package/build/services/RosterStore.js +233 -0
- package/package.json +12 -11
- package/scripts/preflight.mjs +67 -0
- package/scripts/smoke.mjs +92 -0
- package/.env.example +0 -8
- package/authenticate.js +0 -207
- package/build/experimental/semantic-breakout-tool.js +0 -188
- package/build/experimental/semantic-intent-parser.js +0 -222
- package/build/experimental/semantic-tool-integration.js +0 -146
- package/build/experimental/test-parser.js +0 -61
- package/build/services/YahooApiClient.js +0 -309
package/README.md
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# 🏒 Semantic CHIRP Intelligence MCP
|
|
2
2
|
|
|
3
|
-
> **
|
|
4
|
-
> A Model Context Protocol (MCP) server that turns
|
|
3
|
+
> **Universal fantasy hockey intelligence.**
|
|
4
|
+
> A Model Context Protocol (MCP) server that turns any roster into an AI advisor —
|
|
5
|
+
> no account, no API key, no platform lock-in. Paste your team, get the cold truth.
|
|
5
6
|
|
|
6
7
|
[](https://chirp.semanticintent.dev)
|
|
7
8
|

|
|
@@ -15,18 +16,28 @@
|
|
|
15
16
|
|
|
16
17
|
## What this is
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
CHIRP is a **players-and-teams intelligence layer**. You tell it who is on your
|
|
20
|
+
roster — by pasting it from anywhere — and it reasons about schedules, statistics,
|
|
21
|
+
lineups, trades and draft value using the NHL's public API.
|
|
19
22
|
|
|
20
|
-
It
|
|
23
|
+
It is not tied to a fantasy platform. Yahoo, ESPN, Sleeper, CBS, a spreadsheet or a
|
|
24
|
+
paper league all work the same way, because the only thing CHIRP needs from you is
|
|
25
|
+
a list of names.
|
|
26
|
+
|
|
27
|
+
Every tool carries intent metadata, analyses run through a shared template, and
|
|
28
|
+
results come back with a *point of view* — schedule edges, roster truths, and the
|
|
29
|
+
occasional chirp.
|
|
21
30
|
|
|
22
31
|
### Highlights
|
|
23
32
|
|
|
33
|
+
- 🚀 **Zero setup** — no OAuth, no API key, no application to any platform. Install, paste a roster, done.
|
|
34
|
+
- 📋 **Paste from anywhere** — names resolve against live NHL rosters, so team and position fill themselves in. Accents, `Lastname, Firstname` and punctuation all handled.
|
|
24
35
|
- ❄️ **ICE — the Intent Chirp Engine** — championship-level roster analysis with brutal honesty
|
|
25
|
-
-
|
|
26
|
-
-
|
|
36
|
+
- 🎯 **Draft intelligence** — who to take at pick N, scored on real production and playoff-week schedule
|
|
37
|
+
- 🗓️ **Schedule intelligence** — every game count comes from the NHL's public club-schedule API, per club, per week
|
|
27
38
|
- 🏛️ **Semantic Anchoring Governance** — every tool declares its intent; a dashboard surfaces the health metrics
|
|
28
39
|
- 🧩 **Template Pattern architecture** — analyses are composable, consistent, and testable
|
|
29
|
-
- 🔒 **Read-only & local** —
|
|
40
|
+
- 🔒 **Read-only & local** — no credentials of any kind, no third-party data egress; your roster never leaves your machine
|
|
30
41
|
|
|
31
42
|
---
|
|
32
43
|
|
|
@@ -42,11 +53,15 @@ It's built on the same **Semantic Intent** philosophy as its sibling project, th
|
|
|
42
53
|
├─────────────────────────────────────────────────────────────┤
|
|
43
54
|
│ Intelligence layer (src/analyses/ + src/template/) │
|
|
44
55
|
│ • AnalysisTemplate — shared Template Pattern base │
|
|
45
|
-
│ • Ice /
|
|
56
|
+
│ • Ice / Lineup / GamesInHand / Streaming / WeekendStream │
|
|
57
|
+
│ • Breakout / ScheduleValue / DraftPick │
|
|
46
58
|
├─────────────────────────────────────────────────────────────┤
|
|
47
59
|
│ Services (src/services/) │
|
|
48
60
|
│ • ChirpIntelligence — turns data into chirp │
|
|
49
|
-
│ •
|
|
61
|
+
│ • NhlScheduleService — schedules, standings (NHL public API)│
|
|
62
|
+
│ • NhlStatsService — player identity + season statistics │
|
|
63
|
+
│ • RosterStore — parses and stores what you paste │
|
|
64
|
+
│ • LeagueDataService — league state, source-agnostic │
|
|
50
65
|
├─────────────────────────────────────────────────────────────┤
|
|
51
66
|
│ Domain (src/domain/) — types + governance │
|
|
52
67
|
└─────────────────────────────────────────────────────────────┘
|
|
@@ -59,90 +74,97 @@ It's built on the same **Semantic Intent** philosophy as its sibling project, th
|
|
|
59
74
|
|
|
60
75
|
## Available Tools
|
|
61
76
|
|
|
62
|
-
###
|
|
77
|
+
### Setting up your league (paste-based)
|
|
63
78
|
|
|
64
79
|
| Tool | Description |
|
|
65
80
|
|------|-------------|
|
|
66
|
-
| `
|
|
67
|
-
| `
|
|
68
|
-
| `
|
|
69
|
-
| `
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
| `compare_matchup` | Category-by-category breakdown of your matchup |
|
|
73
|
-
| `optimize_lineup` | Lineup recommendations based on health and positions |
|
|
74
|
-
| `get_trending_players` | Most-added / most-owned players — hot pickups |
|
|
75
|
-
| `debug_api_call` | Inspect raw Yahoo API responses for troubleshooting |
|
|
76
|
-
|
|
77
|
-
### CHIRP intelligence tools (Template Pattern + semantic analysis)
|
|
81
|
+
| `set_roster` | 📋 Paste your roster. Names resolve against live NHL rosters; team and position fill themselves in |
|
|
82
|
+
| `set_opponent_roster` | 📋 Paste your weekly opponent, enabling head-to-head analysis |
|
|
83
|
+
| `set_standings` | 📊 Paste league standings for league context |
|
|
84
|
+
| `show_stored_data` | 🗂️ Show (or clear) what CHIRP currently knows |
|
|
85
|
+
|
|
86
|
+
### Core data tools
|
|
78
87
|
|
|
79
88
|
| Tool | Description |
|
|
80
89
|
|------|-------------|
|
|
81
|
-
| `
|
|
82
|
-
| `
|
|
83
|
-
| `
|
|
84
|
-
| `
|
|
85
|
-
| `
|
|
86
|
-
| `governance_dashboard` | 🏛️ Semantic Anchoring Governance health, analysis metrics, and violations |
|
|
90
|
+
| `get_team_roster` | Your roster with live NHL club, position, season stats and games this week |
|
|
91
|
+
| `get_league_standings` | The standings you pasted |
|
|
92
|
+
| `search_players` | Search all 1,200+ NHL players by position, ranked by production |
|
|
93
|
+
| `get_player_stats` | Full stats for any player — by name, not an internal id |
|
|
94
|
+
| `compare_matchup` | Category-by-category comparison of your roster against your opponent's |
|
|
87
95
|
|
|
88
|
-
|
|
96
|
+
### CHIRP intelligence tools
|
|
89
97
|
|
|
90
|
-
|
|
98
|
+
| Tool | Description |
|
|
99
|
+
|------|-------------|
|
|
100
|
+
| `ice` | ❄️ **Intent Chirp Engine** — the flagship advisor; ice-cold, championship-level roster analysis |
|
|
101
|
+
| `get_roster_transaction_recommendations` | 🏒 ICE roster optimization — savage, brutally honest calls |
|
|
102
|
+
| `optimize_lineup` | Lineup recommendations from health, position and who actually plays tonight |
|
|
103
|
+
| `get_games_in_hand` | Schedule-advantage analysis, you vs. your opponent |
|
|
104
|
+
| `get_streaming_recommendations` | Schedule-aware pickup candidates |
|
|
105
|
+
| `analyze_weekend_streams` | 🌊 Weekend classifier — desperation filler vs. genuine upside |
|
|
106
|
+
| `analyze_breakout_players` | 📈 Breakout candidates scored on real production, opportunity and risk |
|
|
107
|
+
| `analyze_trade` | Category-by-category trade breakdown with an ACCEPT / DECLINE / PUSH verdict |
|
|
108
|
+
| `chirp_opponent` | Scouts your opponent's roster and chirps its weaknesses |
|
|
109
|
+
| `governance_dashboard` | 🏛️ Semantic Anchoring Governance health and analysis metrics |
|
|
110
|
+
|
|
111
|
+
### Draft tools
|
|
91
112
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
113
|
+
| Tool | Description |
|
|
114
|
+
|------|-------------|
|
|
115
|
+
| `chirp_draft_pick` | 🎯 **ICE at the draft table** — who to take at pick N, given who is gone, what you need, and playoff-week schedule |
|
|
116
|
+
| `schedule_value` | 🗓️ All 32 clubs rated — total games, four-game weeks, light weeks, back-to-backs, playoff-window volume |
|
|
95
117
|
|
|
96
|
-
|
|
118
|
+
> **On availability:** CHIRP knows every NHL player, but it cannot know who is
|
|
119
|
+
> *unowned in your league* — ownership is league-private and no public source
|
|
120
|
+
> exposes it. Pool-based tools therefore return "players not on the rosters you
|
|
121
|
+
> provided", ranked by production, and say so. Check availability before adding.
|
|
97
122
|
|
|
98
|
-
|
|
123
|
+
## Where the numbers come from
|
|
99
124
|
|
|
100
|
-
|
|
125
|
+
Every figure is fetched, not estimated — and none of it needs an account:
|
|
101
126
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
-
|
|
127
|
+
| Signal | Source |
|
|
128
|
+
|--------|--------|
|
|
129
|
+
| Games per week, back-to-backs, playoff-window volume | NHL public API (`club-schedule-season`) — all 32 clubs, cached per season |
|
|
130
|
+
| Player identity, club, position | NHL public API (`roster`) — 1,268 players |
|
|
131
|
+
| Season statistics (skaters and goalies) | NHL public API (`club-stats`) |
|
|
132
|
+
| Opponent difficulty | NHL standings, ranked by goals allowed per game |
|
|
133
|
+
| Your roster, opponent, standings | What you paste |
|
|
105
134
|
|
|
106
|
-
|
|
135
|
+
When a source is unreachable, the tool says so in its output and drops that
|
|
136
|
+
component from its scoring — it does not substitute an estimate for a fact.
|
|
107
137
|
|
|
108
|
-
|
|
138
|
+
---
|
|
109
139
|
|
|
110
|
-
|
|
140
|
+
## Prerequisites
|
|
111
141
|
|
|
112
|
-
|
|
142
|
+
- **Node.js 20+**
|
|
143
|
+
- An MCP client — e.g. **Claude Desktop**
|
|
113
144
|
|
|
114
|
-
|
|
145
|
+
That is the whole list. There is no account to create, no application to file, and
|
|
146
|
+
no credential to store.
|
|
115
147
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
148
|
+
> **Coming from v3?** v3 read your league through the Yahoo Fantasy API. In 2026
|
|
149
|
+
> Yahoo put that API behind a manual approval process that also revoked existing
|
|
150
|
+
> access, so a working install could stop working without any change to the code.
|
|
151
|
+
> v4 removes the dependency entirely: CHIRP now reasons about any roster you paste,
|
|
152
|
+
> on any platform. The Yahoo integration is preserved at the
|
|
153
|
+
> [v3.2.0 tag](https://github.com/semanticintent/semantic-chirp-intelligence-mcp/releases/tag/v3.2.0).
|
|
122
154
|
|
|
123
|
-
|
|
124
|
-
```
|
|
125
|
-
YAHOO_CLIENT_ID=your_client_id
|
|
126
|
-
YAHOO_CLIENT_SECRET=your_client_secret
|
|
127
|
-
YAHOO_LEAGUE_ID=your_league_id
|
|
128
|
-
YAHOO_TEAM_ID=your_team_id
|
|
129
|
-
```
|
|
155
|
+
---
|
|
130
156
|
|
|
131
|
-
|
|
157
|
+
## Setup
|
|
132
158
|
|
|
133
159
|
```bash
|
|
160
|
+
git clone https://github.com/semanticintent/semantic-chirp-intelligence-mcp.git
|
|
161
|
+
cd semantic-chirp-intelligence-mcp
|
|
162
|
+
npm install
|
|
134
163
|
npm run build
|
|
164
|
+
npm run preflight # checks the build and the NHL API — no credentials involved
|
|
135
165
|
```
|
|
136
166
|
|
|
137
|
-
###
|
|
138
|
-
|
|
139
|
-
```bash
|
|
140
|
-
node authenticate.js
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
Open the printed URL, click through the self-signed-certificate warning (it's a local callback), sign in, and authorize. The token is saved to `.yahoo-oauth.json` (git-ignored). The server auto-refreshes it after that.
|
|
144
|
-
|
|
145
|
-
### 6. Add to Claude Desktop
|
|
167
|
+
### Add to Claude Desktop
|
|
146
168
|
|
|
147
169
|
Edit your Claude Desktop config:
|
|
148
170
|
- **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
@@ -153,14 +175,7 @@ Edit your Claude Desktop config:
|
|
|
153
175
|
"mcpServers": {
|
|
154
176
|
"semantic-chirp-intelligence-mcp": {
|
|
155
177
|
"command": "node",
|
|
156
|
-
"args": ["/absolute/path/to/semantic-chirp-intelligence-mcp/build/index.js"]
|
|
157
|
-
"env": {
|
|
158
|
-
"YAHOO_CLIENT_ID": "your_client_id",
|
|
159
|
-
"YAHOO_CLIENT_SECRET": "your_client_secret",
|
|
160
|
-
"YAHOO_LEAGUE_ID": "your_league_id",
|
|
161
|
-
"YAHOO_TEAM_ID": "your_team_id",
|
|
162
|
-
"DOTENV_CONFIG_QUIET": "true"
|
|
163
|
-
}
|
|
178
|
+
"args": ["/absolute/path/to/semantic-chirp-intelligence-mcp/build/index.js"]
|
|
164
179
|
}
|
|
165
180
|
}
|
|
166
181
|
}
|
|
@@ -168,17 +183,23 @@ Edit your Claude Desktop config:
|
|
|
168
183
|
|
|
169
184
|
Use an **absolute path** to `build/index.js` (forward slashes, even on Windows). Restart Claude Desktop — the CHIRP tools will appear.
|
|
170
185
|
|
|
186
|
+
There is no `env` block, because there is nothing to configure. Your pasted
|
|
187
|
+
roster is stored in the project's git-ignored `.chirp-data/` and never leaves
|
|
188
|
+
your machine.
|
|
189
|
+
|
|
171
190
|
---
|
|
172
191
|
|
|
173
192
|
## Usage
|
|
174
193
|
|
|
175
194
|
Once connected, just talk to Claude about your team:
|
|
176
195
|
|
|
196
|
+
- *"I'm on the clock at pick 47 — who should I take?"*
|
|
197
|
+
- *"Which teams have the best schedule during my league's playoff weeks?"*
|
|
177
198
|
- *"Run ICE on my roster — what should I actually do this week?"*
|
|
178
199
|
- *"Where do I have a games-in-hand edge over my opponent?"*
|
|
179
200
|
- *"Find me streaming goalies for the weekend — real value, not desperation pickups."*
|
|
180
201
|
- *"Am I winning my matchup? Which categories am I losing?"*
|
|
181
|
-
- *"Who are the
|
|
202
|
+
- *"Who are the best players not on my roster right now?"*
|
|
182
203
|
- *"Show me the governance dashboard."*
|
|
183
204
|
|
|
184
205
|
---
|
|
@@ -191,6 +212,8 @@ npm run type-check # tsc --noEmit
|
|
|
191
212
|
npm test # run the vitest suite once
|
|
192
213
|
npm run test:watch # watch mode
|
|
193
214
|
npm run test:coverage
|
|
215
|
+
npm run preflight # build + NHL API reachability
|
|
216
|
+
npm run smoke # call every tool and flag crash-like responses
|
|
194
217
|
```
|
|
195
218
|
|
|
196
219
|
### Project structure
|
|
@@ -199,25 +222,48 @@ npm run test:coverage
|
|
|
199
222
|
semantic-chirp-intelligence-mcp/
|
|
200
223
|
├── src/
|
|
201
224
|
│ ├── index.ts # MCP server (stdio) + tool registration
|
|
202
|
-
│ ├── analyses/ # Template-Pattern analyses (Ice, Streaming, GamesInHand,
|
|
225
|
+
│ ├── analyses/ # Template-Pattern analyses (Ice, Streaming, GamesInHand,
|
|
226
|
+
│ │ # WeekendStream, Lineup, Breakout, ScheduleValue, DraftPick)
|
|
203
227
|
│ ├── template/ # AnalysisTemplate base
|
|
204
|
-
│ ├── services/ #
|
|
228
|
+
│ ├── services/ # NhlScheduleService, NhlStatsService, RosterStore,
|
|
229
|
+
│ │ # LeagueDataService, ChirpIntelligence
|
|
205
230
|
│ ├── config/ # tool-metadata, personality-modes, chirp-styles
|
|
206
|
-
│ ├── domain/ # types, governance
|
|
207
|
-
│ └── experimental/ # semantic-intent parser experiments
|
|
231
|
+
│ ├── domain/ # types, governance, nhl-teams
|
|
208
232
|
├── tests/ # vitest tests
|
|
209
|
-
├──
|
|
233
|
+
├── scripts/preflight.mjs # build + NHL API check
|
|
234
|
+
├── scripts/smoke.mjs # calls every tool, flags crash-like responses
|
|
210
235
|
├── docs/ # documentation (architecture, setup, dev notes)
|
|
211
|
-
└── .env.example
|
|
212
236
|
```
|
|
213
237
|
|
|
214
238
|
---
|
|
215
239
|
|
|
240
|
+
## Troubleshooting
|
|
241
|
+
|
|
242
|
+
**A name did not resolve**
|
|
243
|
+
`set_roster` reports every line it could not match to exactly one NHL player,
|
|
244
|
+
under `needs_attention`. Ambiguous surnames come back with their candidates —
|
|
245
|
+
give a full name and re-run. Nothing is ever guessed onto your roster.
|
|
246
|
+
|
|
247
|
+
**Tools say no roster has been provided**
|
|
248
|
+
Paste one with `set_roster`. `show_stored_data` shows what is currently stored.
|
|
249
|
+
|
|
250
|
+
**Game counts are zero**
|
|
251
|
+
Check the dates. Outside the regular season there are genuinely no games to count;
|
|
252
|
+
`schedule_value` still works year-round because it reads the whole published season.
|
|
253
|
+
|
|
254
|
+
**Stats look like last season**
|
|
255
|
+
They are. Before opening night the current season has no statistics at all, so
|
|
256
|
+
CHIRP attaches the last completed season — which is the right basis at a draft.
|
|
257
|
+
Every response names the season it used.
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
216
261
|
## Security
|
|
217
262
|
|
|
218
|
-
- **
|
|
219
|
-
- **
|
|
220
|
-
- **
|
|
263
|
+
- **No credentials at all** — v4 holds no API keys, tokens or account bindings. There is nothing to leak.
|
|
264
|
+
- **Read-only** — the only network calls are GETs to the NHL's public API. CHIRP cannot modify a roster anywhere.
|
|
265
|
+
- **Local-only** — runs over stdio. Your pasted roster stays in `.chirp-data/` on your machine and is git-ignored.
|
|
266
|
+
- See [SECURITY.md](./SECURITY.md) for the full policy.
|
|
221
267
|
|
|
222
268
|
## Part of Cormorant Foraging
|
|
223
269
|
|
|
@@ -242,7 +288,7 @@ Contributions welcome — see [CONTRIBUTING.md](./CONTRIBUTING.md) and the [Code
|
|
|
242
288
|
## Acknowledgments
|
|
243
289
|
|
|
244
290
|
- [Model Context Protocol](https://modelcontextprotocol.io) by Anthropic
|
|
245
|
-
- [
|
|
291
|
+
- [NHL public API](https://api-web.nhle.com) — schedules, rosters, statistics and standings, free and unauthenticated
|
|
246
292
|
- Sibling project: [`semantic-wake-intelligence-mcp`](https://github.com/semanticintent/semantic-wake-intelligence-mcp)
|
|
247
293
|
|
|
248
294
|
---
|
|
@@ -12,42 +12,25 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import { AnalysisTemplate } from '../template/AnalysisTemplate.js';
|
|
14
14
|
import { ChirpIntelligence } from '../services/ChirpIntelligence.js';
|
|
15
|
+
import { LEAGUE_DATA, LeagueDataService } from '../services/LeagueDataService.js';
|
|
16
|
+
import { NHL_STATS } from '../services/NhlStatsService.js';
|
|
17
|
+
import { NHL_SCHEDULE } from '../services/NhlScheduleService.js';
|
|
15
18
|
export class BreakoutAnalysis extends AnalysisTemplate {
|
|
16
|
-
|
|
17
|
-
leagueId;
|
|
18
|
-
teamId;
|
|
19
|
-
constructor(yahooClient, leagueId, teamId) {
|
|
19
|
+
constructor() {
|
|
20
20
|
super('get_breakout_analysis', 'streaming_recommendations');
|
|
21
|
-
this.yahooClient = yahooClient;
|
|
22
|
-
this.leagueId = leagueId;
|
|
23
|
-
this.teamId = teamId;
|
|
24
21
|
}
|
|
25
22
|
/**
|
|
26
23
|
* Fetch raw data: free agents, trending players, roster
|
|
27
24
|
*/
|
|
28
25
|
async fetchData(args) {
|
|
29
|
-
|
|
30
|
-
//
|
|
31
|
-
|
|
32
|
-
const freeAgentPromises = positions.map(pos => this.yahooClient.searchPlayers(pos, 50, this.leagueId));
|
|
33
|
-
const [freeAgentResults, trendingAdds, roster] = await Promise.all([
|
|
34
|
-
Promise.all(freeAgentPromises),
|
|
35
|
-
this.yahooClient.getTrendingPlayers('add', 25, this.leagueId),
|
|
36
|
-
this.yahooClient.getTeamRoster(this.leagueId, this.teamId)
|
|
37
|
-
]);
|
|
38
|
-
// Combine and deduplicate free agents
|
|
39
|
-
const allFreeAgents = [];
|
|
40
|
-
for (const result of freeAgentResults) {
|
|
41
|
-
if (result.players) {
|
|
42
|
-
allFreeAgents.push(...result.players);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
// Remove duplicates and filter by ownership
|
|
46
|
-
const uniqueFreeAgents = Array.from(new Map(allFreeAgents.map(p => [p.player_id, p])).values()).filter(p => (p.percent_owned || 0) < ownershipThreshold);
|
|
26
|
+
await Promise.all([NHL_STATS.load(), NHL_SCHEDULE.load()]);
|
|
27
|
+
// Breakout candidates are drawn from every NHL player not already on a
|
|
28
|
+
// roster you provided, scored on their real season line.
|
|
47
29
|
return {
|
|
48
|
-
freeAgents:
|
|
49
|
-
trendingAdds:
|
|
50
|
-
roster
|
|
30
|
+
freeAgents: LEAGUE_DATA.getPlayerPool({ limit: 200 }),
|
|
31
|
+
trendingAdds: [],
|
|
32
|
+
roster: LEAGUE_DATA.getRoster(),
|
|
33
|
+
pool_caveat: LeagueDataService.POOL_CAVEAT
|
|
51
34
|
};
|
|
52
35
|
}
|
|
53
36
|
/**
|
|
@@ -228,17 +211,23 @@ export class BreakoutAnalysis extends AnalysisTemplate {
|
|
|
228
211
|
return 'sleeper';
|
|
229
212
|
}
|
|
230
213
|
/**
|
|
231
|
-
*
|
|
214
|
+
* Real season stat line for a candidate, from Yahoo.
|
|
215
|
+
*
|
|
216
|
+
* Missing categories come back as 0 rather than absent so the scoring
|
|
217
|
+
* formula keeps its shape; `has_stats` distinguishes a genuine zero from a
|
|
218
|
+
* player Yahoo returned nothing for.
|
|
232
219
|
*/
|
|
233
220
|
async getPlayerMetrics(player) {
|
|
234
|
-
//
|
|
235
|
-
|
|
221
|
+
// v4: the pool carries NHL season statistics on each player already.
|
|
222
|
+
const stats = player.stats ?? null;
|
|
236
223
|
return {
|
|
237
|
-
G:
|
|
238
|
-
A:
|
|
239
|
-
GP:
|
|
240
|
-
|
|
241
|
-
|
|
224
|
+
G: stats?.goals ?? 0,
|
|
225
|
+
A: stats?.assists ?? 0,
|
|
226
|
+
GP: stats?.games_played ?? 0,
|
|
227
|
+
// The NHL feed publishes power-play goals, not power-play points.
|
|
228
|
+
PPP: stats?.power_play_goals ?? 0,
|
|
229
|
+
SOG: stats?.shots ?? 0,
|
|
230
|
+
has_stats: Boolean(stats)
|
|
242
231
|
};
|
|
243
232
|
}
|
|
244
233
|
/**
|