@claudinho/cli 0.1.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.
Files changed (4) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +103 -0
  3. package/dist/index.js +3459 -0
  4. package/package.json +55 -0
package/dist/index.js ADDED
@@ -0,0 +1,3459 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/index.ts
4
+ import { Command } from "commander";
5
+
6
+ // src/config.ts
7
+ var SUPPORTED_LANGS = ["en", "es", "pt", "fr"];
8
+ function pickLang(explicit) {
9
+ const candidates = [
10
+ explicit,
11
+ process.env.CLAUDINHO_LANG,
12
+ process.env.LANG?.split(".")[0]?.split("_")[0]
13
+ ];
14
+ for (const c of candidates) {
15
+ if (c && SUPPORTED_LANGS.includes(c)) {
16
+ return c;
17
+ }
18
+ }
19
+ return "en";
20
+ }
21
+ function pickColor(explicit) {
22
+ if (explicit === false) return false;
23
+ if (process.env.NO_COLOR) return false;
24
+ if (!process.stdout.isTTY) return false;
25
+ return true;
26
+ }
27
+ function isSupportedLang(s) {
28
+ return SUPPORTED_LANGS.includes(s);
29
+ }
30
+ function resolveConfig(opts) {
31
+ const langRequestedUnsupported = opts.lang && !isSupportedLang(opts.lang) ? opts.lang : void 0;
32
+ return {
33
+ lang: pickLang(opts.lang),
34
+ tz: opts.tz ?? process.env.CLAUDINHO_TZ ?? void 0,
35
+ json: opts.json ?? false,
36
+ color: pickColor(opts.color),
37
+ source: opts.source ?? process.env.CLAUDINHO_SOURCE ?? "espn",
38
+ langRequestedUnsupported
39
+ };
40
+ }
41
+
42
+ // src/i18n.ts
43
+ var EN = {
44
+ "today.title": "Today's matches",
45
+ "today.on": "Matches",
46
+ "today.none": "No matches scheduled for this date.",
47
+ "live.title": "Live now",
48
+ "live.none": "No matches in play right now.",
49
+ "next.none": "No upcoming fixture found for {team}.",
50
+ "next.label": "Next up for {team}",
51
+ "next.in": "in {countdown}",
52
+ "table.title": "Group {group}",
53
+ "table.none": "No group found for {group}.",
54
+ "match.none": "No match found with id {id}.",
55
+ "status.scheduled": "scheduled",
56
+ "status.live": "LIVE",
57
+ "status.ht": "HT",
58
+ "status.ft": "FT",
59
+ "status.postponed": "postponed",
60
+ "status.cancelled": "cancelled",
61
+ "col.team": "Team",
62
+ "col.p": "P",
63
+ "col.w": "W",
64
+ "col.d": "D",
65
+ "col.l": "L",
66
+ "col.gd": "GD",
67
+ "col.pts": "Pts",
68
+ "err.date": "Invalid date {date}. Use YYYY-MM-DD.",
69
+ "warn.tz": "Unknown timezone {tz}; using system timezone.",
70
+ "warn.lang": "Unsupported language {lang}; using English. (supported: en, es, pt, fr)",
71
+ disclaimer: "Not affiliated with FIFA or Anthropic. Data: ESPN."
72
+ };
73
+ var ES = {
74
+ "today.title": "Partidos de hoy",
75
+ "today.on": "Partidos",
76
+ "today.none": "No hay partidos para esta fecha.",
77
+ "live.title": "En vivo",
78
+ "live.none": "No hay partidos en juego ahora mismo.",
79
+ "next.none": "No se encontr\xF3 pr\xF3ximo partido para {team}.",
80
+ "next.label": "Pr\xF3ximo de {team}",
81
+ "next.in": "en {countdown}",
82
+ "table.title": "Grupo {group}",
83
+ "table.none": "No se encontr\xF3 el grupo {group}.",
84
+ "match.none": "No se encontr\xF3 partido con id {id}.",
85
+ "status.scheduled": "programado",
86
+ "status.live": "EN VIVO",
87
+ "status.ht": "DESC",
88
+ "status.ft": "FIN",
89
+ "status.postponed": "aplazado",
90
+ "status.cancelled": "cancelado",
91
+ "col.team": "Equipo",
92
+ "col.p": "PJ",
93
+ "col.w": "G",
94
+ "col.d": "E",
95
+ "col.l": "P",
96
+ "col.gd": "DG",
97
+ "col.pts": "Pts",
98
+ "err.date": "Fecha inv\xE1lida {date}. Usa AAAA-MM-DD.",
99
+ "warn.tz": "Zona horaria desconocida {tz}; usando la del sistema.",
100
+ "warn.lang": "Idioma no soportado {lang}; usando ingl\xE9s. (disponibles: en, es, pt, fr)",
101
+ disclaimer: "No afiliado a FIFA ni Anthropic. Datos: ESPN."
102
+ };
103
+ var PT = {
104
+ "today.title": "Jogos de hoje",
105
+ "today.on": "Jogos",
106
+ "today.none": "Nenhum jogo para esta data.",
107
+ "live.title": "Ao vivo",
108
+ "live.none": "Nenhum jogo em andamento agora.",
109
+ "next.none": "Nenhum pr\xF3ximo jogo encontrado para {team}.",
110
+ "next.label": "Pr\xF3ximo de {team}",
111
+ "next.in": "em {countdown}",
112
+ "table.title": "Grupo {group}",
113
+ "table.none": "Grupo {group} n\xE3o encontrado.",
114
+ "match.none": "Nenhum jogo encontrado com id {id}.",
115
+ "status.scheduled": "agendado",
116
+ "status.live": "AO VIVO",
117
+ "status.ht": "INT",
118
+ "status.ft": "FIM",
119
+ "status.postponed": "adiado",
120
+ "status.cancelled": "cancelado",
121
+ "col.team": "Sele\xE7\xE3o",
122
+ "col.p": "J",
123
+ "col.w": "V",
124
+ "col.d": "E",
125
+ "col.l": "D",
126
+ "col.gd": "SG",
127
+ "col.pts": "Pts",
128
+ "err.date": "Data inv\xE1lida {date}. Use AAAA-MM-DD.",
129
+ "warn.tz": "Fuso hor\xE1rio desconhecido {tz}; usando o do sistema.",
130
+ "warn.lang": "Idioma n\xE3o suportado {lang}; usando ingl\xEAs. (dispon\xEDveis: en, es, pt, fr)",
131
+ disclaimer: "N\xE3o afiliado \xE0 FIFA nem \xE0 Anthropic. Dados: ESPN."
132
+ };
133
+ var FR = {
134
+ "today.title": "Matchs d'aujourd'hui",
135
+ "today.on": "Matchs",
136
+ "today.none": "Aucun match pr\xE9vu pour cette date.",
137
+ "live.title": "En direct",
138
+ "live.none": "Aucun match en cours pour l'instant.",
139
+ "next.none": "Aucun prochain match trouv\xE9 pour {team}.",
140
+ "next.label": "Prochain match de {team}",
141
+ "next.in": "dans {countdown}",
142
+ "table.title": "Groupe {group}",
143
+ "table.none": "Groupe {group} introuvable.",
144
+ "match.none": "Aucun match trouv\xE9 avec id {id}.",
145
+ "status.scheduled": "pr\xE9vu",
146
+ "status.live": "DIRECT",
147
+ "status.ht": "MT",
148
+ "status.ft": "FIN",
149
+ "status.postponed": "report\xE9",
150
+ "status.cancelled": "annul\xE9",
151
+ "col.team": "\xC9quipe",
152
+ "col.p": "J",
153
+ "col.w": "G",
154
+ "col.d": "N",
155
+ "col.l": "P",
156
+ "col.gd": "Diff",
157
+ "col.pts": "Pts",
158
+ "err.date": "Date invalide {date}. Utilisez AAAA-MM-JJ.",
159
+ "warn.tz": "Fuseau horaire inconnu {tz} ; utilisation du fuseau syst\xE8me.",
160
+ "warn.lang": "Langue non prise en charge {lang} ; utilisation de l\u2019anglais. (disponibles : en, es, pt, fr)",
161
+ disclaimer: "Non affili\xE9 \xE0 la FIFA ni \xE0 Anthropic. Donn\xE9es : ESPN."
162
+ };
163
+ var CATALOGS = { en: EN, es: ES, pt: PT, fr: FR };
164
+ function makeT(lang) {
165
+ const dict = CATALOGS[lang] ?? EN;
166
+ return (key, vars) => {
167
+ let s = dict[key] ?? EN[key] ?? key;
168
+ if (vars) for (const [k, v] of Object.entries(vars)) s = s.replace(`{${k}}`, v);
169
+ return s;
170
+ };
171
+ }
172
+
173
+ // ../core/dist/index.js
174
+ var REGIONAL_INDICATOR_A = 127462;
175
+ var TAG_BASE = 917504;
176
+ var TAG_CANCEL = 917631;
177
+ var BLACK_FLAG = 127988;
178
+ var NEUTRAL = "\u{1F3F3}\uFE0F";
179
+ function norm(s) {
180
+ return s.toLowerCase().normalize("NFD").replace(/[̀-ͯ]/g, "").replace(/[^a-z]/g, "");
181
+ }
182
+ function subdivisionFlag(lettersOnly) {
183
+ const tags = [...lettersOnly].map((c) => TAG_BASE + c.charCodeAt(0));
184
+ return String.fromCodePoint(BLACK_FLAG, ...tags, TAG_CANCEL);
185
+ }
186
+ function flagEmoji(region) {
187
+ const r = region.trim();
188
+ if (r.includes("-")) {
189
+ const letters = r.toLowerCase().replace(/-/g, "");
190
+ return subdivisionFlag(letters);
191
+ }
192
+ const cc = r.toUpperCase();
193
+ if (!/^[A-Z]{2}$/.test(cc)) return NEUTRAL;
194
+ return String.fromCodePoint(
195
+ REGIONAL_INDICATOR_A + (cc.charCodeAt(0) - 65),
196
+ REGIONAL_INDICATOR_A + (cc.charCodeAt(1) - 65)
197
+ );
198
+ }
199
+ var NATIONS = [
200
+ ["Mexico", "MX"],
201
+ ["South Africa", "ZA"],
202
+ ["South Korea", "KR"],
203
+ ["Czechia", "CZ"],
204
+ ["Canada", "CA"],
205
+ ["Bosnia-Herzegovina", "BA"],
206
+ ["United States", "US"],
207
+ ["Paraguay", "PY"],
208
+ ["Qatar", "QA"],
209
+ ["Switzerland", "CH"],
210
+ ["Brazil", "BR"],
211
+ ["Morocco", "MA"],
212
+ ["Haiti", "HT"],
213
+ ["Scotland", "GB-SCT"],
214
+ ["Australia", "AU"],
215
+ ["T\xFCrkiye", "TR"],
216
+ ["Germany", "DE"],
217
+ ["Curacao", "CW"],
218
+ ["Netherlands", "NL"],
219
+ ["Japan", "JP"],
220
+ ["Ivory Coast", "CI"],
221
+ ["Ecuador", "EC"],
222
+ ["Sweden", "SE"],
223
+ ["Tunisia", "TN"],
224
+ ["Argentina", "AR"],
225
+ ["France", "FR"],
226
+ ["Spain", "ES"],
227
+ ["Portugal", "PT"],
228
+ ["England", "GB-ENG"],
229
+ ["Wales", "GB-WLS"],
230
+ ["Belgium", "BE"],
231
+ ["Croatia", "HR"],
232
+ ["Uruguay", "UY"],
233
+ ["Colombia", "CO"],
234
+ ["Senegal", "SN"],
235
+ ["Iran", "IR"],
236
+ ["Saudi Arabia", "SA"],
237
+ ["Egypt", "EG"],
238
+ ["Nigeria", "NG"],
239
+ ["Ghana", "GH"],
240
+ ["Cameroon", "CM"],
241
+ ["Algeria", "DZ"],
242
+ ["Norway", "NO"],
243
+ ["Denmark", "DK"],
244
+ ["Austria", "AT"],
245
+ ["Poland", "PL"],
246
+ ["Italy", "IT"],
247
+ ["Serbia", "RS"],
248
+ ["Panama", "PA"],
249
+ ["Costa Rica", "CR"],
250
+ ["Jordan", "JO"],
251
+ ["Uzbekistan", "UZ"],
252
+ ["New Zealand", "NZ"],
253
+ ["Cape Verde", "CV"],
254
+ ["Jamaica", "JM"],
255
+ ["Peru", "PE"],
256
+ ["Chile", "CL"],
257
+ ["Honduras", "HN"],
258
+ ["DR Congo", "CD"],
259
+ ["Mali", "ML"],
260
+ ["Venezuela", "VE"],
261
+ ["Greece", "GR"],
262
+ ["Hungary", "HU"],
263
+ ["Slovenia", "SI"],
264
+ ["Slovakia", "SK"],
265
+ ["Romania", "RO"],
266
+ ["Ukraine", "UA"],
267
+ ["Angola", "AO"],
268
+ ["Benin", "BJ"],
269
+ ["Gabon", "GA"],
270
+ ["Bolivia", "BO"],
271
+ ["Guinea", "GN"],
272
+ ["Burkina Faso", "BF"],
273
+ ["Zambia", "ZM"],
274
+ ["Iraq", "IQ"],
275
+ ["United Arab Emirates", "AE"],
276
+ ["Oman", "OM"],
277
+ ["Bahrain", "BH"],
278
+ ["China", "CN"],
279
+ ["Indonesia", "ID"],
280
+ ["Thailand", "TH"],
281
+ ["Vietnam", "VN"],
282
+ ["India", "IN"],
283
+ ["Russia", "RU"],
284
+ ["Finland", "FI"],
285
+ ["Ireland", "IE"],
286
+ ["Northern Ireland", "GB-NIR"],
287
+ ["Iceland", "IS"],
288
+ ["Albania", "AL"],
289
+ ["Georgia", "GE"],
290
+ ["North Macedonia", "MK"],
291
+ ["Montenegro", "ME"],
292
+ ["Kosovo", "XK"]
293
+ ];
294
+ var ALIASES = [
295
+ ["Turkey", "TR"],
296
+ ["Korea Republic", "KR"],
297
+ ["Republic of Korea", "KR"],
298
+ ["Korea DPR", "KP"],
299
+ ["North Korea", "KP"],
300
+ ["Czech Republic", "CZ"],
301
+ ["Cote d'Ivoire", "CI"],
302
+ ["Cote dIvoire", "CI"],
303
+ ["C\xF4te d\u2019Ivoire", "CI"],
304
+ ["Bosnia and Herzegovina", "BA"],
305
+ ["Bosnia", "BA"],
306
+ ["USA", "US"],
307
+ ["United States of America", "US"],
308
+ ["US", "US"],
309
+ ["Cabo Verde", "CV"],
310
+ ["Congo DR", "CD"],
311
+ ["Democratic Republic of the Congo", "CD"],
312
+ ["IR Iran", "IR"],
313
+ ["Cura\xE7ao", "CW"],
314
+ ["Holland", "NL"],
315
+ ["Republic of Ireland", "IE"],
316
+ ["UAE", "AE"],
317
+ // Names where Intl's English label differs from the common short form.
318
+ ["Hong Kong", "HK"],
319
+ ["Myanmar", "MM"],
320
+ ["Palestine", "PS"],
321
+ ["Burma", "MM"],
322
+ ["Cape Verde", "CV"]
323
+ ];
324
+ var BY_NATION = Object.fromEntries(
325
+ [...NATIONS, ...ALIASES].map(([name, code]) => [norm(name), code])
326
+ );
327
+ var BY_CODE = {
328
+ MEX: "MX",
329
+ RSA: "ZA",
330
+ KOR: "KR",
331
+ CZE: "CZ",
332
+ CAN: "CA",
333
+ BIH: "BA",
334
+ USA: "US",
335
+ PAR: "PY",
336
+ QAT: "QA",
337
+ SUI: "CH",
338
+ BRA: "BR",
339
+ MAR: "MA",
340
+ HAI: "HT",
341
+ SCO: "GB-SCT",
342
+ AUS: "AU",
343
+ TUR: "TR",
344
+ GER: "DE",
345
+ CUW: "CW",
346
+ NED: "NL",
347
+ JPN: "JP",
348
+ CIV: "CI",
349
+ ECU: "EC",
350
+ SWE: "SE",
351
+ TUN: "TN",
352
+ ARG: "AR",
353
+ FRA: "FR",
354
+ ESP: "ES",
355
+ POR: "PT",
356
+ ENG: "GB-ENG",
357
+ WAL: "GB-WLS",
358
+ BEL: "BE",
359
+ CRO: "HR",
360
+ URU: "UY",
361
+ COL: "CO",
362
+ SEN: "SN",
363
+ IRN: "IR",
364
+ KSA: "SA",
365
+ EGY: "EG",
366
+ NGA: "NG",
367
+ GHA: "GH",
368
+ CMR: "CM",
369
+ ALG: "DZ",
370
+ NOR: "NO",
371
+ DEN: "DK",
372
+ AUT: "AT",
373
+ POL: "PL",
374
+ ITA: "IT",
375
+ SRB: "RS",
376
+ PAN: "PA",
377
+ CRC: "CR",
378
+ JOR: "JO",
379
+ UZB: "UZ",
380
+ NZL: "NZ",
381
+ CPV: "CV",
382
+ JAM: "JM",
383
+ PER: "PE",
384
+ CHI: "CL",
385
+ HON: "HN",
386
+ COD: "CD",
387
+ MLI: "ML"
388
+ };
389
+ function nationToFlag(nameOrCode) {
390
+ const region = nationToRegion(nameOrCode);
391
+ return region ? flagEmoji(region) : NEUTRAL;
392
+ }
393
+ var INTL_BY_NAME;
394
+ function intlNameMap() {
395
+ if (INTL_BY_NAME) return INTL_BY_NAME;
396
+ const map = {};
397
+ try {
398
+ const dn = new Intl.DisplayNames(["en"], { type: "region" });
399
+ for (let a = 65; a <= 90; a++) {
400
+ for (let b = 65; b <= 90; b++) {
401
+ const code = String.fromCharCode(a, b);
402
+ let name;
403
+ try {
404
+ name = dn.of(code);
405
+ } catch {
406
+ name = void 0;
407
+ }
408
+ if (name && name !== code) {
409
+ const key = norm(name);
410
+ if (!(key in map)) map[key] = code;
411
+ }
412
+ }
413
+ }
414
+ } catch {
415
+ }
416
+ INTL_BY_NAME = map;
417
+ return map;
418
+ }
419
+ function nationToRegion(nameOrCode) {
420
+ if (!nameOrCode) return void 0;
421
+ const byName = BY_NATION[norm(nameOrCode)];
422
+ if (byName) return byName;
423
+ const byCode = BY_CODE[nameOrCode.trim().toUpperCase()];
424
+ if (byCode) return byCode;
425
+ return intlNameMap()[norm(nameOrCode)];
426
+ }
427
+ function isValidTimeZone(tz) {
428
+ if (!tz) return false;
429
+ try {
430
+ new Intl.DateTimeFormat("en", { timeZone: tz });
431
+ return true;
432
+ } catch {
433
+ return false;
434
+ }
435
+ }
436
+ function isValidDate(s) {
437
+ if (!s || !/^\d{4}-\d{2}-\d{2}$/.test(s)) return false;
438
+ const d = /* @__PURE__ */ new Date(`${s}T00:00:00Z`);
439
+ if (Number.isNaN(d.getTime())) return false;
440
+ return d.toISOString().slice(0, 10) === s;
441
+ }
442
+ function envTz() {
443
+ if (typeof process !== "undefined" && process.env && process.env.CLAUDINHO_TZ) {
444
+ return process.env.CLAUDINHO_TZ;
445
+ }
446
+ return void 0;
447
+ }
448
+ function systemTz() {
449
+ try {
450
+ return Intl.DateTimeFormat().resolvedOptions().timeZone;
451
+ } catch {
452
+ return void 0;
453
+ }
454
+ }
455
+ function resolveTz(explicit) {
456
+ if (explicit && isValidTimeZone(explicit)) return explicit;
457
+ const fromEnv = envTz();
458
+ if (fromEnv && isValidTimeZone(fromEnv)) return fromEnv;
459
+ return systemTz();
460
+ }
461
+ function formatKickoff(iso, opts = {}) {
462
+ const tz = resolveTz(opts.tz);
463
+ const locale = opts.locale || "en";
464
+ return new Intl.DateTimeFormat(locale, {
465
+ weekday: "short",
466
+ hour: "2-digit",
467
+ minute: "2-digit",
468
+ hour12: false,
469
+ timeZone: tz
470
+ }).format(new Date(iso));
471
+ }
472
+ function countdown(iso, from = /* @__PURE__ */ new Date()) {
473
+ const ms = new Date(iso).getTime() - from.getTime();
474
+ if (ms <= 0) return "now";
475
+ const totalMin = Math.floor(ms / 6e4);
476
+ const days = Math.floor(totalMin / 1440);
477
+ const hours = Math.floor(totalMin % 1440 / 60);
478
+ const mins = totalMin % 60;
479
+ if (days > 0) return `${days}d${hours}h`;
480
+ if (hours > 0) return `${hours}h${mins}m`;
481
+ return `${mins}m`;
482
+ }
483
+ function localDate(iso, tz) {
484
+ const zone = resolveTz(tz);
485
+ return new Intl.DateTimeFormat("en-CA", {
486
+ year: "numeric",
487
+ month: "2-digit",
488
+ day: "2-digit",
489
+ timeZone: zone
490
+ }).format(new Date(iso));
491
+ }
492
+ function isLive(status) {
493
+ return status === "LIVE" || status === "HT";
494
+ }
495
+ function isFinished(status) {
496
+ return status === "FT";
497
+ }
498
+ function scoreline(match) {
499
+ if (!match.score) return "vs";
500
+ return `${match.score.home}\u2013${match.score.away}`;
501
+ }
502
+ function byKickoff(a, b) {
503
+ return a.kickoff.localeCompare(b.kickoff);
504
+ }
505
+ var schedule_2026_default = [
506
+ {
507
+ id: "760415",
508
+ stage: "GROUP",
509
+ group: "A",
510
+ kickoff: "2026-06-11T19:00Z",
511
+ venue: "Estadio Banorte",
512
+ home: {
513
+ code: "MEX",
514
+ name: "Mexico",
515
+ flag: "\u{1F1F2}\u{1F1FD}"
516
+ },
517
+ away: {
518
+ code: "RSA",
519
+ name: "South Africa",
520
+ flag: "\u{1F1FF}\u{1F1E6}"
521
+ },
522
+ status: "SCHEDULED",
523
+ updatedAt: "2026-05-31T08:32:53.559Z"
524
+ },
525
+ {
526
+ id: "760414",
527
+ stage: "GROUP",
528
+ group: "A",
529
+ kickoff: "2026-06-12T02:00Z",
530
+ venue: "Estadio Akron",
531
+ home: {
532
+ code: "KOR",
533
+ name: "South Korea",
534
+ flag: "\u{1F1F0}\u{1F1F7}"
535
+ },
536
+ away: {
537
+ code: "CZE",
538
+ name: "Czechia",
539
+ flag: "\u{1F1E8}\u{1F1FF}"
540
+ },
541
+ status: "SCHEDULED",
542
+ updatedAt: "2026-05-31T08:32:53.560Z"
543
+ },
544
+ {
545
+ id: "760416",
546
+ stage: "GROUP",
547
+ group: "B",
548
+ kickoff: "2026-06-12T19:00Z",
549
+ venue: "BMO Field",
550
+ home: {
551
+ code: "CAN",
552
+ name: "Canada",
553
+ flag: "\u{1F1E8}\u{1F1E6}"
554
+ },
555
+ away: {
556
+ code: "BIH",
557
+ name: "Bosnia-Herzegovina",
558
+ flag: "\u{1F1E7}\u{1F1E6}"
559
+ },
560
+ status: "SCHEDULED",
561
+ updatedAt: "2026-05-31T08:32:53.560Z"
562
+ },
563
+ {
564
+ id: "760417",
565
+ stage: "GROUP",
566
+ group: "D",
567
+ kickoff: "2026-06-13T01:00Z",
568
+ venue: "SoFi Stadium",
569
+ home: {
570
+ code: "USA",
571
+ name: "United States",
572
+ flag: "\u{1F1FA}\u{1F1F8}"
573
+ },
574
+ away: {
575
+ code: "PAR",
576
+ name: "Paraguay",
577
+ flag: "\u{1F1F5}\u{1F1FE}"
578
+ },
579
+ status: "SCHEDULED",
580
+ updatedAt: "2026-05-31T08:32:53.560Z"
581
+ },
582
+ {
583
+ id: "760420",
584
+ stage: "GROUP",
585
+ group: "B",
586
+ kickoff: "2026-06-13T19:00Z",
587
+ venue: "Levi's Stadium",
588
+ home: {
589
+ code: "QAT",
590
+ name: "Qatar",
591
+ flag: "\u{1F1F6}\u{1F1E6}"
592
+ },
593
+ away: {
594
+ code: "SUI",
595
+ name: "Switzerland",
596
+ flag: "\u{1F1E8}\u{1F1ED}"
597
+ },
598
+ status: "SCHEDULED",
599
+ updatedAt: "2026-05-31T08:32:53.560Z"
600
+ },
601
+ {
602
+ id: "760419",
603
+ stage: "GROUP",
604
+ group: "C",
605
+ kickoff: "2026-06-13T22:00Z",
606
+ venue: "MetLife Stadium",
607
+ home: {
608
+ code: "BRA",
609
+ name: "Brazil",
610
+ flag: "\u{1F1E7}\u{1F1F7}"
611
+ },
612
+ away: {
613
+ code: "MAR",
614
+ name: "Morocco",
615
+ flag: "\u{1F1F2}\u{1F1E6}"
616
+ },
617
+ status: "SCHEDULED",
618
+ updatedAt: "2026-05-31T08:32:53.560Z"
619
+ },
620
+ {
621
+ id: "760418",
622
+ stage: "GROUP",
623
+ group: "C",
624
+ kickoff: "2026-06-14T01:00Z",
625
+ venue: "Gillette Stadium",
626
+ home: {
627
+ code: "HAI",
628
+ name: "Haiti",
629
+ flag: "\u{1F1ED}\u{1F1F9}"
630
+ },
631
+ away: {
632
+ code: "SCO",
633
+ name: "Scotland",
634
+ flag: "\u{1F3F4}\u{E0067}\u{E0062}\u{E0073}\u{E0063}\u{E0074}\u{E007F}"
635
+ },
636
+ status: "SCHEDULED",
637
+ updatedAt: "2026-05-31T08:32:53.560Z"
638
+ },
639
+ {
640
+ id: "760421",
641
+ stage: "GROUP",
642
+ group: "D",
643
+ kickoff: "2026-06-14T04:00Z",
644
+ venue: "BC Place",
645
+ home: {
646
+ code: "AUS",
647
+ name: "Australia",
648
+ flag: "\u{1F1E6}\u{1F1FA}"
649
+ },
650
+ away: {
651
+ code: "TUR",
652
+ name: "T\xFCrkiye",
653
+ flag: "\u{1F1F9}\u{1F1F7}"
654
+ },
655
+ status: "SCHEDULED",
656
+ updatedAt: "2026-05-31T08:32:53.560Z"
657
+ },
658
+ {
659
+ id: "760422",
660
+ stage: "GROUP",
661
+ group: "E",
662
+ kickoff: "2026-06-14T17:00Z",
663
+ venue: "NRG Stadium",
664
+ home: {
665
+ code: "GER",
666
+ name: "Germany",
667
+ flag: "\u{1F1E9}\u{1F1EA}"
668
+ },
669
+ away: {
670
+ code: "CUW",
671
+ name: "Curacao",
672
+ flag: "\u{1F1E8}\u{1F1FC}"
673
+ },
674
+ status: "SCHEDULED",
675
+ updatedAt: "2026-05-31T08:32:53.560Z"
676
+ },
677
+ {
678
+ id: "760425",
679
+ stage: "GROUP",
680
+ group: "F",
681
+ kickoff: "2026-06-14T20:00Z",
682
+ venue: "AT&T Stadium",
683
+ home: {
684
+ code: "NED",
685
+ name: "Netherlands",
686
+ flag: "\u{1F1F3}\u{1F1F1}"
687
+ },
688
+ away: {
689
+ code: "JPN",
690
+ name: "Japan",
691
+ flag: "\u{1F1EF}\u{1F1F5}"
692
+ },
693
+ status: "SCHEDULED",
694
+ updatedAt: "2026-05-31T08:32:53.560Z"
695
+ },
696
+ {
697
+ id: "760423",
698
+ stage: "GROUP",
699
+ group: "E",
700
+ kickoff: "2026-06-14T23:00Z",
701
+ venue: "Lincoln Financial Field",
702
+ home: {
703
+ code: "CIV",
704
+ name: "Ivory Coast",
705
+ flag: "\u{1F1E8}\u{1F1EE}"
706
+ },
707
+ away: {
708
+ code: "ECU",
709
+ name: "Ecuador",
710
+ flag: "\u{1F1EA}\u{1F1E8}"
711
+ },
712
+ status: "SCHEDULED",
713
+ updatedAt: "2026-05-31T08:32:53.560Z"
714
+ },
715
+ {
716
+ id: "760424",
717
+ stage: "GROUP",
718
+ group: "F",
719
+ kickoff: "2026-06-15T02:00Z",
720
+ venue: "Estadio BBVA",
721
+ home: {
722
+ code: "SWE",
723
+ name: "Sweden",
724
+ flag: "\u{1F1F8}\u{1F1EA}"
725
+ },
726
+ away: {
727
+ code: "TUN",
728
+ name: "Tunisia",
729
+ flag: "\u{1F1F9}\u{1F1F3}"
730
+ },
731
+ status: "SCHEDULED",
732
+ updatedAt: "2026-05-31T08:32:53.560Z"
733
+ },
734
+ {
735
+ id: "760428",
736
+ stage: "GROUP",
737
+ group: "H",
738
+ kickoff: "2026-06-15T16:00Z",
739
+ venue: "Mercedes-Benz Stadium",
740
+ home: {
741
+ code: "ESP",
742
+ name: "Spain",
743
+ flag: "\u{1F1EA}\u{1F1F8}"
744
+ },
745
+ away: {
746
+ code: "CPV",
747
+ name: "Cape Verde",
748
+ flag: "\u{1F1E8}\u{1F1FB}"
749
+ },
750
+ status: "SCHEDULED",
751
+ updatedAt: "2026-05-31T08:32:53.560Z"
752
+ },
753
+ {
754
+ id: "760426",
755
+ stage: "GROUP",
756
+ group: "G",
757
+ kickoff: "2026-06-15T19:00Z",
758
+ venue: "Lumen Field",
759
+ home: {
760
+ code: "BEL",
761
+ name: "Belgium",
762
+ flag: "\u{1F1E7}\u{1F1EA}"
763
+ },
764
+ away: {
765
+ code: "EGY",
766
+ name: "Egypt",
767
+ flag: "\u{1F1EA}\u{1F1EC}"
768
+ },
769
+ status: "SCHEDULED",
770
+ updatedAt: "2026-05-31T08:32:53.560Z"
771
+ },
772
+ {
773
+ id: "760429",
774
+ stage: "GROUP",
775
+ group: "H",
776
+ kickoff: "2026-06-15T22:00Z",
777
+ venue: "Hard Rock Stadium",
778
+ home: {
779
+ code: "KSA",
780
+ name: "Saudi Arabia",
781
+ flag: "\u{1F1F8}\u{1F1E6}"
782
+ },
783
+ away: {
784
+ code: "URU",
785
+ name: "Uruguay",
786
+ flag: "\u{1F1FA}\u{1F1FE}"
787
+ },
788
+ status: "SCHEDULED",
789
+ updatedAt: "2026-05-31T08:32:53.560Z"
790
+ },
791
+ {
792
+ id: "760427",
793
+ stage: "GROUP",
794
+ group: "G",
795
+ kickoff: "2026-06-16T01:00Z",
796
+ venue: "SoFi Stadium",
797
+ home: {
798
+ code: "IRN",
799
+ name: "Iran",
800
+ flag: "\u{1F1EE}\u{1F1F7}"
801
+ },
802
+ away: {
803
+ code: "NZL",
804
+ name: "New Zealand",
805
+ flag: "\u{1F1F3}\u{1F1FF}"
806
+ },
807
+ status: "SCHEDULED",
808
+ updatedAt: "2026-05-31T08:32:53.560Z"
809
+ },
810
+ {
811
+ id: "760432",
812
+ stage: "GROUP",
813
+ group: "I",
814
+ kickoff: "2026-06-16T19:00Z",
815
+ venue: "MetLife Stadium",
816
+ home: {
817
+ code: "FRA",
818
+ name: "France",
819
+ flag: "\u{1F1EB}\u{1F1F7}"
820
+ },
821
+ away: {
822
+ code: "SEN",
823
+ name: "Senegal",
824
+ flag: "\u{1F1F8}\u{1F1F3}"
825
+ },
826
+ status: "SCHEDULED",
827
+ updatedAt: "2026-05-31T08:32:53.560Z"
828
+ },
829
+ {
830
+ id: "760430",
831
+ stage: "GROUP",
832
+ group: "I",
833
+ kickoff: "2026-06-16T22:00Z",
834
+ venue: "Gillette Stadium",
835
+ home: {
836
+ code: "IRQ",
837
+ name: "Iraq",
838
+ flag: "\u{1F1EE}\u{1F1F6}"
839
+ },
840
+ away: {
841
+ code: "NOR",
842
+ name: "Norway",
843
+ flag: "\u{1F1F3}\u{1F1F4}"
844
+ },
845
+ status: "SCHEDULED",
846
+ updatedAt: "2026-05-31T08:32:53.560Z"
847
+ },
848
+ {
849
+ id: "760433",
850
+ stage: "GROUP",
851
+ group: "J",
852
+ kickoff: "2026-06-17T01:00Z",
853
+ venue: "GEHA Field at Arrowhead Stadium",
854
+ home: {
855
+ code: "ARG",
856
+ name: "Argentina",
857
+ flag: "\u{1F1E6}\u{1F1F7}"
858
+ },
859
+ away: {
860
+ code: "ALG",
861
+ name: "Algeria",
862
+ flag: "\u{1F1E9}\u{1F1FF}"
863
+ },
864
+ status: "SCHEDULED",
865
+ updatedAt: "2026-05-31T08:32:53.560Z"
866
+ },
867
+ {
868
+ id: "760431",
869
+ stage: "GROUP",
870
+ group: "J",
871
+ kickoff: "2026-06-17T04:00Z",
872
+ venue: "Levi's Stadium",
873
+ home: {
874
+ code: "AUT",
875
+ name: "Austria",
876
+ flag: "\u{1F1E6}\u{1F1F9}"
877
+ },
878
+ away: {
879
+ code: "JOR",
880
+ name: "Jordan",
881
+ flag: "\u{1F1EF}\u{1F1F4}"
882
+ },
883
+ status: "SCHEDULED",
884
+ updatedAt: "2026-05-31T08:32:53.560Z"
885
+ },
886
+ {
887
+ id: "760435",
888
+ stage: "GROUP",
889
+ group: "K",
890
+ kickoff: "2026-06-17T17:00Z",
891
+ venue: "NRG Stadium",
892
+ home: {
893
+ code: "POR",
894
+ name: "Portugal",
895
+ flag: "\u{1F1F5}\u{1F1F9}"
896
+ },
897
+ away: {
898
+ code: "COD",
899
+ name: "Congo DR",
900
+ flag: "\u{1F1E8}\u{1F1E9}"
901
+ },
902
+ status: "SCHEDULED",
903
+ updatedAt: "2026-05-31T08:32:53.560Z"
904
+ },
905
+ {
906
+ id: "760437",
907
+ stage: "GROUP",
908
+ group: "L",
909
+ kickoff: "2026-06-17T20:00Z",
910
+ venue: "AT&T Stadium",
911
+ home: {
912
+ code: "ENG",
913
+ name: "England",
914
+ flag: "\u{1F3F4}\u{E0067}\u{E0062}\u{E0065}\u{E006E}\u{E0067}\u{E007F}"
915
+ },
916
+ away: {
917
+ code: "CRO",
918
+ name: "Croatia",
919
+ flag: "\u{1F1ED}\u{1F1F7}"
920
+ },
921
+ status: "SCHEDULED",
922
+ updatedAt: "2026-05-31T08:32:53.560Z"
923
+ },
924
+ {
925
+ id: "760434",
926
+ stage: "GROUP",
927
+ group: "L",
928
+ kickoff: "2026-06-17T23:00Z",
929
+ venue: "BMO Field",
930
+ home: {
931
+ code: "GHA",
932
+ name: "Ghana",
933
+ flag: "\u{1F1EC}\u{1F1ED}"
934
+ },
935
+ away: {
936
+ code: "PAN",
937
+ name: "Panama",
938
+ flag: "\u{1F1F5}\u{1F1E6}"
939
+ },
940
+ status: "SCHEDULED",
941
+ updatedAt: "2026-05-31T08:32:53.560Z"
942
+ },
943
+ {
944
+ id: "760436",
945
+ stage: "GROUP",
946
+ group: "K",
947
+ kickoff: "2026-06-18T02:00Z",
948
+ venue: "Estadio Banorte",
949
+ home: {
950
+ code: "UZB",
951
+ name: "Uzbekistan",
952
+ flag: "\u{1F1FA}\u{1F1FF}"
953
+ },
954
+ away: {
955
+ code: "COL",
956
+ name: "Colombia",
957
+ flag: "\u{1F1E8}\u{1F1F4}"
958
+ },
959
+ status: "SCHEDULED",
960
+ updatedAt: "2026-05-31T08:32:53.560Z"
961
+ },
962
+ {
963
+ id: "760438",
964
+ stage: "GROUP",
965
+ group: "A",
966
+ kickoff: "2026-06-18T16:00Z",
967
+ venue: "Mercedes-Benz Stadium",
968
+ home: {
969
+ code: "CZE",
970
+ name: "Czechia",
971
+ flag: "\u{1F1E8}\u{1F1FF}"
972
+ },
973
+ away: {
974
+ code: "RSA",
975
+ name: "South Africa",
976
+ flag: "\u{1F1FF}\u{1F1E6}"
977
+ },
978
+ status: "SCHEDULED",
979
+ updatedAt: "2026-05-31T08:32:53.624Z"
980
+ },
981
+ {
982
+ id: "760439",
983
+ stage: "GROUP",
984
+ group: "B",
985
+ kickoff: "2026-06-18T19:00Z",
986
+ venue: "SoFi Stadium",
987
+ home: {
988
+ code: "SUI",
989
+ name: "Switzerland",
990
+ flag: "\u{1F1E8}\u{1F1ED}"
991
+ },
992
+ away: {
993
+ code: "BIH",
994
+ name: "Bosnia-Herzegovina",
995
+ flag: "\u{1F1E7}\u{1F1E6}"
996
+ },
997
+ status: "SCHEDULED",
998
+ updatedAt: "2026-05-31T08:32:53.624Z"
999
+ },
1000
+ {
1001
+ id: "760440",
1002
+ stage: "GROUP",
1003
+ group: "B",
1004
+ kickoff: "2026-06-18T22:00Z",
1005
+ venue: "BC Place",
1006
+ home: {
1007
+ code: "CAN",
1008
+ name: "Canada",
1009
+ flag: "\u{1F1E8}\u{1F1E6}"
1010
+ },
1011
+ away: {
1012
+ code: "QAT",
1013
+ name: "Qatar",
1014
+ flag: "\u{1F1F6}\u{1F1E6}"
1015
+ },
1016
+ status: "SCHEDULED",
1017
+ updatedAt: "2026-05-31T08:32:53.624Z"
1018
+ },
1019
+ {
1020
+ id: "760441",
1021
+ stage: "GROUP",
1022
+ group: "A",
1023
+ kickoff: "2026-06-19T01:00Z",
1024
+ venue: "Estadio Akron",
1025
+ home: {
1026
+ code: "MEX",
1027
+ name: "Mexico",
1028
+ flag: "\u{1F1F2}\u{1F1FD}"
1029
+ },
1030
+ away: {
1031
+ code: "KOR",
1032
+ name: "South Korea",
1033
+ flag: "\u{1F1F0}\u{1F1F7}"
1034
+ },
1035
+ status: "SCHEDULED",
1036
+ updatedAt: "2026-05-31T08:32:53.624Z"
1037
+ },
1038
+ {
1039
+ id: "760442",
1040
+ stage: "GROUP",
1041
+ group: "D",
1042
+ kickoff: "2026-06-19T19:00Z",
1043
+ venue: "Lumen Field",
1044
+ home: {
1045
+ code: "USA",
1046
+ name: "United States",
1047
+ flag: "\u{1F1FA}\u{1F1F8}"
1048
+ },
1049
+ away: {
1050
+ code: "AUS",
1051
+ name: "Australia",
1052
+ flag: "\u{1F1E6}\u{1F1FA}"
1053
+ },
1054
+ status: "SCHEDULED",
1055
+ updatedAt: "2026-05-31T08:32:53.624Z"
1056
+ },
1057
+ {
1058
+ id: "760445",
1059
+ stage: "GROUP",
1060
+ group: "C",
1061
+ kickoff: "2026-06-19T22:00Z",
1062
+ venue: "Gillette Stadium",
1063
+ home: {
1064
+ code: "SCO",
1065
+ name: "Scotland",
1066
+ flag: "\u{1F3F4}\u{E0067}\u{E0062}\u{E0073}\u{E0063}\u{E0074}\u{E007F}"
1067
+ },
1068
+ away: {
1069
+ code: "MAR",
1070
+ name: "Morocco",
1071
+ flag: "\u{1F1F2}\u{1F1E6}"
1072
+ },
1073
+ status: "SCHEDULED",
1074
+ updatedAt: "2026-05-31T08:32:53.624Z"
1075
+ },
1076
+ {
1077
+ id: "760444",
1078
+ stage: "GROUP",
1079
+ group: "C",
1080
+ kickoff: "2026-06-20T00:30Z",
1081
+ venue: "Lincoln Financial Field",
1082
+ home: {
1083
+ code: "BRA",
1084
+ name: "Brazil",
1085
+ flag: "\u{1F1E7}\u{1F1F7}"
1086
+ },
1087
+ away: {
1088
+ code: "HAI",
1089
+ name: "Haiti",
1090
+ flag: "\u{1F1ED}\u{1F1F9}"
1091
+ },
1092
+ status: "SCHEDULED",
1093
+ updatedAt: "2026-05-31T08:32:53.624Z"
1094
+ },
1095
+ {
1096
+ id: "760443",
1097
+ stage: "GROUP",
1098
+ group: "D",
1099
+ kickoff: "2026-06-20T03:00Z",
1100
+ venue: "Levi's Stadium",
1101
+ home: {
1102
+ code: "TUR",
1103
+ name: "T\xFCrkiye",
1104
+ flag: "\u{1F1F9}\u{1F1F7}"
1105
+ },
1106
+ away: {
1107
+ code: "PAR",
1108
+ name: "Paraguay",
1109
+ flag: "\u{1F1F5}\u{1F1FE}"
1110
+ },
1111
+ status: "SCHEDULED",
1112
+ updatedAt: "2026-05-31T08:32:53.624Z"
1113
+ },
1114
+ {
1115
+ id: "760447",
1116
+ stage: "GROUP",
1117
+ group: "F",
1118
+ kickoff: "2026-06-20T17:00Z",
1119
+ venue: "NRG Stadium",
1120
+ home: {
1121
+ code: "NED",
1122
+ name: "Netherlands",
1123
+ flag: "\u{1F1F3}\u{1F1F1}"
1124
+ },
1125
+ away: {
1126
+ code: "SWE",
1127
+ name: "Sweden",
1128
+ flag: "\u{1F1F8}\u{1F1EA}"
1129
+ },
1130
+ status: "SCHEDULED",
1131
+ updatedAt: "2026-05-31T08:32:53.624Z"
1132
+ },
1133
+ {
1134
+ id: "760448",
1135
+ stage: "GROUP",
1136
+ group: "E",
1137
+ kickoff: "2026-06-20T20:00Z",
1138
+ venue: "BMO Field",
1139
+ home: {
1140
+ code: "GER",
1141
+ name: "Germany",
1142
+ flag: "\u{1F1E9}\u{1F1EA}"
1143
+ },
1144
+ away: {
1145
+ code: "CIV",
1146
+ name: "Ivory Coast",
1147
+ flag: "\u{1F1E8}\u{1F1EE}"
1148
+ },
1149
+ status: "SCHEDULED",
1150
+ updatedAt: "2026-05-31T08:32:53.624Z"
1151
+ },
1152
+ {
1153
+ id: "760446",
1154
+ stage: "GROUP",
1155
+ group: "E",
1156
+ kickoff: "2026-06-21T00:00Z",
1157
+ venue: "GEHA Field at Arrowhead Stadium",
1158
+ home: {
1159
+ code: "ECU",
1160
+ name: "Ecuador",
1161
+ flag: "\u{1F1EA}\u{1F1E8}"
1162
+ },
1163
+ away: {
1164
+ code: "CUW",
1165
+ name: "Curacao",
1166
+ flag: "\u{1F1E8}\u{1F1FC}"
1167
+ },
1168
+ status: "SCHEDULED",
1169
+ updatedAt: "2026-05-31T08:32:53.624Z"
1170
+ },
1171
+ {
1172
+ id: "760449",
1173
+ stage: "GROUP",
1174
+ group: "F",
1175
+ kickoff: "2026-06-21T04:00Z",
1176
+ venue: "Estadio BBVA",
1177
+ home: {
1178
+ code: "TUN",
1179
+ name: "Tunisia",
1180
+ flag: "\u{1F1F9}\u{1F1F3}"
1181
+ },
1182
+ away: {
1183
+ code: "JPN",
1184
+ name: "Japan",
1185
+ flag: "\u{1F1EF}\u{1F1F5}"
1186
+ },
1187
+ status: "SCHEDULED",
1188
+ updatedAt: "2026-05-31T08:32:53.624Z"
1189
+ },
1190
+ {
1191
+ id: "760453",
1192
+ stage: "GROUP",
1193
+ group: "H",
1194
+ kickoff: "2026-06-21T16:00Z",
1195
+ venue: "Mercedes-Benz Stadium",
1196
+ home: {
1197
+ code: "ESP",
1198
+ name: "Spain",
1199
+ flag: "\u{1F1EA}\u{1F1F8}"
1200
+ },
1201
+ away: {
1202
+ code: "KSA",
1203
+ name: "Saudi Arabia",
1204
+ flag: "\u{1F1F8}\u{1F1E6}"
1205
+ },
1206
+ status: "SCHEDULED",
1207
+ updatedAt: "2026-05-31T08:32:53.624Z"
1208
+ },
1209
+ {
1210
+ id: "760451",
1211
+ stage: "GROUP",
1212
+ group: "G",
1213
+ kickoff: "2026-06-21T19:00Z",
1214
+ venue: "SoFi Stadium",
1215
+ home: {
1216
+ code: "BEL",
1217
+ name: "Belgium",
1218
+ flag: "\u{1F1E7}\u{1F1EA}"
1219
+ },
1220
+ away: {
1221
+ code: "IRN",
1222
+ name: "Iran",
1223
+ flag: "\u{1F1EE}\u{1F1F7}"
1224
+ },
1225
+ status: "SCHEDULED",
1226
+ updatedAt: "2026-05-31T08:32:53.624Z"
1227
+ },
1228
+ {
1229
+ id: "760450",
1230
+ stage: "GROUP",
1231
+ group: "H",
1232
+ kickoff: "2026-06-21T22:00Z",
1233
+ venue: "Hard Rock Stadium",
1234
+ home: {
1235
+ code: "URU",
1236
+ name: "Uruguay",
1237
+ flag: "\u{1F1FA}\u{1F1FE}"
1238
+ },
1239
+ away: {
1240
+ code: "CPV",
1241
+ name: "Cape Verde",
1242
+ flag: "\u{1F1E8}\u{1F1FB}"
1243
+ },
1244
+ status: "SCHEDULED",
1245
+ updatedAt: "2026-05-31T08:32:53.624Z"
1246
+ },
1247
+ {
1248
+ id: "760452",
1249
+ stage: "GROUP",
1250
+ group: "G",
1251
+ kickoff: "2026-06-22T01:00Z",
1252
+ venue: "BC Place",
1253
+ home: {
1254
+ code: "NZL",
1255
+ name: "New Zealand",
1256
+ flag: "\u{1F1F3}\u{1F1FF}"
1257
+ },
1258
+ away: {
1259
+ code: "EGY",
1260
+ name: "Egypt",
1261
+ flag: "\u{1F1EA}\u{1F1EC}"
1262
+ },
1263
+ status: "SCHEDULED",
1264
+ updatedAt: "2026-05-31T08:32:53.624Z"
1265
+ },
1266
+ {
1267
+ id: "760456",
1268
+ stage: "GROUP",
1269
+ group: "J",
1270
+ kickoff: "2026-06-22T17:00Z",
1271
+ venue: "AT&T Stadium",
1272
+ home: {
1273
+ code: "ARG",
1274
+ name: "Argentina",
1275
+ flag: "\u{1F1E6}\u{1F1F7}"
1276
+ },
1277
+ away: {
1278
+ code: "AUT",
1279
+ name: "Austria",
1280
+ flag: "\u{1F1E6}\u{1F1F9}"
1281
+ },
1282
+ status: "SCHEDULED",
1283
+ updatedAt: "2026-05-31T08:32:53.624Z"
1284
+ },
1285
+ {
1286
+ id: "760457",
1287
+ stage: "GROUP",
1288
+ group: "I",
1289
+ kickoff: "2026-06-22T21:00Z",
1290
+ venue: "Lincoln Financial Field",
1291
+ home: {
1292
+ code: "FRA",
1293
+ name: "France",
1294
+ flag: "\u{1F1EB}\u{1F1F7}"
1295
+ },
1296
+ away: {
1297
+ code: "IRQ",
1298
+ name: "Iraq",
1299
+ flag: "\u{1F1EE}\u{1F1F6}"
1300
+ },
1301
+ status: "SCHEDULED",
1302
+ updatedAt: "2026-05-31T08:32:53.624Z"
1303
+ },
1304
+ {
1305
+ id: "760454",
1306
+ stage: "GROUP",
1307
+ group: "I",
1308
+ kickoff: "2026-06-23T00:00Z",
1309
+ venue: "MetLife Stadium",
1310
+ home: {
1311
+ code: "NOR",
1312
+ name: "Norway",
1313
+ flag: "\u{1F1F3}\u{1F1F4}"
1314
+ },
1315
+ away: {
1316
+ code: "SEN",
1317
+ name: "Senegal",
1318
+ flag: "\u{1F1F8}\u{1F1F3}"
1319
+ },
1320
+ status: "SCHEDULED",
1321
+ updatedAt: "2026-05-31T08:32:53.624Z"
1322
+ },
1323
+ {
1324
+ id: "760455",
1325
+ stage: "GROUP",
1326
+ group: "J",
1327
+ kickoff: "2026-06-23T03:00Z",
1328
+ venue: "Levi's Stadium",
1329
+ home: {
1330
+ code: "JOR",
1331
+ name: "Jordan",
1332
+ flag: "\u{1F1EF}\u{1F1F4}"
1333
+ },
1334
+ away: {
1335
+ code: "ALG",
1336
+ name: "Algeria",
1337
+ flag: "\u{1F1E9}\u{1F1FF}"
1338
+ },
1339
+ status: "SCHEDULED",
1340
+ updatedAt: "2026-05-31T08:32:53.624Z"
1341
+ },
1342
+ {
1343
+ id: "760461",
1344
+ stage: "GROUP",
1345
+ group: "K",
1346
+ kickoff: "2026-06-23T17:00Z",
1347
+ venue: "NRG Stadium",
1348
+ home: {
1349
+ code: "POR",
1350
+ name: "Portugal",
1351
+ flag: "\u{1F1F5}\u{1F1F9}"
1352
+ },
1353
+ away: {
1354
+ code: "UZB",
1355
+ name: "Uzbekistan",
1356
+ flag: "\u{1F1FA}\u{1F1FF}"
1357
+ },
1358
+ status: "SCHEDULED",
1359
+ updatedAt: "2026-05-31T08:32:53.624Z"
1360
+ },
1361
+ {
1362
+ id: "760458",
1363
+ stage: "GROUP",
1364
+ group: "L",
1365
+ kickoff: "2026-06-23T20:00Z",
1366
+ venue: "Gillette Stadium",
1367
+ home: {
1368
+ code: "ENG",
1369
+ name: "England",
1370
+ flag: "\u{1F3F4}\u{E0067}\u{E0062}\u{E0065}\u{E006E}\u{E0067}\u{E007F}"
1371
+ },
1372
+ away: {
1373
+ code: "GHA",
1374
+ name: "Ghana",
1375
+ flag: "\u{1F1EC}\u{1F1ED}"
1376
+ },
1377
+ status: "SCHEDULED",
1378
+ updatedAt: "2026-05-31T08:32:53.624Z"
1379
+ },
1380
+ {
1381
+ id: "760460",
1382
+ stage: "GROUP",
1383
+ group: "L",
1384
+ kickoff: "2026-06-23T23:00Z",
1385
+ venue: "BMO Field",
1386
+ home: {
1387
+ code: "PAN",
1388
+ name: "Panama",
1389
+ flag: "\u{1F1F5}\u{1F1E6}"
1390
+ },
1391
+ away: {
1392
+ code: "CRO",
1393
+ name: "Croatia",
1394
+ flag: "\u{1F1ED}\u{1F1F7}"
1395
+ },
1396
+ status: "SCHEDULED",
1397
+ updatedAt: "2026-05-31T08:32:53.625Z"
1398
+ },
1399
+ {
1400
+ id: "760459",
1401
+ stage: "GROUP",
1402
+ group: "K",
1403
+ kickoff: "2026-06-24T02:00Z",
1404
+ venue: "Estadio Akron",
1405
+ home: {
1406
+ code: "COL",
1407
+ name: "Colombia",
1408
+ flag: "\u{1F1E8}\u{1F1F4}"
1409
+ },
1410
+ away: {
1411
+ code: "COD",
1412
+ name: "Congo DR",
1413
+ flag: "\u{1F1E8}\u{1F1E9}"
1414
+ },
1415
+ status: "SCHEDULED",
1416
+ updatedAt: "2026-05-31T08:32:53.625Z"
1417
+ },
1418
+ {
1419
+ id: "760462",
1420
+ stage: "GROUP",
1421
+ group: "B",
1422
+ kickoff: "2026-06-24T19:00Z",
1423
+ venue: "Lumen Field",
1424
+ home: {
1425
+ code: "BIH",
1426
+ name: "Bosnia-Herzegovina",
1427
+ flag: "\u{1F1E7}\u{1F1E6}"
1428
+ },
1429
+ away: {
1430
+ code: "QAT",
1431
+ name: "Qatar",
1432
+ flag: "\u{1F1F6}\u{1F1E6}"
1433
+ },
1434
+ status: "SCHEDULED",
1435
+ updatedAt: "2026-05-31T08:32:53.625Z"
1436
+ },
1437
+ {
1438
+ id: "760463",
1439
+ stage: "GROUP",
1440
+ group: "B",
1441
+ kickoff: "2026-06-24T19:00Z",
1442
+ venue: "BC Place",
1443
+ home: {
1444
+ code: "SUI",
1445
+ name: "Switzerland",
1446
+ flag: "\u{1F1E8}\u{1F1ED}"
1447
+ },
1448
+ away: {
1449
+ code: "CAN",
1450
+ name: "Canada",
1451
+ flag: "\u{1F1E8}\u{1F1E6}"
1452
+ },
1453
+ status: "SCHEDULED",
1454
+ updatedAt: "2026-05-31T08:32:53.625Z"
1455
+ },
1456
+ {
1457
+ id: "760464",
1458
+ stage: "GROUP",
1459
+ group: "C",
1460
+ kickoff: "2026-06-24T22:00Z",
1461
+ venue: "Mercedes-Benz Stadium",
1462
+ home: {
1463
+ code: "MAR",
1464
+ name: "Morocco",
1465
+ flag: "\u{1F1F2}\u{1F1E6}"
1466
+ },
1467
+ away: {
1468
+ code: "HAI",
1469
+ name: "Haiti",
1470
+ flag: "\u{1F1ED}\u{1F1F9}"
1471
+ },
1472
+ status: "SCHEDULED",
1473
+ updatedAt: "2026-05-31T08:32:53.625Z"
1474
+ },
1475
+ {
1476
+ id: "760465",
1477
+ stage: "GROUP",
1478
+ group: "C",
1479
+ kickoff: "2026-06-24T22:00Z",
1480
+ venue: "Hard Rock Stadium",
1481
+ home: {
1482
+ code: "SCO",
1483
+ name: "Scotland",
1484
+ flag: "\u{1F3F4}\u{E0067}\u{E0062}\u{E0073}\u{E0063}\u{E0074}\u{E007F}"
1485
+ },
1486
+ away: {
1487
+ code: "BRA",
1488
+ name: "Brazil",
1489
+ flag: "\u{1F1E7}\u{1F1F7}"
1490
+ },
1491
+ status: "SCHEDULED",
1492
+ updatedAt: "2026-05-31T08:32:53.625Z"
1493
+ },
1494
+ {
1495
+ id: "760467",
1496
+ stage: "GROUP",
1497
+ group: "A",
1498
+ kickoff: "2026-06-25T01:00Z",
1499
+ venue: "Estadio Banorte",
1500
+ home: {
1501
+ code: "CZE",
1502
+ name: "Czechia",
1503
+ flag: "\u{1F1E8}\u{1F1FF}"
1504
+ },
1505
+ away: {
1506
+ code: "MEX",
1507
+ name: "Mexico",
1508
+ flag: "\u{1F1F2}\u{1F1FD}"
1509
+ },
1510
+ status: "SCHEDULED",
1511
+ updatedAt: "2026-05-31T08:32:53.625Z"
1512
+ },
1513
+ {
1514
+ id: "760466",
1515
+ stage: "GROUP",
1516
+ group: "A",
1517
+ kickoff: "2026-06-25T01:00Z",
1518
+ venue: "Estadio BBVA",
1519
+ home: {
1520
+ code: "RSA",
1521
+ name: "South Africa",
1522
+ flag: "\u{1F1FF}\u{1F1E6}"
1523
+ },
1524
+ away: {
1525
+ code: "KOR",
1526
+ name: "South Korea",
1527
+ flag: "\u{1F1F0}\u{1F1F7}"
1528
+ },
1529
+ status: "SCHEDULED",
1530
+ updatedAt: "2026-05-31T08:32:53.625Z"
1531
+ },
1532
+ {
1533
+ id: "760473",
1534
+ stage: "GROUP",
1535
+ group: "E",
1536
+ kickoff: "2026-06-25T20:00Z",
1537
+ venue: "Lincoln Financial Field",
1538
+ home: {
1539
+ code: "CUW",
1540
+ name: "Curacao",
1541
+ flag: "\u{1F1E8}\u{1F1FC}"
1542
+ },
1543
+ away: {
1544
+ code: "CIV",
1545
+ name: "Ivory Coast",
1546
+ flag: "\u{1F1E8}\u{1F1EE}"
1547
+ },
1548
+ status: "SCHEDULED",
1549
+ updatedAt: "2026-05-31T08:32:53.682Z"
1550
+ },
1551
+ {
1552
+ id: "760468",
1553
+ stage: "GROUP",
1554
+ group: "E",
1555
+ kickoff: "2026-06-25T20:00Z",
1556
+ venue: "MetLife Stadium",
1557
+ home: {
1558
+ code: "ECU",
1559
+ name: "Ecuador",
1560
+ flag: "\u{1F1EA}\u{1F1E8}"
1561
+ },
1562
+ away: {
1563
+ code: "GER",
1564
+ name: "Germany",
1565
+ flag: "\u{1F1E9}\u{1F1EA}"
1566
+ },
1567
+ status: "SCHEDULED",
1568
+ updatedAt: "2026-05-31T08:32:53.682Z"
1569
+ },
1570
+ {
1571
+ id: "760471",
1572
+ stage: "GROUP",
1573
+ group: "F",
1574
+ kickoff: "2026-06-25T23:00Z",
1575
+ venue: "AT&T Stadium",
1576
+ home: {
1577
+ code: "JPN",
1578
+ name: "Japan",
1579
+ flag: "\u{1F1EF}\u{1F1F5}"
1580
+ },
1581
+ away: {
1582
+ code: "SWE",
1583
+ name: "Sweden",
1584
+ flag: "\u{1F1F8}\u{1F1EA}"
1585
+ },
1586
+ status: "SCHEDULED",
1587
+ updatedAt: "2026-05-31T08:32:53.682Z"
1588
+ },
1589
+ {
1590
+ id: "760472",
1591
+ stage: "GROUP",
1592
+ group: "F",
1593
+ kickoff: "2026-06-25T23:00Z",
1594
+ venue: "GEHA Field at Arrowhead Stadium",
1595
+ home: {
1596
+ code: "TUN",
1597
+ name: "Tunisia",
1598
+ flag: "\u{1F1F9}\u{1F1F3}"
1599
+ },
1600
+ away: {
1601
+ code: "NED",
1602
+ name: "Netherlands",
1603
+ flag: "\u{1F1F3}\u{1F1F1}"
1604
+ },
1605
+ status: "SCHEDULED",
1606
+ updatedAt: "2026-05-31T08:32:53.682Z"
1607
+ },
1608
+ {
1609
+ id: "760469",
1610
+ stage: "GROUP",
1611
+ group: "D",
1612
+ kickoff: "2026-06-26T02:00Z",
1613
+ venue: "Levi's Stadium",
1614
+ home: {
1615
+ code: "PAR",
1616
+ name: "Paraguay",
1617
+ flag: "\u{1F1F5}\u{1F1FE}"
1618
+ },
1619
+ away: {
1620
+ code: "AUS",
1621
+ name: "Australia",
1622
+ flag: "\u{1F1E6}\u{1F1FA}"
1623
+ },
1624
+ status: "SCHEDULED",
1625
+ updatedAt: "2026-05-31T08:32:53.682Z"
1626
+ },
1627
+ {
1628
+ id: "760470",
1629
+ stage: "GROUP",
1630
+ group: "D",
1631
+ kickoff: "2026-06-26T02:00Z",
1632
+ venue: "SoFi Stadium",
1633
+ home: {
1634
+ code: "TUR",
1635
+ name: "T\xFCrkiye",
1636
+ flag: "\u{1F1F9}\u{1F1F7}"
1637
+ },
1638
+ away: {
1639
+ code: "USA",
1640
+ name: "United States",
1641
+ flag: "\u{1F1FA}\u{1F1F8}"
1642
+ },
1643
+ status: "SCHEDULED",
1644
+ updatedAt: "2026-05-31T08:32:53.682Z"
1645
+ },
1646
+ {
1647
+ id: "760475",
1648
+ stage: "GROUP",
1649
+ group: "I",
1650
+ kickoff: "2026-06-26T19:00Z",
1651
+ venue: "Gillette Stadium",
1652
+ home: {
1653
+ code: "NOR",
1654
+ name: "Norway",
1655
+ flag: "\u{1F1F3}\u{1F1F4}"
1656
+ },
1657
+ away: {
1658
+ code: "FRA",
1659
+ name: "France",
1660
+ flag: "\u{1F1EB}\u{1F1F7}"
1661
+ },
1662
+ status: "SCHEDULED",
1663
+ updatedAt: "2026-05-31T08:32:53.682Z"
1664
+ },
1665
+ {
1666
+ id: "760474",
1667
+ stage: "GROUP",
1668
+ group: "I",
1669
+ kickoff: "2026-06-26T19:00Z",
1670
+ venue: "BMO Field",
1671
+ home: {
1672
+ code: "SEN",
1673
+ name: "Senegal",
1674
+ flag: "\u{1F1F8}\u{1F1F3}"
1675
+ },
1676
+ away: {
1677
+ code: "IRQ",
1678
+ name: "Iraq",
1679
+ flag: "\u{1F1EE}\u{1F1F6}"
1680
+ },
1681
+ status: "SCHEDULED",
1682
+ updatedAt: "2026-05-31T08:32:53.682Z"
1683
+ },
1684
+ {
1685
+ id: "760478",
1686
+ stage: "GROUP",
1687
+ group: "H",
1688
+ kickoff: "2026-06-27T00:00Z",
1689
+ venue: "NRG Stadium",
1690
+ home: {
1691
+ code: "CPV",
1692
+ name: "Cape Verde",
1693
+ flag: "\u{1F1E8}\u{1F1FB}"
1694
+ },
1695
+ away: {
1696
+ code: "KSA",
1697
+ name: "Saudi Arabia",
1698
+ flag: "\u{1F1F8}\u{1F1E6}"
1699
+ },
1700
+ status: "SCHEDULED",
1701
+ updatedAt: "2026-05-31T08:32:53.682Z"
1702
+ },
1703
+ {
1704
+ id: "760479",
1705
+ stage: "GROUP",
1706
+ group: "H",
1707
+ kickoff: "2026-06-27T00:00Z",
1708
+ venue: "Estadio Akron",
1709
+ home: {
1710
+ code: "URU",
1711
+ name: "Uruguay",
1712
+ flag: "\u{1F1FA}\u{1F1FE}"
1713
+ },
1714
+ away: {
1715
+ code: "ESP",
1716
+ name: "Spain",
1717
+ flag: "\u{1F1EA}\u{1F1F8}"
1718
+ },
1719
+ status: "SCHEDULED",
1720
+ updatedAt: "2026-05-31T08:32:53.682Z"
1721
+ },
1722
+ {
1723
+ id: "760476",
1724
+ stage: "GROUP",
1725
+ group: "G",
1726
+ kickoff: "2026-06-27T03:00Z",
1727
+ venue: "Lumen Field",
1728
+ home: {
1729
+ code: "EGY",
1730
+ name: "Egypt",
1731
+ flag: "\u{1F1EA}\u{1F1EC}"
1732
+ },
1733
+ away: {
1734
+ code: "IRN",
1735
+ name: "Iran",
1736
+ flag: "\u{1F1EE}\u{1F1F7}"
1737
+ },
1738
+ status: "SCHEDULED",
1739
+ updatedAt: "2026-05-31T08:32:53.682Z"
1740
+ },
1741
+ {
1742
+ id: "760477",
1743
+ stage: "GROUP",
1744
+ group: "G",
1745
+ kickoff: "2026-06-27T03:00Z",
1746
+ venue: "BC Place",
1747
+ home: {
1748
+ code: "NZL",
1749
+ name: "New Zealand",
1750
+ flag: "\u{1F1F3}\u{1F1FF}"
1751
+ },
1752
+ away: {
1753
+ code: "BEL",
1754
+ name: "Belgium",
1755
+ flag: "\u{1F1E7}\u{1F1EA}"
1756
+ },
1757
+ status: "SCHEDULED",
1758
+ updatedAt: "2026-05-31T08:32:53.682Z"
1759
+ },
1760
+ {
1761
+ id: "760480",
1762
+ stage: "GROUP",
1763
+ group: "L",
1764
+ kickoff: "2026-06-27T21:00Z",
1765
+ venue: "Lincoln Financial Field",
1766
+ home: {
1767
+ code: "CRO",
1768
+ name: "Croatia",
1769
+ flag: "\u{1F1ED}\u{1F1F7}"
1770
+ },
1771
+ away: {
1772
+ code: "GHA",
1773
+ name: "Ghana",
1774
+ flag: "\u{1F1EC}\u{1F1ED}"
1775
+ },
1776
+ status: "SCHEDULED",
1777
+ updatedAt: "2026-05-31T08:32:53.682Z"
1778
+ },
1779
+ {
1780
+ id: "760485",
1781
+ stage: "GROUP",
1782
+ group: "L",
1783
+ kickoff: "2026-06-27T21:00Z",
1784
+ venue: "MetLife Stadium",
1785
+ home: {
1786
+ code: "PAN",
1787
+ name: "Panama",
1788
+ flag: "\u{1F1F5}\u{1F1E6}"
1789
+ },
1790
+ away: {
1791
+ code: "ENG",
1792
+ name: "England",
1793
+ flag: "\u{1F3F4}\u{E0067}\u{E0062}\u{E0065}\u{E006E}\u{E0067}\u{E007F}"
1794
+ },
1795
+ status: "SCHEDULED",
1796
+ updatedAt: "2026-05-31T08:32:53.682Z"
1797
+ },
1798
+ {
1799
+ id: "760481",
1800
+ stage: "GROUP",
1801
+ group: "K",
1802
+ kickoff: "2026-06-27T23:30Z",
1803
+ venue: "Hard Rock Stadium",
1804
+ home: {
1805
+ code: "COL",
1806
+ name: "Colombia",
1807
+ flag: "\u{1F1E8}\u{1F1F4}"
1808
+ },
1809
+ away: {
1810
+ code: "POR",
1811
+ name: "Portugal",
1812
+ flag: "\u{1F1F5}\u{1F1F9}"
1813
+ },
1814
+ status: "SCHEDULED",
1815
+ updatedAt: "2026-05-31T08:32:53.682Z"
1816
+ },
1817
+ {
1818
+ id: "760482",
1819
+ stage: "GROUP",
1820
+ group: "K",
1821
+ kickoff: "2026-06-27T23:30Z",
1822
+ venue: "Mercedes-Benz Stadium",
1823
+ home: {
1824
+ code: "COD",
1825
+ name: "Congo DR",
1826
+ flag: "\u{1F1E8}\u{1F1E9}"
1827
+ },
1828
+ away: {
1829
+ code: "UZB",
1830
+ name: "Uzbekistan",
1831
+ flag: "\u{1F1FA}\u{1F1FF}"
1832
+ },
1833
+ status: "SCHEDULED",
1834
+ updatedAt: "2026-05-31T08:32:53.682Z"
1835
+ },
1836
+ {
1837
+ id: "760484",
1838
+ stage: "GROUP",
1839
+ group: "J",
1840
+ kickoff: "2026-06-28T02:00Z",
1841
+ venue: "GEHA Field at Arrowhead Stadium",
1842
+ home: {
1843
+ code: "ALG",
1844
+ name: "Algeria",
1845
+ flag: "\u{1F1E9}\u{1F1FF}"
1846
+ },
1847
+ away: {
1848
+ code: "AUT",
1849
+ name: "Austria",
1850
+ flag: "\u{1F1E6}\u{1F1F9}"
1851
+ },
1852
+ status: "SCHEDULED",
1853
+ updatedAt: "2026-05-31T08:32:53.682Z"
1854
+ },
1855
+ {
1856
+ id: "760483",
1857
+ stage: "GROUP",
1858
+ group: "J",
1859
+ kickoff: "2026-06-28T02:00Z",
1860
+ venue: "AT&T Stadium",
1861
+ home: {
1862
+ code: "JOR",
1863
+ name: "Jordan",
1864
+ flag: "\u{1F1EF}\u{1F1F4}"
1865
+ },
1866
+ away: {
1867
+ code: "ARG",
1868
+ name: "Argentina",
1869
+ flag: "\u{1F1E6}\u{1F1F7}"
1870
+ },
1871
+ status: "SCHEDULED",
1872
+ updatedAt: "2026-05-31T08:32:53.682Z"
1873
+ },
1874
+ {
1875
+ id: "760486",
1876
+ stage: "R32",
1877
+ kickoff: "2026-06-28T19:00Z",
1878
+ venue: "SoFi Stadium",
1879
+ home: {
1880
+ code: "2A",
1881
+ name: "Group A 2nd Place",
1882
+ flag: "\u{1F3F3}\uFE0F"
1883
+ },
1884
+ away: {
1885
+ code: "2B",
1886
+ name: "Group B 2nd Place",
1887
+ flag: "\u{1F3F3}\uFE0F"
1888
+ },
1889
+ status: "SCHEDULED",
1890
+ updatedAt: "2026-05-31T08:32:53.682Z"
1891
+ },
1892
+ {
1893
+ id: "760487",
1894
+ stage: "R32",
1895
+ kickoff: "2026-06-29T17:00Z",
1896
+ venue: "NRG Stadium",
1897
+ home: {
1898
+ code: "1C",
1899
+ name: "Group C Winner",
1900
+ flag: "\u{1F3F3}\uFE0F"
1901
+ },
1902
+ away: {
1903
+ code: "2F",
1904
+ name: "Group F 2nd Place",
1905
+ flag: "\u{1F3F3}\uFE0F"
1906
+ },
1907
+ status: "SCHEDULED",
1908
+ updatedAt: "2026-05-31T08:32:53.682Z"
1909
+ },
1910
+ {
1911
+ id: "760489",
1912
+ stage: "R32",
1913
+ kickoff: "2026-06-29T20:30Z",
1914
+ venue: "Gillette Stadium",
1915
+ home: {
1916
+ code: "1E",
1917
+ name: "Group E Winner",
1918
+ flag: "\u{1F3F3}\uFE0F"
1919
+ },
1920
+ away: {
1921
+ code: "3RD",
1922
+ name: "Third Place Group A/B/C/D/F",
1923
+ flag: "\u{1F3F3}\uFE0F"
1924
+ },
1925
+ status: "SCHEDULED",
1926
+ updatedAt: "2026-05-31T08:32:53.682Z"
1927
+ },
1928
+ {
1929
+ id: "760488",
1930
+ stage: "R32",
1931
+ kickoff: "2026-06-30T01:00Z",
1932
+ venue: "Estadio BBVA",
1933
+ home: {
1934
+ code: "1F",
1935
+ name: "Group F Winner",
1936
+ flag: "\u{1F3F3}\uFE0F"
1937
+ },
1938
+ away: {
1939
+ code: "2C",
1940
+ name: "Group C 2nd Place",
1941
+ flag: "\u{1F3F3}\uFE0F"
1942
+ },
1943
+ status: "SCHEDULED",
1944
+ updatedAt: "2026-05-31T08:32:53.682Z"
1945
+ },
1946
+ {
1947
+ id: "760490",
1948
+ stage: "R32",
1949
+ kickoff: "2026-06-30T17:00Z",
1950
+ venue: "AT&T Stadium",
1951
+ home: {
1952
+ code: "2E",
1953
+ name: "Group E 2nd Place",
1954
+ flag: "\u{1F3F3}\uFE0F"
1955
+ },
1956
+ away: {
1957
+ code: "2I",
1958
+ name: "Group I 2nd Place",
1959
+ flag: "\u{1F3F3}\uFE0F"
1960
+ },
1961
+ status: "SCHEDULED",
1962
+ updatedAt: "2026-05-31T08:32:53.682Z"
1963
+ },
1964
+ {
1965
+ id: "760492",
1966
+ stage: "R32",
1967
+ kickoff: "2026-06-30T21:00Z",
1968
+ venue: "MetLife Stadium",
1969
+ home: {
1970
+ code: "1I",
1971
+ name: "Group I Winner",
1972
+ flag: "\u{1F3F3}\uFE0F"
1973
+ },
1974
+ away: {
1975
+ code: "3RD",
1976
+ name: "Third Place Group C/D/F/G/H",
1977
+ flag: "\u{1F3F3}\uFE0F"
1978
+ },
1979
+ status: "SCHEDULED",
1980
+ updatedAt: "2026-05-31T08:32:53.682Z"
1981
+ },
1982
+ {
1983
+ id: "760491",
1984
+ stage: "R32",
1985
+ kickoff: "2026-07-01T01:00Z",
1986
+ venue: "Estadio Banorte",
1987
+ home: {
1988
+ code: "1A",
1989
+ name: "Group A Winner",
1990
+ flag: "\u{1F3F3}\uFE0F"
1991
+ },
1992
+ away: {
1993
+ code: "3RD",
1994
+ name: "Third Place Group C/E/F/H/I",
1995
+ flag: "\u{1F3F3}\uFE0F"
1996
+ },
1997
+ status: "SCHEDULED",
1998
+ updatedAt: "2026-05-31T08:32:53.682Z"
1999
+ },
2000
+ {
2001
+ id: "760495",
2002
+ stage: "R32",
2003
+ kickoff: "2026-07-01T16:00Z",
2004
+ venue: "Mercedes-Benz Stadium",
2005
+ home: {
2006
+ code: "1L",
2007
+ name: "Group L Winner",
2008
+ flag: "\u{1F3F3}\uFE0F"
2009
+ },
2010
+ away: {
2011
+ code: "3RD",
2012
+ name: "Third Place Group E/H/I/J/K",
2013
+ flag: "\u{1F3F3}\uFE0F"
2014
+ },
2015
+ status: "SCHEDULED",
2016
+ updatedAt: "2026-05-31T08:32:53.682Z"
2017
+ },
2018
+ {
2019
+ id: "760493",
2020
+ stage: "R32",
2021
+ kickoff: "2026-07-01T20:00Z",
2022
+ venue: "Lumen Field",
2023
+ home: {
2024
+ code: "1G",
2025
+ name: "Group G Winner",
2026
+ flag: "\u{1F3F3}\uFE0F"
2027
+ },
2028
+ away: {
2029
+ code: "3RD",
2030
+ name: "Third Place Group A/E/H/I/J",
2031
+ flag: "\u{1F3F3}\uFE0F"
2032
+ },
2033
+ status: "SCHEDULED",
2034
+ updatedAt: "2026-05-31T08:32:53.682Z"
2035
+ },
2036
+ {
2037
+ id: "760494",
2038
+ stage: "R32",
2039
+ kickoff: "2026-07-02T00:00Z",
2040
+ venue: "Levi's Stadium",
2041
+ home: {
2042
+ code: "1D",
2043
+ name: "Group D Winner",
2044
+ flag: "\u{1F3F3}\uFE0F"
2045
+ },
2046
+ away: {
2047
+ code: "3RD",
2048
+ name: "Third Place Group B/E/F/I/J",
2049
+ flag: "\u{1F3F3}\uFE0F"
2050
+ },
2051
+ status: "SCHEDULED",
2052
+ updatedAt: "2026-05-31T08:32:53.683Z"
2053
+ },
2054
+ {
2055
+ id: "760497",
2056
+ stage: "R32",
2057
+ kickoff: "2026-07-02T19:00Z",
2058
+ venue: "SoFi Stadium",
2059
+ home: {
2060
+ code: "1H",
2061
+ name: "Group H Winner",
2062
+ flag: "\u{1F3F3}\uFE0F"
2063
+ },
2064
+ away: {
2065
+ code: "2J",
2066
+ name: "Group J 2nd Place",
2067
+ flag: "\u{1F3F3}\uFE0F"
2068
+ },
2069
+ status: "SCHEDULED",
2070
+ updatedAt: "2026-05-31T08:32:53.746Z"
2071
+ },
2072
+ {
2073
+ id: "760496",
2074
+ stage: "R32",
2075
+ kickoff: "2026-07-02T23:00Z",
2076
+ venue: "BMO Field",
2077
+ home: {
2078
+ code: "2K",
2079
+ name: "Group K 2nd Place",
2080
+ flag: "\u{1F3F3}\uFE0F"
2081
+ },
2082
+ away: {
2083
+ code: "2L",
2084
+ name: "Group L 2nd Place",
2085
+ flag: "\u{1F3F3}\uFE0F"
2086
+ },
2087
+ status: "SCHEDULED",
2088
+ updatedAt: "2026-05-31T08:32:53.746Z"
2089
+ },
2090
+ {
2091
+ id: "760498",
2092
+ stage: "R32",
2093
+ kickoff: "2026-07-03T03:00Z",
2094
+ venue: "BC Place",
2095
+ home: {
2096
+ code: "1B",
2097
+ name: "Group B Winner",
2098
+ flag: "\u{1F3F3}\uFE0F"
2099
+ },
2100
+ away: {
2101
+ code: "3RD",
2102
+ name: "Third Place Group E/F/G/I/J",
2103
+ flag: "\u{1F3F3}\uFE0F"
2104
+ },
2105
+ status: "SCHEDULED",
2106
+ updatedAt: "2026-05-31T08:32:53.746Z"
2107
+ },
2108
+ {
2109
+ id: "760499",
2110
+ stage: "R32",
2111
+ kickoff: "2026-07-03T18:00Z",
2112
+ venue: "AT&T Stadium",
2113
+ home: {
2114
+ code: "2D",
2115
+ name: "Group D 2nd Place",
2116
+ flag: "\u{1F3F3}\uFE0F"
2117
+ },
2118
+ away: {
2119
+ code: "2G",
2120
+ name: "Group G 2nd Place",
2121
+ flag: "\u{1F3F3}\uFE0F"
2122
+ },
2123
+ status: "SCHEDULED",
2124
+ updatedAt: "2026-05-31T08:32:53.746Z"
2125
+ },
2126
+ {
2127
+ id: "760500",
2128
+ stage: "R32",
2129
+ kickoff: "2026-07-03T22:00Z",
2130
+ venue: "Hard Rock Stadium",
2131
+ home: {
2132
+ code: "1J",
2133
+ name: "Group J Winner",
2134
+ flag: "\u{1F3F3}\uFE0F"
2135
+ },
2136
+ away: {
2137
+ code: "2H",
2138
+ name: "Group H 2nd Place",
2139
+ flag: "\u{1F3F3}\uFE0F"
2140
+ },
2141
+ status: "SCHEDULED",
2142
+ updatedAt: "2026-05-31T08:32:53.746Z"
2143
+ },
2144
+ {
2145
+ id: "760501",
2146
+ stage: "R32",
2147
+ kickoff: "2026-07-04T01:30Z",
2148
+ venue: "GEHA Field at Arrowhead Stadium",
2149
+ home: {
2150
+ code: "1K",
2151
+ name: "Group K Winner",
2152
+ flag: "\u{1F3F3}\uFE0F"
2153
+ },
2154
+ away: {
2155
+ code: "3RD",
2156
+ name: "Third Place Group D/E/I/J/L",
2157
+ flag: "\u{1F3F3}\uFE0F"
2158
+ },
2159
+ status: "SCHEDULED",
2160
+ updatedAt: "2026-05-31T08:32:53.746Z"
2161
+ },
2162
+ {
2163
+ id: "760502",
2164
+ stage: "R16",
2165
+ kickoff: "2026-07-04T17:00Z",
2166
+ venue: "NRG Stadium",
2167
+ home: {
2168
+ code: "RD32",
2169
+ name: "Round of 32 1 Winner",
2170
+ flag: "\u{1F3F3}\uFE0F"
2171
+ },
2172
+ away: {
2173
+ code: "RD32",
2174
+ name: "Round of 32 3 Winner",
2175
+ flag: "\u{1F3F3}\uFE0F"
2176
+ },
2177
+ status: "SCHEDULED",
2178
+ updatedAt: "2026-05-31T08:32:53.746Z"
2179
+ },
2180
+ {
2181
+ id: "760503",
2182
+ stage: "R16",
2183
+ kickoff: "2026-07-04T21:00Z",
2184
+ venue: "Lincoln Financial Field",
2185
+ home: {
2186
+ code: "RD32",
2187
+ name: "Round of 32 2 Winner",
2188
+ flag: "\u{1F3F3}\uFE0F"
2189
+ },
2190
+ away: {
2191
+ code: "RD32",
2192
+ name: "Round of 32 5 Winner",
2193
+ flag: "\u{1F3F3}\uFE0F"
2194
+ },
2195
+ status: "SCHEDULED",
2196
+ updatedAt: "2026-05-31T08:32:53.746Z"
2197
+ },
2198
+ {
2199
+ id: "760504",
2200
+ stage: "R16",
2201
+ kickoff: "2026-07-05T20:00Z",
2202
+ venue: "MetLife Stadium",
2203
+ home: {
2204
+ code: "RD32",
2205
+ name: "Round of 32 4 Winner",
2206
+ flag: "\u{1F3F3}\uFE0F"
2207
+ },
2208
+ away: {
2209
+ code: "RD32",
2210
+ name: "Round of 32 6 Winner",
2211
+ flag: "\u{1F3F3}\uFE0F"
2212
+ },
2213
+ status: "SCHEDULED",
2214
+ updatedAt: "2026-05-31T08:32:53.746Z"
2215
+ },
2216
+ {
2217
+ id: "760505",
2218
+ stage: "R16",
2219
+ kickoff: "2026-07-06T00:00Z",
2220
+ venue: "Estadio Banorte",
2221
+ home: {
2222
+ code: "RD32",
2223
+ name: "Round of 32 7 Winner",
2224
+ flag: "\u{1F3F3}\uFE0F"
2225
+ },
2226
+ away: {
2227
+ code: "RD32",
2228
+ name: "Round of 32 8 Winner",
2229
+ flag: "\u{1F3F3}\uFE0F"
2230
+ },
2231
+ status: "SCHEDULED",
2232
+ updatedAt: "2026-05-31T08:32:53.746Z"
2233
+ },
2234
+ {
2235
+ id: "760506",
2236
+ stage: "R16",
2237
+ kickoff: "2026-07-06T19:00Z",
2238
+ venue: "AT&T Stadium",
2239
+ home: {
2240
+ code: "RD32",
2241
+ name: "Round of 32 11 Winner",
2242
+ flag: "\u{1F3F3}\uFE0F"
2243
+ },
2244
+ away: {
2245
+ code: "RD32",
2246
+ name: "Round of 32 12 Winner",
2247
+ flag: "\u{1F3F3}\uFE0F"
2248
+ },
2249
+ status: "SCHEDULED",
2250
+ updatedAt: "2026-05-31T08:32:53.746Z"
2251
+ },
2252
+ {
2253
+ id: "760507",
2254
+ stage: "R16",
2255
+ kickoff: "2026-07-07T00:00Z",
2256
+ venue: "Lumen Field",
2257
+ home: {
2258
+ code: "RD32",
2259
+ name: "Round of 32 9 Winner",
2260
+ flag: "\u{1F3F3}\uFE0F"
2261
+ },
2262
+ away: {
2263
+ code: "RD32",
2264
+ name: "Round of 32 10 Winner",
2265
+ flag: "\u{1F3F3}\uFE0F"
2266
+ },
2267
+ status: "SCHEDULED",
2268
+ updatedAt: "2026-05-31T08:32:53.746Z"
2269
+ },
2270
+ {
2271
+ id: "760509",
2272
+ stage: "R16",
2273
+ kickoff: "2026-07-07T16:00Z",
2274
+ venue: "Mercedes-Benz Stadium",
2275
+ home: {
2276
+ code: "RD32",
2277
+ name: "Round of 32 14 Winner",
2278
+ flag: "\u{1F3F3}\uFE0F"
2279
+ },
2280
+ away: {
2281
+ code: "RD32",
2282
+ name: "Round of 32 16 Winner",
2283
+ flag: "\u{1F3F3}\uFE0F"
2284
+ },
2285
+ status: "SCHEDULED",
2286
+ updatedAt: "2026-05-31T08:32:53.746Z"
2287
+ },
2288
+ {
2289
+ id: "760508",
2290
+ stage: "R16",
2291
+ kickoff: "2026-07-07T20:00Z",
2292
+ venue: "BC Place",
2293
+ home: {
2294
+ code: "RD32",
2295
+ name: "Round of 32 13 Winner",
2296
+ flag: "\u{1F3F3}\uFE0F"
2297
+ },
2298
+ away: {
2299
+ code: "RD32",
2300
+ name: "Round of 32 15 Winner",
2301
+ flag: "\u{1F3F3}\uFE0F"
2302
+ },
2303
+ status: "SCHEDULED",
2304
+ updatedAt: "2026-05-31T08:32:53.746Z"
2305
+ },
2306
+ {
2307
+ id: "760510",
2308
+ stage: "QF",
2309
+ kickoff: "2026-07-09T20:00Z",
2310
+ venue: "Gillette Stadium",
2311
+ home: {
2312
+ code: "RD16 W1",
2313
+ name: "Round of 16 1 Winner",
2314
+ flag: "\u{1F3F3}\uFE0F"
2315
+ },
2316
+ away: {
2317
+ code: "RD16 W2",
2318
+ name: "Round of 16 2 Winner",
2319
+ flag: "\u{1F3F3}\uFE0F"
2320
+ },
2321
+ status: "SCHEDULED",
2322
+ updatedAt: "2026-05-31T08:32:53.806Z"
2323
+ },
2324
+ {
2325
+ id: "760511",
2326
+ stage: "QF",
2327
+ kickoff: "2026-07-10T19:00Z",
2328
+ venue: "SoFi Stadium",
2329
+ home: {
2330
+ code: "RD16 W5",
2331
+ name: "Round of 16 5 Winner",
2332
+ flag: "\u{1F3F3}\uFE0F"
2333
+ },
2334
+ away: {
2335
+ code: "RD16 W6",
2336
+ name: "Round of 16 6 Winner",
2337
+ flag: "\u{1F3F3}\uFE0F"
2338
+ },
2339
+ status: "SCHEDULED",
2340
+ updatedAt: "2026-05-31T08:32:53.806Z"
2341
+ },
2342
+ {
2343
+ id: "760512",
2344
+ stage: "QF",
2345
+ kickoff: "2026-07-11T21:00Z",
2346
+ venue: "Hard Rock Stadium",
2347
+ home: {
2348
+ code: "RD16 W3",
2349
+ name: "Round of 16 3 Winner",
2350
+ flag: "\u{1F3F3}\uFE0F"
2351
+ },
2352
+ away: {
2353
+ code: "RD16 W4",
2354
+ name: "Round of 16 4 Winner",
2355
+ flag: "\u{1F3F3}\uFE0F"
2356
+ },
2357
+ status: "SCHEDULED",
2358
+ updatedAt: "2026-05-31T08:32:53.806Z"
2359
+ },
2360
+ {
2361
+ id: "760513",
2362
+ stage: "QF",
2363
+ kickoff: "2026-07-12T01:00Z",
2364
+ venue: "GEHA Field at Arrowhead Stadium",
2365
+ home: {
2366
+ code: "RD16 W7",
2367
+ name: "Round of 16 7 Winner",
2368
+ flag: "\u{1F3F3}\uFE0F"
2369
+ },
2370
+ away: {
2371
+ code: "RD16 W8",
2372
+ name: "Round of 16 8 Winner",
2373
+ flag: "\u{1F3F3}\uFE0F"
2374
+ },
2375
+ status: "SCHEDULED",
2376
+ updatedAt: "2026-05-31T08:32:53.806Z"
2377
+ },
2378
+ {
2379
+ id: "760514",
2380
+ stage: "SF",
2381
+ kickoff: "2026-07-14T19:00Z",
2382
+ venue: "AT&T Stadium",
2383
+ home: {
2384
+ code: "QFW1",
2385
+ name: "Quarterfinal 1 Winner",
2386
+ flag: "\u{1F3F3}\uFE0F"
2387
+ },
2388
+ away: {
2389
+ code: "QFW2",
2390
+ name: "Quarterfinal 2 Winner",
2391
+ flag: "\u{1F3F3}\uFE0F"
2392
+ },
2393
+ status: "SCHEDULED",
2394
+ updatedAt: "2026-05-31T08:32:53.806Z"
2395
+ },
2396
+ {
2397
+ id: "760515",
2398
+ stage: "SF",
2399
+ kickoff: "2026-07-15T19:00Z",
2400
+ venue: "Mercedes-Benz Stadium",
2401
+ home: {
2402
+ code: "QFW3",
2403
+ name: "Quarterfinal 3 Winner",
2404
+ flag: "\u{1F3F3}\uFE0F"
2405
+ },
2406
+ away: {
2407
+ code: "QW4",
2408
+ name: "Quarterfinal 4 Winner",
2409
+ flag: "\u{1F3F3}\uFE0F"
2410
+ },
2411
+ status: "SCHEDULED",
2412
+ updatedAt: "2026-05-31T08:32:53.806Z"
2413
+ },
2414
+ {
2415
+ id: "760516",
2416
+ stage: "3P",
2417
+ kickoff: "2026-07-18T21:00Z",
2418
+ venue: "Hard Rock Stadium",
2419
+ home: {
2420
+ code: "SF L1",
2421
+ name: "Semifinal 1 Loser",
2422
+ flag: "\u{1F3F3}\uFE0F"
2423
+ },
2424
+ away: {
2425
+ code: "SF L2",
2426
+ name: "Semifinal 2 Loser",
2427
+ flag: "\u{1F3F3}\uFE0F"
2428
+ },
2429
+ status: "SCHEDULED",
2430
+ updatedAt: "2026-05-31T08:32:53.923Z"
2431
+ },
2432
+ {
2433
+ id: "760517",
2434
+ stage: "F",
2435
+ kickoff: "2026-07-19T19:00Z",
2436
+ venue: "MetLife Stadium",
2437
+ home: {
2438
+ code: "SFW1",
2439
+ name: "Semifinal 1 Winner",
2440
+ flag: "\u{1F3F3}\uFE0F"
2441
+ },
2442
+ away: {
2443
+ code: "SFW2",
2444
+ name: "Semifinal 2 Winner",
2445
+ flag: "\u{1F3F3}\uFE0F"
2446
+ },
2447
+ status: "SCHEDULED",
2448
+ updatedAt: "2026-05-31T08:32:53.924Z"
2449
+ }
2450
+ ];
2451
+ var SCHEDULE = schedule_2026_default;
2452
+ function allFixtures() {
2453
+ return SCHEDULE;
2454
+ }
2455
+ function fixturesByDate(dateISO, fixtures = SCHEDULE) {
2456
+ const day = dateISO.slice(0, 10);
2457
+ return fixtures.filter((m) => m.kickoff.slice(0, 10) === day).sort(byKickoff);
2458
+ }
2459
+ function fixturesByTeam(code, fixtures = SCHEDULE) {
2460
+ const c = code.toUpperCase();
2461
+ return fixtures.filter((m) => m.home.code.toUpperCase() === c || m.away.code.toUpperCase() === c).sort(byKickoff);
2462
+ }
2463
+ function fixturesByGroup(group, fixtures = SCHEDULE) {
2464
+ const g = group.toUpperCase();
2465
+ return fixtures.filter((m) => (m.group ?? "").toUpperCase() === g).sort(byKickoff);
2466
+ }
2467
+ function nextFixtureForTeam(code, opts = {}) {
2468
+ const from = opts.from ?? /* @__PURE__ */ new Date();
2469
+ return fixturesByTeam(code, opts.fixtures ?? SCHEDULE).find(
2470
+ (m) => new Date(m.kickoff).getTime() >= from.getTime()
2471
+ );
2472
+ }
2473
+ function groups(fixtures = SCHEDULE) {
2474
+ const set = /* @__PURE__ */ new Set();
2475
+ for (const m of fixtures) if (m.group) set.add(m.group);
2476
+ return [...set].sort();
2477
+ }
2478
+ function blankRow(team) {
2479
+ return {
2480
+ team,
2481
+ played: 0,
2482
+ won: 0,
2483
+ drawn: 0,
2484
+ lost: 0,
2485
+ goalsFor: 0,
2486
+ goalsAgainst: 0,
2487
+ goalDiff: 0,
2488
+ points: 0
2489
+ };
2490
+ }
2491
+ function computeStandings(matches) {
2492
+ const rows = /* @__PURE__ */ new Map();
2493
+ const ensure = (t) => {
2494
+ let r = rows.get(t.code);
2495
+ if (!r) {
2496
+ r = blankRow(t);
2497
+ rows.set(t.code, r);
2498
+ }
2499
+ return r;
2500
+ };
2501
+ for (const m of matches) {
2502
+ const home = ensure(m.home);
2503
+ const away = ensure(m.away);
2504
+ if (!isFinished(m.status) || !m.score) continue;
2505
+ const { home: hg, away: ag } = m.score;
2506
+ home.played++;
2507
+ away.played++;
2508
+ home.goalsFor += hg;
2509
+ home.goalsAgainst += ag;
2510
+ away.goalsFor += ag;
2511
+ away.goalsAgainst += hg;
2512
+ if (hg > ag) {
2513
+ home.won++;
2514
+ away.lost++;
2515
+ home.points += 3;
2516
+ } else if (hg < ag) {
2517
+ away.won++;
2518
+ home.lost++;
2519
+ away.points += 3;
2520
+ } else {
2521
+ home.drawn++;
2522
+ away.drawn++;
2523
+ home.points++;
2524
+ away.points++;
2525
+ }
2526
+ }
2527
+ for (const r of rows.values()) r.goalDiff = r.goalsFor - r.goalsAgainst;
2528
+ return [...rows.values()].sort(
2529
+ (a, b) => b.points - a.points || b.goalDiff - a.goalDiff || b.goalsFor - a.goalsFor || a.team.name.localeCompare(b.team.name)
2530
+ );
2531
+ }
2532
+ var ESPN_SOCCER = "https://site.api.espn.com/apis/site/v2/sports/soccer";
2533
+ var DEFAULT_COMPETITION = "fifa.world";
2534
+ var DEFAULT_BASE = `${ESPN_SOCCER}/${DEFAULT_COMPETITION}`;
2535
+ var USER_AGENT = "claudinho/0.0 (+https://github.com/arturogarrido/claudinho)";
2536
+ function competitionBase(slug) {
2537
+ return `${ESPN_SOCCER}/${slug}`;
2538
+ }
2539
+ function mapStatus(st) {
2540
+ const name = (st?.type?.name ?? "").toUpperCase();
2541
+ const state = st?.type?.state ?? "";
2542
+ if (name.includes("HALFTIME")) return "HT";
2543
+ if (name.includes("POSTPONED")) return "POSTPONED";
2544
+ if (name.includes("CANCEL")) return "CANCELLED";
2545
+ if (state === "pre") return "SCHEDULED";
2546
+ if (state === "post") return "FT";
2547
+ if (state === "in") return "LIVE";
2548
+ return "SCHEDULED";
2549
+ }
2550
+ function parseMinute(st) {
2551
+ if (st?.type?.state !== "in") return void 0;
2552
+ const dc = st.displayClock?.match(/(\d+)/);
2553
+ if (dc) return parseInt(dc[1], 10);
2554
+ if (typeof st.clock === "number" && st.clock > 0) {
2555
+ return Math.floor(st.clock / 60) || void 0;
2556
+ }
2557
+ return void 0;
2558
+ }
2559
+ var SLUG_TO_STAGE = {
2560
+ "group-stage": "GROUP",
2561
+ "round-of-32": "R32",
2562
+ "round-of-16": "R16",
2563
+ quarterfinals: "QF",
2564
+ semifinals: "SF",
2565
+ "3rd-place-match": "3P",
2566
+ final: "F"
2567
+ };
2568
+ function stageFromSlug(slug) {
2569
+ if (slug && SLUG_TO_STAGE[slug]) return SLUG_TO_STAGE[slug];
2570
+ if (!slug) return "GROUP";
2571
+ return "FRIENDLY";
2572
+ }
2573
+ function toInt(s) {
2574
+ if (s == null || s === "") return void 0;
2575
+ const n = parseInt(s, 10);
2576
+ return Number.isFinite(n) ? n : void 0;
2577
+ }
2578
+ function toTeam(t) {
2579
+ const name = t?.displayName ?? t?.name ?? t?.location ?? t?.shortDisplayName ?? "TBD";
2580
+ const code = (t?.abbreviation ?? name.slice(0, 3)).toUpperCase();
2581
+ return { code, name, flag: nationToFlag(t?.displayName ?? t?.abbreviation ?? name) };
2582
+ }
2583
+ function mapEspnEvent(ev, ctx = {}) {
2584
+ const comp = ev.competitions?.[0];
2585
+ const competitors = comp?.competitors ?? [];
2586
+ const homeC = competitors.find((c) => c.homeAway === "home") ?? competitors[0];
2587
+ const awayC = competitors.find((c) => c.homeAway === "away") ?? competitors[1];
2588
+ const status = mapStatus(ev.status ?? comp?.status);
2589
+ const stage = stageFromSlug(ev.season?.slug);
2590
+ const home = toTeam(homeC?.team);
2591
+ const away = toTeam(awayC?.team);
2592
+ let group;
2593
+ if (stage === "GROUP" && ctx.groupByTeam) {
2594
+ group = ctx.groupByTeam[home.code] ?? ctx.groupByTeam[away.code];
2595
+ }
2596
+ const hs = toInt(homeC?.score);
2597
+ const as = toInt(awayC?.score);
2598
+ const hasScore = status !== "SCHEDULED" && hs !== void 0 && as !== void 0;
2599
+ return {
2600
+ id: ev.id,
2601
+ stage,
2602
+ group,
2603
+ kickoff: ev.date,
2604
+ venue: comp?.venue?.fullName ?? "",
2605
+ home,
2606
+ away,
2607
+ score: hasScore ? { home: hs, away: as } : void 0,
2608
+ minute: parseMinute(ev.status ?? comp?.status),
2609
+ status,
2610
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
2611
+ };
2612
+ }
2613
+ function toEspnDate(d) {
2614
+ return d.replace(/\D/g, "").slice(0, 8);
2615
+ }
2616
+ var EspnAdapter = class {
2617
+ constructor(opts = {}) {
2618
+ this.opts = opts;
2619
+ }
2620
+ opts;
2621
+ name = "espn";
2622
+ capabilities = { push: false, latencyHintSec: 45 };
2623
+ /** Cached team-code -> group-letter map (built lazily from standings). */
2624
+ groupMap;
2625
+ async fetchByDate(dateISO) {
2626
+ return this.fetchScoreboard(toEspnDate(dateISO));
2627
+ }
2628
+ async fetchWindow(startDate, endDate) {
2629
+ return this.fetchScoreboard(`${toEspnDate(startDate)}-${toEspnDate(endDate)}`);
2630
+ }
2631
+ async fetchLive() {
2632
+ const today = await this.fetchScoreboard();
2633
+ return today.filter((m) => m.status === "LIVE" || m.status === "HT");
2634
+ }
2635
+ /**
2636
+ * Build (and cache) a team-code -> group-letter map from the standings
2637
+ * endpoint. Best-effort: returns {} if standings are unavailable.
2638
+ */
2639
+ async fetchGroupMap(force = false) {
2640
+ if (this.groupMap && !force) return this.groupMap;
2641
+ const base = this.opts.baseUrl ?? DEFAULT_BASE;
2642
+ const standingsUrl = `${base.replace("/apis/site/v2/", "/apis/v2/")}/standings`;
2643
+ const map = {};
2644
+ try {
2645
+ const data = await this.get(standingsUrl);
2646
+ for (const child of data.children ?? []) {
2647
+ const letter = (child.name ?? child.abbreviation ?? "").match(/Group\s+([A-L])/i)?.[1]?.toUpperCase();
2648
+ if (!letter) continue;
2649
+ for (const e of child.standings?.entries ?? []) {
2650
+ const code = e.team?.abbreviation?.toUpperCase();
2651
+ if (code) map[code] = letter;
2652
+ }
2653
+ }
2654
+ } catch {
2655
+ }
2656
+ this.groupMap = map;
2657
+ return map;
2658
+ }
2659
+ async fetchScoreboard(dates) {
2660
+ const base = this.opts.baseUrl ?? DEFAULT_BASE;
2661
+ const url = new URL(`${base}/scoreboard`);
2662
+ url.searchParams.set("limit", "300");
2663
+ if (dates) url.searchParams.set("dates", dates);
2664
+ const groupByTeam = this.opts.enrichGroups === false ? {} : await this.fetchGroupMap();
2665
+ const data = await this.get(url.toString());
2666
+ return (data.events ?? []).map((ev) => mapEspnEvent(ev, { groupByTeam }));
2667
+ }
2668
+ async get(url) {
2669
+ const doFetch = this.opts.fetchImpl ?? fetch;
2670
+ const controller = new AbortController();
2671
+ const timer = setTimeout(
2672
+ () => controller.abort(),
2673
+ this.opts.timeoutMs ?? 15e3
2674
+ );
2675
+ try {
2676
+ const res = await doFetch(url, {
2677
+ signal: controller.signal,
2678
+ headers: { Accept: "application/json", "User-Agent": USER_AGENT }
2679
+ });
2680
+ if (!res.ok) {
2681
+ throw new Error(`ESPN request failed: ${res.status} ${res.statusText}`);
2682
+ }
2683
+ return await res.json();
2684
+ } finally {
2685
+ clearTimeout(timer);
2686
+ }
2687
+ }
2688
+ };
2689
+ function resolveCompetition(explicit) {
2690
+ if (explicit) return explicit;
2691
+ if (typeof process !== "undefined" && process.env?.CLAUDINHO_COMPETITION) {
2692
+ return process.env.CLAUDINHO_COMPETITION;
2693
+ }
2694
+ return DEFAULT_COMPETITION;
2695
+ }
2696
+ function makeAdapter(source = "espn") {
2697
+ switch (source) {
2698
+ case "espn":
2699
+ default: {
2700
+ const competition = resolveCompetition();
2701
+ const baseUrl = competition === DEFAULT_COMPETITION ? void 0 : competitionBase(competition);
2702
+ return new EspnAdapter({ baseUrl });
2703
+ }
2704
+ }
2705
+ }
2706
+ function mergeLive(base, live) {
2707
+ const byId = new Map(base.map((m) => [m.id, m]));
2708
+ for (const m of live) byId.set(m.id, m);
2709
+ return [...byId.values()];
2710
+ }
2711
+ async function getMatchesForDate(adapter, dateISO) {
2712
+ const base = allFixtures();
2713
+ try {
2714
+ const live = await adapter.fetchByDate(dateISO);
2715
+ return { matches: mergeLive(base, live), degraded: false };
2716
+ } catch {
2717
+ return { matches: base, degraded: true };
2718
+ }
2719
+ }
2720
+ async function getLiveMatches(adapter) {
2721
+ try {
2722
+ return { matches: await adapter.fetchLive(), degraded: false };
2723
+ } catch {
2724
+ return { matches: [], degraded: true };
2725
+ }
2726
+ }
2727
+
2728
+ // src/commands.ts
2729
+ import Table from "cli-table3";
2730
+
2731
+ // src/format.ts
2732
+ import pc from "picocolors";
2733
+ function paint(enabled) {
2734
+ const id = (s) => s;
2735
+ if (!enabled) {
2736
+ return {
2737
+ dim: id,
2738
+ bold: id,
2739
+ green: id,
2740
+ yellow: id,
2741
+ red: id,
2742
+ cyan: id,
2743
+ gray: id
2744
+ };
2745
+ }
2746
+ return {
2747
+ dim: pc.dim,
2748
+ bold: pc.bold,
2749
+ green: pc.green,
2750
+ yellow: pc.yellow,
2751
+ red: pc.red,
2752
+ cyan: pc.cyan,
2753
+ gray: pc.gray
2754
+ };
2755
+ }
2756
+ function painterFor(cfg) {
2757
+ return paint(cfg.color);
2758
+ }
2759
+ function statusToken(m, t, c) {
2760
+ switch (m.status) {
2761
+ case "LIVE":
2762
+ return c.green(`${m.minute ? `${m.minute}'` : t("status.live")}`);
2763
+ case "HT":
2764
+ return c.yellow(t("status.ht"));
2765
+ case "FT":
2766
+ return c.gray(t("status.ft"));
2767
+ case "POSTPONED":
2768
+ return c.red(t("status.postponed"));
2769
+ case "CANCELLED":
2770
+ return c.red(t("status.cancelled"));
2771
+ case "SCHEDULED":
2772
+ default:
2773
+ return "";
2774
+ }
2775
+ }
2776
+ function matchLine(m, cfg, t, c) {
2777
+ const home = `${m.home.flag} ${m.home.name}`;
2778
+ const away = `${m.away.name} ${m.away.flag}`;
2779
+ const mid = isLive(m.status) || m.status === "FT" ? c.bold(scoreline(m)) : c.dim("vs");
2780
+ const left = `${home.padEnd(22)} ${mid.padStart(3)} ${away}`;
2781
+ let right = "";
2782
+ if (m.status === "SCHEDULED") {
2783
+ right = c.dim(
2784
+ `${formatKickoff(m.kickoff, { tz: cfg.tz, locale: cfg.lang })}`
2785
+ );
2786
+ } else {
2787
+ right = statusToken(m, t, c);
2788
+ }
2789
+ return ` ${left} ${right}`.trimEnd();
2790
+ }
2791
+ function header(text, c) {
2792
+ return c.bold(c.cyan(text));
2793
+ }
2794
+ function disclaimer(t, c) {
2795
+ return c.dim(t("disclaimer"));
2796
+ }
2797
+
2798
+ // src/cache.ts
2799
+ import {
2800
+ closeSync,
2801
+ mkdirSync,
2802
+ openSync,
2803
+ readFileSync,
2804
+ renameSync,
2805
+ rmSync,
2806
+ statSync,
2807
+ writeSync
2808
+ } from "fs";
2809
+ import { homedir } from "os";
2810
+ import { join } from "path";
2811
+ var LOCK_STALE_MS = 6e4;
2812
+ function cacheDir() {
2813
+ const base = process.env.XDG_CACHE_HOME || join(homedir(), ".cache");
2814
+ return join(base, "claudinho");
2815
+ }
2816
+ function cachePath() {
2817
+ return join(cacheDir(), "state.json");
2818
+ }
2819
+ function lockPath() {
2820
+ return join(cacheDir(), "refresh.lock");
2821
+ }
2822
+ function readState() {
2823
+ try {
2824
+ return JSON.parse(readFileSync(cachePath(), "utf8"));
2825
+ } catch {
2826
+ return void 0;
2827
+ }
2828
+ }
2829
+ function writeState(state) {
2830
+ const dir = cacheDir();
2831
+ mkdirSync(dir, { recursive: true });
2832
+ const tmp = join(dir, `state.${process.pid}.tmp`);
2833
+ writeFileSync_(tmp, JSON.stringify(state));
2834
+ renameSync(tmp, cachePath());
2835
+ }
2836
+ function writeFileSync_(path, data) {
2837
+ const fd = openSync(path, "w");
2838
+ try {
2839
+ writeSync(fd, data);
2840
+ } finally {
2841
+ closeSync(fd);
2842
+ }
2843
+ }
2844
+ function ageMs(state, now = Date.now()) {
2845
+ if (!state) return Infinity;
2846
+ const t = Date.parse(state.updatedAt);
2847
+ return Number.isFinite(t) ? now - t : Infinity;
2848
+ }
2849
+ function lockAgeMs(now = Date.now()) {
2850
+ const lp = lockPath();
2851
+ try {
2852
+ const contents = readFileSync(lp, "utf8");
2853
+ const written = Number.parseInt(contents.split(/\s+/)[1] ?? "", 10);
2854
+ if (Number.isFinite(written)) return now - written;
2855
+ } catch {
2856
+ return Infinity;
2857
+ }
2858
+ try {
2859
+ return now - statSync(lp).mtimeMs;
2860
+ } catch {
2861
+ return Infinity;
2862
+ }
2863
+ }
2864
+ function isLockFresh(now = Date.now()) {
2865
+ return lockAgeMs(now) < LOCK_STALE_MS;
2866
+ }
2867
+ function acquireLock(now = Date.now()) {
2868
+ mkdirSync(cacheDir(), { recursive: true });
2869
+ const lp = lockPath();
2870
+ try {
2871
+ const fd = openSync(lp, "wx");
2872
+ try {
2873
+ writeSync(fd, `${process.pid} ${now}`);
2874
+ } finally {
2875
+ closeSync(fd);
2876
+ }
2877
+ return true;
2878
+ } catch {
2879
+ if (lockAgeMs(now) > LOCK_STALE_MS) {
2880
+ try {
2881
+ rmSync(lp, { force: true });
2882
+ } catch {
2883
+ return false;
2884
+ }
2885
+ try {
2886
+ const fd = openSync(lp, "wx");
2887
+ try {
2888
+ writeSync(fd, `${process.pid} ${now}`);
2889
+ } finally {
2890
+ closeSync(fd);
2891
+ }
2892
+ return true;
2893
+ } catch {
2894
+ return false;
2895
+ }
2896
+ }
2897
+ return false;
2898
+ }
2899
+ }
2900
+ function releaseLock() {
2901
+ try {
2902
+ rmSync(lockPath(), { force: true });
2903
+ } catch {
2904
+ }
2905
+ }
2906
+
2907
+ // src/statusline.ts
2908
+ var LIVE_WINDOW_MS = 140 * 6e4;
2909
+ var DISPLAY_STALE_MS = 5 * 6e4;
2910
+ var LIVE_TTL_MS = 15e3;
2911
+ function inLiveWindow(now = Date.now(), fixtures = allFixtures()) {
2912
+ for (const m of fixtures) {
2913
+ const k = Date.parse(m.kickoff);
2914
+ if (now >= k && now <= k + LIVE_WINDOW_MS) return true;
2915
+ }
2916
+ return false;
2917
+ }
2918
+ function nextOverall(now, fixtures = allFixtures()) {
2919
+ return [...fixtures].sort(byKickoff).find((m) => Date.parse(m.kickoff) >= now);
2920
+ }
2921
+ function matchSegment(m, compact) {
2922
+ const minute = m.status === "HT" ? "HT" : m.minute ? `${m.minute}'` : "LIVE";
2923
+ const home = compact ? m.home.flag : `${m.home.flag} ${m.home.code}`;
2924
+ const away = compact ? m.away.flag : `${m.away.code} ${m.away.flag}`;
2925
+ return `${home} ${scoreline(m)} ${away} ${minute}`;
2926
+ }
2927
+ function liveMatchesFromCache(state, nowMs = Date.now()) {
2928
+ const fresh = state && ageMs(state, nowMs) < DISPLAY_STALE_MS;
2929
+ const liveArr = fresh && Array.isArray(state?.live) ? state.live : [];
2930
+ return liveArr.filter(
2931
+ (m) => !!m && typeof m === "object" && isLive(m.status) && !!m.home?.code && !!m.away?.code
2932
+ );
2933
+ }
2934
+ function renderPrompt(state, opts = {}) {
2935
+ const now = opts.now ?? /* @__PURE__ */ new Date();
2936
+ const nowMs = now.getTime();
2937
+ const compact = opts.compact ?? true;
2938
+ const team = opts.team?.toUpperCase();
2939
+ const live = liveMatchesFromCache(state, nowMs);
2940
+ if (team) {
2941
+ const mine = live.find((m) => m.home?.code === team || m.away?.code === team);
2942
+ if (mine) return `\u26BD ${matchSegment(mine, compact)}`;
2943
+ } else if (live.length > 0) {
2944
+ const max = opts.max && opts.max > 0 ? opts.max : live.length;
2945
+ const shown = live.slice(0, max);
2946
+ let line2 = "\u26BD " + shown.map((m) => matchSegment(m, compact)).join(" \xB7 ");
2947
+ const overflow = live.length - shown.length;
2948
+ if (overflow > 0) line2 += ` +${overflow}`;
2949
+ return line2;
2950
+ }
2951
+ const next = team ? nextFixtureForTeam(team, { from: now }) : nextOverall(nowMs);
2952
+ if (next) {
2953
+ return `${next.home.flag} vs ${next.away.flag} in ${countdown(next.kickoff, now)}`;
2954
+ }
2955
+ return "\u26BD \u2014";
2956
+ }
2957
+
2958
+ // src/hook.ts
2959
+ function line(m) {
2960
+ const minute = m.status === "HT" ? "half-time" : m.minute ? `${m.minute}'` : "live";
2961
+ return `${m.home.flag} ${m.home.name} ${scoreline(m)} ${m.away.name} ${m.away.flag} (${minute})`;
2962
+ }
2963
+ function renderHook(state, opts = {}) {
2964
+ const now = opts.now ?? /* @__PURE__ */ new Date();
2965
+ const team = opts.team?.toUpperCase();
2966
+ let live = liveMatchesFromCache(state, now.getTime());
2967
+ if (live.length === 0) return "";
2968
+ if (team) {
2969
+ live = [...live].sort((a, b) => {
2970
+ const aHas = a.home.code === team || a.away.code === team ? 0 : 1;
2971
+ const bHas = b.home.code === team || b.away.code === team ? 0 : 1;
2972
+ return aHas - bHas;
2973
+ });
2974
+ }
2975
+ const lines = live.map(line).join("\n");
2976
+ return `[Claudinho \u2014 live football scores right now]
2977
+ ${lines}`;
2978
+ }
2979
+ function hookContext(opts = {}) {
2980
+ return renderHook(readState(), opts);
2981
+ }
2982
+
2983
+ // src/refresh.ts
2984
+ import { spawn } from "child_process";
2985
+ var MIN_REFRESH_MS = 12e3;
2986
+ function liveWindowActive(nowMs) {
2987
+ if (resolveCompetition() !== DEFAULT_COMPETITION) return true;
2988
+ return inLiveWindow(nowMs);
2989
+ }
2990
+ function liveAdapter() {
2991
+ const competition = resolveCompetition();
2992
+ if (competition === DEFAULT_COMPETITION) {
2993
+ return new EspnAdapter({ enrichGroups: false });
2994
+ }
2995
+ return makeAdapter("espn");
2996
+ }
2997
+ async function runRefresh(opts = {}) {
2998
+ const now = opts.now ?? /* @__PURE__ */ new Date();
2999
+ const source = opts.source ?? "espn";
3000
+ if (ageMs(readState(), now.getTime()) < MIN_REFRESH_MS) return;
3001
+ if (!acquireLock()) return;
3002
+ try {
3003
+ let live = [];
3004
+ let degraded = false;
3005
+ if (liveWindowActive(now.getTime())) {
3006
+ try {
3007
+ live = await liveAdapter().fetchLive();
3008
+ } catch {
3009
+ degraded = true;
3010
+ }
3011
+ }
3012
+ writeState({ updatedAt: now.toISOString(), live, degraded, source });
3013
+ } finally {
3014
+ releaseLock();
3015
+ }
3016
+ }
3017
+ function shouldRefresh(now = Date.now()) {
3018
+ if (!liveWindowActive(now)) return false;
3019
+ if (isLockFresh(now)) return false;
3020
+ return ageMs(readState(), now) > LIVE_TTL_MS;
3021
+ }
3022
+ function spawnRefresh(source) {
3023
+ try {
3024
+ const entry = process.argv[1];
3025
+ if (!entry) return;
3026
+ const child = spawn(process.execPath, [entry, "_refresh", "--source", source], {
3027
+ detached: true,
3028
+ stdio: "ignore"
3029
+ });
3030
+ child.unref();
3031
+ } catch {
3032
+ }
3033
+ }
3034
+
3035
+ // src/install.ts
3036
+ import {
3037
+ copyFileSync,
3038
+ existsSync,
3039
+ mkdirSync as mkdirSync2,
3040
+ readFileSync as readFileSync2,
3041
+ writeFileSync
3042
+ } from "fs";
3043
+ import { homedir as homedir2 } from "os";
3044
+ import { dirname, join as join2 } from "path";
3045
+ function claudeSettingsPath() {
3046
+ return join2(homedir2(), ".claude", "settings.json");
3047
+ }
3048
+ function backupOnce(path) {
3049
+ const bak = `${path}.claudinho.bak`;
3050
+ if (existsSync(path) && !existsSync(bak)) copyFileSync(path, bak);
3051
+ }
3052
+ function initStatusline(opts = {}) {
3053
+ const path = opts.path ?? claudeSettingsPath();
3054
+ const sl = { type: "command", command: opts.command ?? "claudinho prompt" };
3055
+ const snippet = JSON.stringify({ statusLine: sl }, null, 2);
3056
+ if (opts.print) {
3057
+ return { action: "printed", path, message: snippet };
3058
+ }
3059
+ let settings = {};
3060
+ if (existsSync(path)) {
3061
+ try {
3062
+ settings = JSON.parse(readFileSync2(path, "utf8"));
3063
+ } catch {
3064
+ return {
3065
+ action: "manual",
3066
+ path,
3067
+ message: `Could not parse ${path}. Add this manually:
3068
+ ${snippet}`
3069
+ };
3070
+ }
3071
+ }
3072
+ const existing = settings.statusLine;
3073
+ if (existing?.command?.includes("claudinho")) {
3074
+ return { action: "already", path, message: `Statusline already uses claudinho (${path}).` };
3075
+ }
3076
+ backupOnce(path);
3077
+ settings.statusLine = sl;
3078
+ mkdirSync2(dirname(path), { recursive: true });
3079
+ writeFileSync(path, JSON.stringify(settings, null, 2) + "\n", "utf8");
3080
+ return {
3081
+ action: "written",
3082
+ path,
3083
+ message: `Statusline configured in ${path}. Restart Claude Code to see it.`
3084
+ };
3085
+ }
3086
+ var HOOK_EVENT = "UserPromptSubmit";
3087
+ var HOOK_COMMAND = "claudinho hook";
3088
+ function initHook(opts = {}) {
3089
+ const path = opts.path ?? claudeSettingsPath();
3090
+ const command = opts.command ?? HOOK_COMMAND;
3091
+ const snippet = JSON.stringify(
3092
+ { hooks: { [HOOK_EVENT]: [{ hooks: [{ type: "command", command }] }] } },
3093
+ null,
3094
+ 2
3095
+ );
3096
+ if (opts.print) return { action: "printed", path, message: snippet };
3097
+ let settings = {};
3098
+ if (existsSync(path)) {
3099
+ try {
3100
+ settings = JSON.parse(readFileSync2(path, "utf8"));
3101
+ } catch {
3102
+ return {
3103
+ action: "manual",
3104
+ path,
3105
+ message: `Could not parse ${path}. Add this manually:
3106
+ ${snippet}`
3107
+ };
3108
+ }
3109
+ }
3110
+ const hooks = settings.hooks ??= {};
3111
+ const matchers = hooks[HOOK_EVENT] ??= [];
3112
+ const already = matchers.some(
3113
+ (m) => (m.hooks ?? []).some((h) => typeof h.command === "string" && h.command.includes("claudinho"))
3114
+ );
3115
+ if (already) {
3116
+ return { action: "already", path, message: `UserPromptSubmit hook already uses claudinho (${path}).` };
3117
+ }
3118
+ backupOnce(path);
3119
+ matchers.push({ hooks: [{ type: "command", command }] });
3120
+ mkdirSync2(dirname(path), { recursive: true });
3121
+ writeFileSync(path, JSON.stringify(settings, null, 2) + "\n", "utf8");
3122
+ return {
3123
+ action: "written",
3124
+ path,
3125
+ message: `Live-score hook configured in ${path}. Restart Claude Code; during matches, the score is injected into context on each prompt.`
3126
+ };
3127
+ }
3128
+
3129
+ // src/commands.ts
3130
+ function adapterFor({ cfg, adapter }) {
3131
+ return adapter ?? makeAdapter(cfg.source);
3132
+ }
3133
+ function out(line2 = "") {
3134
+ process.stdout.write(line2 + "\n");
3135
+ }
3136
+ function emitJson(data) {
3137
+ out(JSON.stringify(data, null, 2));
3138
+ }
3139
+ var InputError = class extends Error {
3140
+ };
3141
+ function precheck(cfg, t, date) {
3142
+ if (cfg.langRequestedUnsupported) {
3143
+ process.stderr.write(t("warn.lang", { lang: cfg.langRequestedUnsupported }) + "\n");
3144
+ }
3145
+ if (cfg.tz && !isValidTimeZone(cfg.tz)) {
3146
+ process.stderr.write(t("warn.tz", { tz: cfg.tz }) + "\n");
3147
+ }
3148
+ if (date !== void 0 && !isValidDate(date)) {
3149
+ throw new InputError(t("err.date", { date }));
3150
+ }
3151
+ }
3152
+ async function cmdToday(date, ctx) {
3153
+ const { cfg, t } = ctx;
3154
+ precheck(cfg, t, date);
3155
+ const adapter = adapterFor(ctx);
3156
+ const targetDate = date ?? localDate((/* @__PURE__ */ new Date()).toISOString(), cfg.tz);
3157
+ const { matches, degraded } = await getMatchesForDate(adapter, targetDate);
3158
+ const todays = fixturesByDate(targetDate, matches);
3159
+ if (cfg.json) {
3160
+ emitJson({ date: targetDate, degraded, matches: todays });
3161
+ return;
3162
+ }
3163
+ const c = painterFor(cfg);
3164
+ const title = date === void 0 ? t("today.title") : t("today.on");
3165
+ out();
3166
+ out(header(`${title} \xB7 ${targetDate}`, c));
3167
+ out();
3168
+ if (todays.length === 0) {
3169
+ out(c.dim(" " + t("today.none")));
3170
+ } else {
3171
+ for (const m of todays) out(matchLine(m, cfg, t, c));
3172
+ }
3173
+ out();
3174
+ out(disclaimer(t, c));
3175
+ }
3176
+ async function cmdLive(ctx) {
3177
+ const { cfg, t } = ctx;
3178
+ precheck(cfg, t);
3179
+ const adapter = adapterFor(ctx);
3180
+ const { matches, degraded } = await getLiveMatches(adapter);
3181
+ if (cfg.json) {
3182
+ emitJson({ degraded, matches });
3183
+ return;
3184
+ }
3185
+ const c = painterFor(cfg);
3186
+ out();
3187
+ out(header(t("live.title"), c));
3188
+ out();
3189
+ if (matches.length === 0) {
3190
+ out(c.dim(" " + t("live.none")));
3191
+ } else {
3192
+ for (const m of matches) out(matchLine(m, cfg, t, c));
3193
+ }
3194
+ out();
3195
+ out(disclaimer(t, c));
3196
+ }
3197
+ async function cmdNext(team, { cfg, t }) {
3198
+ precheck(cfg, t);
3199
+ const code = team.toUpperCase();
3200
+ const fixture = nextFixtureForTeam(code);
3201
+ if (cfg.json) {
3202
+ emitJson({ team: code, fixture: fixture ?? null });
3203
+ return;
3204
+ }
3205
+ const c = painterFor(cfg);
3206
+ out();
3207
+ if (!fixture) {
3208
+ out(c.dim(" " + t("next.none", { team: code })));
3209
+ out();
3210
+ out(disclaimer(t, c));
3211
+ return;
3212
+ }
3213
+ out(header(t("next.label", { team: code }), c));
3214
+ out();
3215
+ out(matchLine(fixture, cfg, t, c));
3216
+ out(
3217
+ " " + c.dim(
3218
+ `${formatKickoff(fixture.kickoff, { tz: cfg.tz, locale: cfg.lang })} \xB7 ` + t("next.in", { countdown: countdown(fixture.kickoff) })
3219
+ )
3220
+ );
3221
+ out();
3222
+ out(disclaimer(t, c));
3223
+ }
3224
+ async function cmdTable(group, ctx) {
3225
+ const { cfg, t } = ctx;
3226
+ precheck(cfg, t);
3227
+ const adapter = adapterFor(ctx);
3228
+ let matches = allFixtures();
3229
+ try {
3230
+ const live = await adapter.fetchByDate(localDate((/* @__PURE__ */ new Date()).toISOString(), cfg.tz));
3231
+ matches = mergeLive(matches, live);
3232
+ } catch {
3233
+ }
3234
+ const wanted = group ? [group.toUpperCase()] : groups(matches);
3235
+ if (cfg.json) {
3236
+ const tables = wanted.map((g) => ({
3237
+ group: g,
3238
+ standings: computeStandings(fixturesByGroup(g, matches))
3239
+ }));
3240
+ emitJson(group ? tables[0] ?? null : tables);
3241
+ return;
3242
+ }
3243
+ const c = painterFor(cfg);
3244
+ for (const g of wanted) {
3245
+ const rows = computeStandings(fixturesByGroup(g, matches));
3246
+ if (rows.length === 0) {
3247
+ out();
3248
+ out(c.dim(" " + t("table.none", { group: g })));
3249
+ continue;
3250
+ }
3251
+ out();
3252
+ out(header(t("table.title", { group: g }), c));
3253
+ const table = new Table({
3254
+ head: [
3255
+ t("col.team"),
3256
+ t("col.p"),
3257
+ t("col.w"),
3258
+ t("col.d"),
3259
+ t("col.l"),
3260
+ t("col.gd"),
3261
+ t("col.pts")
3262
+ ],
3263
+ colAligns: ["left", "right", "right", "right", "right", "right", "right"],
3264
+ style: { head: cfg.color ? ["cyan"] : [], border: cfg.color ? ["gray"] : [] }
3265
+ });
3266
+ for (const r of rows) {
3267
+ table.push([
3268
+ `${r.team.flag} ${r.team.name}`,
3269
+ r.played,
3270
+ r.won,
3271
+ r.drawn,
3272
+ r.lost,
3273
+ r.goalDiff > 0 ? `+${r.goalDiff}` : `${r.goalDiff}`,
3274
+ cfg.color ? c.bold(`${r.points}`) : r.points
3275
+ ]);
3276
+ }
3277
+ out(table.toString());
3278
+ }
3279
+ out();
3280
+ out(disclaimer(t, c));
3281
+ }
3282
+ function cmdPrompt({ cfg }) {
3283
+ try {
3284
+ const team = process.env.CLAUDINHO_TEAM;
3285
+ const compact = !["0", "false", "no"].includes(
3286
+ (process.env.CLAUDINHO_COMPACT ?? "").toLowerCase()
3287
+ );
3288
+ const maxRaw = Number.parseInt(process.env.CLAUDINHO_MAX ?? "", 10);
3289
+ const max = Number.isFinite(maxRaw) && maxRaw > 0 ? maxRaw : void 0;
3290
+ const state = readState();
3291
+ out(renderPrompt(state, { team, compact, max }));
3292
+ if (shouldRefresh()) spawnRefresh(cfg.source);
3293
+ } catch {
3294
+ out("");
3295
+ }
3296
+ }
3297
+ function cmdHook({ cfg }) {
3298
+ try {
3299
+ const team = process.env.CLAUDINHO_TEAM;
3300
+ const ctx = hookContext({ team });
3301
+ if (ctx) out(ctx);
3302
+ if (shouldRefresh()) spawnRefresh(cfg.source);
3303
+ } catch {
3304
+ }
3305
+ }
3306
+ async function cmdRefresh({ cfg }) {
3307
+ await runRefresh({ source: cfg.source });
3308
+ }
3309
+ function cmdInitStatusline(opts, { cfg }) {
3310
+ const res = initStatusline({ print: opts.print });
3311
+ const c = painterFor(cfg);
3312
+ if (res.action === "printed") {
3313
+ out(res.message);
3314
+ return;
3315
+ }
3316
+ const mark = res.action === "written" ? c.green("\u2713") : res.action === "already" ? c.cyan("\u2022") : c.yellow("!");
3317
+ out(`${mark} ${res.message}`);
3318
+ }
3319
+ function cmdInitHook(opts, { cfg }) {
3320
+ const res = initHook({ print: opts.print });
3321
+ const c = painterFor(cfg);
3322
+ if (res.action === "printed") {
3323
+ out(res.message);
3324
+ return;
3325
+ }
3326
+ const mark = res.action === "written" ? c.green("\u2713") : res.action === "already" ? c.cyan("\u2022") : c.yellow("!");
3327
+ out(`${mark} ${res.message}`);
3328
+ }
3329
+ async function cmdMatch(id, ctx) {
3330
+ const { cfg, t } = ctx;
3331
+ precheck(cfg, t);
3332
+ const adapter = adapterFor(ctx);
3333
+ let match = allFixtures().find((m) => m.id === id);
3334
+ try {
3335
+ if (match) {
3336
+ const live = await adapter.fetchByDate(match.kickoff.slice(0, 10));
3337
+ match = live.find((m) => m.id === id) ?? match;
3338
+ }
3339
+ } catch {
3340
+ }
3341
+ if (cfg.json) {
3342
+ emitJson({ match: match ?? null });
3343
+ return;
3344
+ }
3345
+ const c = painterFor(cfg);
3346
+ out();
3347
+ if (!match) {
3348
+ out(c.dim(" " + t("match.none", { id })));
3349
+ out();
3350
+ out(disclaimer(t, c));
3351
+ return;
3352
+ }
3353
+ const stageLabel = match.group ? `${match.stage} ${match.group}` : match.stage;
3354
+ out(header(`${match.home.name} ${scoreline(match)} ${match.away.name}`, c));
3355
+ out(" " + c.dim(`${stageLabel} \xB7 ${match.venue}`));
3356
+ out(
3357
+ " " + c.dim(
3358
+ `${formatKickoff(match.kickoff, { tz: cfg.tz, locale: cfg.lang })} ${statusToken(match, t, c)}`.trimEnd()
3359
+ )
3360
+ );
3361
+ if (match.events?.length) {
3362
+ out();
3363
+ for (const e of match.events) {
3364
+ out(` ${e.minute}' ${e.type} ${e.teamCode}${e.player ? ` \u2014 ${e.player}` : ""}`);
3365
+ }
3366
+ }
3367
+ out();
3368
+ out(disclaimer(t, c));
3369
+ }
3370
+
3371
+ // src/index.ts
3372
+ function handlePipeError(stream) {
3373
+ stream.on("error", (err) => {
3374
+ if (err.code === "EPIPE") process.exit(0);
3375
+ throw err;
3376
+ });
3377
+ }
3378
+ handlePipeError(process.stdout);
3379
+ handlePipeError(process.stderr);
3380
+ var VERSION = "0.1.0";
3381
+ var DISCLAIMER = "Claudinho is an independent fan project. Not affiliated with or endorsed by FIFA or Anthropic.";
3382
+ function ctxFrom(cmd) {
3383
+ const root = cmd.parent ?? cmd;
3384
+ const opts = root.opts();
3385
+ const cfg = resolveConfig(opts);
3386
+ return { cfg, t: makeT(cfg.lang) };
3387
+ }
3388
+ function fail(err) {
3389
+ const prefix = err instanceof InputError ? "" : "claudinho: ";
3390
+ process.stderr.write(`${prefix}${err.message}
3391
+ `);
3392
+ process.exit(1);
3393
+ }
3394
+ var program = new Command();
3395
+ program.name("claudinho").description("The 2026 football tournament in your terminal.\n" + DISCLAIMER).version(VERSION, "-v, --version").option("--lang <code>", "language: en, es, pt, fr").option("--tz <zone>", "IANA timezone, e.g. America/Mexico_City").option("--json", "output JSON (for scripting)").option("--no-color", "disable ANSI colors").option("--source <name>", "data source (default: espn)");
3396
+ program.command("today").description("show a day's fixtures (default: today)").argument("[date]", "date as YYYY-MM-DD").action(async (date, _opts, cmd) => {
3397
+ try {
3398
+ await cmdToday(date, ctxFrom(cmd));
3399
+ } catch (e) {
3400
+ fail(e);
3401
+ }
3402
+ });
3403
+ program.command("live").description("show matches in play right now").action(async (_opts, cmd) => {
3404
+ try {
3405
+ await cmdLive(ctxFrom(cmd));
3406
+ } catch (e) {
3407
+ fail(e);
3408
+ }
3409
+ });
3410
+ program.command("next").description("show a team's next fixture").argument("<team>", "team code, e.g. MEX").action(async (team, _opts, cmd) => {
3411
+ try {
3412
+ await cmdNext(team, ctxFrom(cmd));
3413
+ } catch (e) {
3414
+ fail(e);
3415
+ }
3416
+ });
3417
+ program.command("table").description("show group standings (default: all groups)").argument("[group]", "group letter A-L").action(async (group, _opts, cmd) => {
3418
+ try {
3419
+ await cmdTable(group, ctxFrom(cmd));
3420
+ } catch (e) {
3421
+ fail(e);
3422
+ }
3423
+ });
3424
+ program.command("match").description("show a single match by id").argument("<id>", "match id").action(async (id, _opts, cmd) => {
3425
+ try {
3426
+ await cmdMatch(id, ctxFrom(cmd));
3427
+ } catch (e) {
3428
+ fail(e);
3429
+ }
3430
+ });
3431
+ program.command("prompt").description("print a one-line status (Claude Code statusline, tmux, Starship, \u2026)").action((_opts, cmd) => {
3432
+ cmdPrompt(ctxFrom(cmd));
3433
+ });
3434
+ program.command("init-statusline").description("configure the Claude Code statusline to use claudinho").option("--print", "print the settings snippet instead of writing it").action((opts, cmd) => {
3435
+ try {
3436
+ cmdInitStatusline(opts, ctxFrom(cmd));
3437
+ } catch (e) {
3438
+ fail(e);
3439
+ }
3440
+ });
3441
+ program.command("hook").description("print live-score context for a Claude Code UserPromptSubmit hook (silent off-match)").action((_opts, cmd) => {
3442
+ cmdHook(ctxFrom(cmd));
3443
+ });
3444
+ program.command("init-hook").description("wire the live-score hook into Claude Code (UserPromptSubmit)").option("--print", "print the settings snippet instead of writing it").action((opts, cmd) => {
3445
+ try {
3446
+ cmdInitHook(opts, ctxFrom(cmd));
3447
+ } catch (e) {
3448
+ fail(e);
3449
+ }
3450
+ });
3451
+ var refreshCmd = new Command("_refresh").description("(internal) refresh the statusline cache").action(async (_opts, cmd) => {
3452
+ try {
3453
+ await cmdRefresh(ctxFrom(cmd));
3454
+ } catch (e) {
3455
+ fail(e);
3456
+ }
3457
+ });
3458
+ program.addCommand(refreshCmd, { hidden: true });
3459
+ program.parseAsync().catch(fail);