@claudinho/cli 0.5.0 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +45 -13
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -2814,9 +2814,15 @@ var EspnAdapter = class {
|
|
|
2814
2814
|
async fetchWindow(startDate, endDate) {
|
|
2815
2815
|
return this.fetchScoreboard(`${toEspnDate(startDate)}-${toEspnDate(endDate)}`);
|
|
2816
2816
|
}
|
|
2817
|
+
/**
|
|
2818
|
+
* In-play matches from ESPN's DEFAULT scoreboard bucket only (no `dates`). This
|
|
2819
|
+
* single bucket misses a late kickoff ESPN files under an adjacent day, so it
|
|
2820
|
+
* is a fallback for window-less callers — the domain `getLiveMatches` wraps a
|
|
2821
|
+
* ±1-day window around this to catch boundary-crossing matches. Prefer it.
|
|
2822
|
+
*/
|
|
2817
2823
|
async fetchLive() {
|
|
2818
2824
|
const today = await this.fetchScoreboard();
|
|
2819
|
-
return today.filter((m) => m.status
|
|
2825
|
+
return today.filter((m) => isLive(m.status));
|
|
2820
2826
|
}
|
|
2821
2827
|
/** Standings endpoint URL (lives under apis/v2, not site/v2; derived from base). */
|
|
2822
2828
|
standingsUrl() {
|
|
@@ -2959,9 +2965,13 @@ async function getMatchById(adapter, id) {
|
|
|
2959
2965
|
return { match: base, degraded: true };
|
|
2960
2966
|
}
|
|
2961
2967
|
}
|
|
2962
|
-
async function getLiveMatches(adapter) {
|
|
2968
|
+
async function getLiveMatches(adapter, now = /* @__PURE__ */ new Date()) {
|
|
2963
2969
|
try {
|
|
2964
|
-
|
|
2970
|
+
const day = now.toISOString().slice(0, 10);
|
|
2971
|
+
const matches = adapter.fetchWindow ? (await adapter.fetchWindow(shiftUtcDate(day, -1), shiftUtcDate(day, 1))).filter(
|
|
2972
|
+
(m) => isLive(m.status)
|
|
2973
|
+
) : await adapter.fetchLive();
|
|
2974
|
+
return { matches, degraded: false, source: adapter.name };
|
|
2965
2975
|
} catch {
|
|
2966
2976
|
return { matches: [], degraded: true };
|
|
2967
2977
|
}
|
|
@@ -3460,6 +3470,9 @@ function formatShareSnippet(input, options = {}) {
|
|
|
3460
3470
|
blocks.push(card.join("\n"));
|
|
3461
3471
|
}
|
|
3462
3472
|
}
|
|
3473
|
+
if (input.degraded && input.matches.length > 0) {
|
|
3474
|
+
blocks.push("(Live data unavailable \u2014 showing the bundled schedule, not live scores.)");
|
|
3475
|
+
}
|
|
3463
3476
|
blocks.push(
|
|
3464
3477
|
shareFooter({
|
|
3465
3478
|
source: input.source,
|
|
@@ -3557,6 +3570,8 @@ var EN = {
|
|
|
3557
3570
|
"today.none": "No matches scheduled for this date.",
|
|
3558
3571
|
"live.title": "Live now",
|
|
3559
3572
|
"live.none": "No matches in play right now.",
|
|
3573
|
+
"live.degraded": "Live scores unavailable right now \u2014 couldn't reach the data provider.",
|
|
3574
|
+
"feed.degraded": "Live scores unavailable \u2014 showing the bundled schedule.",
|
|
3560
3575
|
"next.none": "No upcoming fixture found for {team}.",
|
|
3561
3576
|
"next.label": "Next up for {team}",
|
|
3562
3577
|
"next.in": "in {countdown}",
|
|
@@ -3589,6 +3604,8 @@ var ES = {
|
|
|
3589
3604
|
"today.none": "No hay partidos para esta fecha.",
|
|
3590
3605
|
"live.title": "En vivo",
|
|
3591
3606
|
"live.none": "No hay partidos en juego ahora mismo.",
|
|
3607
|
+
"live.degraded": "Marcadores en vivo no disponibles \u2014 no se pudo conectar con el proveedor de datos.",
|
|
3608
|
+
"feed.degraded": "Marcadores en vivo no disponibles \u2014 mostrando el calendario.",
|
|
3592
3609
|
"next.none": "No se encontr\xF3 pr\xF3ximo partido para {team}.",
|
|
3593
3610
|
"next.label": "Pr\xF3ximo partido de {team}",
|
|
3594
3611
|
"next.in": "en {countdown}",
|
|
@@ -3621,6 +3638,8 @@ var PT = {
|
|
|
3621
3638
|
"today.none": "Nenhum jogo para esta data.",
|
|
3622
3639
|
"live.title": "Ao vivo",
|
|
3623
3640
|
"live.none": "Nenhum jogo em andamento agora.",
|
|
3641
|
+
"live.degraded": "Placar ao vivo indispon\xEDvel \u2014 n\xE3o foi poss\xEDvel conectar ao provedor de dados.",
|
|
3642
|
+
"feed.degraded": "Placar ao vivo indispon\xEDvel \u2014 mostrando a tabela de jogos.",
|
|
3624
3643
|
"next.none": "Nenhum pr\xF3ximo jogo encontrado para {team}.",
|
|
3625
3644
|
"next.label": "Pr\xF3ximo jogo de {team}",
|
|
3626
3645
|
"next.in": "em {countdown}",
|
|
@@ -3653,6 +3672,8 @@ var FR = {
|
|
|
3653
3672
|
"today.none": "Aucun match pr\xE9vu pour cette date.",
|
|
3654
3673
|
"live.title": "En direct",
|
|
3655
3674
|
"live.none": "Aucun match en cours pour l'instant.",
|
|
3675
|
+
"live.degraded": "Scores en direct indisponibles \u2014 impossible de joindre le fournisseur de donn\xE9es.",
|
|
3676
|
+
"feed.degraded": "Scores en direct indisponibles \u2014 affichage du calendrier.",
|
|
3656
3677
|
"next.none": "Aucun prochain match trouv\xE9 pour {team}.",
|
|
3657
3678
|
"next.label": "Prochain match de {team}",
|
|
3658
3679
|
"next.in": "dans {countdown}",
|
|
@@ -4063,7 +4084,9 @@ async function runRefresh(opts = {}) {
|
|
|
4063
4084
|
let degraded = false;
|
|
4064
4085
|
if (liveWindowActive(now.getTime())) {
|
|
4065
4086
|
try {
|
|
4066
|
-
|
|
4087
|
+
const r = await getLiveMatches(liveAdapter(), now);
|
|
4088
|
+
live = r.matches;
|
|
4089
|
+
degraded = r.degraded;
|
|
4067
4090
|
} catch {
|
|
4068
4091
|
degraded = true;
|
|
4069
4092
|
}
|
|
@@ -4296,6 +4319,7 @@ async function cmdToday(date, ctx) {
|
|
|
4296
4319
|
}
|
|
4297
4320
|
}
|
|
4298
4321
|
out();
|
|
4322
|
+
if (degraded) out(c.dim(" " + t("feed.degraded")));
|
|
4299
4323
|
const src = dataSource(source, c);
|
|
4300
4324
|
if (src) out(src);
|
|
4301
4325
|
out(disclaimer(t, c));
|
|
@@ -4313,7 +4337,9 @@ async function cmdLive(ctx) {
|
|
|
4313
4337
|
out();
|
|
4314
4338
|
out(header(t("live.title"), c));
|
|
4315
4339
|
out();
|
|
4316
|
-
if (
|
|
4340
|
+
if (degraded) {
|
|
4341
|
+
out(c.dim(" " + t("live.degraded")));
|
|
4342
|
+
} else if (matches.length === 0) {
|
|
4317
4343
|
out(c.dim(" " + t("live.none")));
|
|
4318
4344
|
} else {
|
|
4319
4345
|
for (const m of matches) out(matchLine(m, cfg, t, c));
|
|
@@ -4502,6 +4528,7 @@ async function cmdMatch(id, ctx) {
|
|
|
4502
4528
|
for (const mline of marketBlock(marketSignal, match)) out(" " + c.dim(mline));
|
|
4503
4529
|
}
|
|
4504
4530
|
out();
|
|
4531
|
+
if (degraded) out(c.dim(" " + t("feed.degraded")));
|
|
4505
4532
|
const src = dataSource(liveSource, c);
|
|
4506
4533
|
if (src) out(src);
|
|
4507
4534
|
out(disclaimer(t, c));
|
|
@@ -4629,6 +4656,7 @@ function emitShare(ctx, e, copy) {
|
|
|
4629
4656
|
target: e.target,
|
|
4630
4657
|
...e.team ? { team: e.team } : {},
|
|
4631
4658
|
source: e.input.source ?? null,
|
|
4659
|
+
degraded: e.input.degraded ?? false,
|
|
4632
4660
|
informationalOnly: true,
|
|
4633
4661
|
style: e.options.style ?? "social",
|
|
4634
4662
|
snippet,
|
|
@@ -4688,7 +4716,7 @@ async function cmdShare(target, team, opts, ctx) {
|
|
|
4688
4716
|
const copy = opts.copy === true;
|
|
4689
4717
|
if (target === "live") {
|
|
4690
4718
|
precheck(cfg, t);
|
|
4691
|
-
const { matches, source: source2 } = await getLiveMatches(adapterFor(ctx));
|
|
4719
|
+
const { matches, degraded: degraded2, source: source2 } = await getLiveMatches(adapterFor(ctx));
|
|
4692
4720
|
emitShare(
|
|
4693
4721
|
ctx,
|
|
4694
4722
|
{
|
|
@@ -4698,7 +4726,9 @@ async function cmdShare(target, team, opts, ctx) {
|
|
|
4698
4726
|
title: "Live match pulse",
|
|
4699
4727
|
matches,
|
|
4700
4728
|
source: source2,
|
|
4701
|
-
|
|
4729
|
+
degraded: degraded2,
|
|
4730
|
+
// Degraded ⇒ feed down, not "nothing's on" — say so on the public card.
|
|
4731
|
+
emptyNote: degraded2 ? "Live scores unavailable right now \u2014 couldn't reach the data provider." : "No matches in play right now.",
|
|
4702
4732
|
installLine: "npx @claudinho/cli live",
|
|
4703
4733
|
tz: cfg.tz,
|
|
4704
4734
|
locale: cfg.lang
|
|
@@ -4713,15 +4743,15 @@ async function cmdShare(target, team, opts, ctx) {
|
|
|
4713
4743
|
if (target === "table") {
|
|
4714
4744
|
precheck(cfg, t);
|
|
4715
4745
|
const group = team?.toUpperCase();
|
|
4716
|
-
const { tables, degraded, source: source2 } = await getStandings(adapterFor(ctx), group);
|
|
4746
|
+
const { tables, degraded: degraded2, source: source2 } = await getStandings(adapterFor(ctx), group);
|
|
4717
4747
|
emitShareTable(
|
|
4718
4748
|
ctx,
|
|
4719
4749
|
{
|
|
4720
4750
|
group,
|
|
4721
4751
|
tables,
|
|
4722
4752
|
// Degraded ⇒ a static roster, served by no live provider: no attribution.
|
|
4723
|
-
source:
|
|
4724
|
-
degraded,
|
|
4753
|
+
source: degraded2 ? void 0 : source2,
|
|
4754
|
+
degraded: degraded2,
|
|
4725
4755
|
installLine: group ? `npx @claudinho/cli table ${group}` : "npx @claudinho/cli table",
|
|
4726
4756
|
emptyNote: group ? `No group ${group}.` : "No standings available.",
|
|
4727
4757
|
options: baseOptions
|
|
@@ -4760,7 +4790,7 @@ async function cmdShare(target, team, opts, ctx) {
|
|
|
4760
4790
|
}
|
|
4761
4791
|
if (target && target !== "today" && !isValidDate(target)) {
|
|
4762
4792
|
precheck(cfg, t);
|
|
4763
|
-
const { match, source: source2 } = await getMatchById(adapterFor(ctx), target);
|
|
4793
|
+
const { match, degraded: degraded2, source: source2 } = await getMatchById(adapterFor(ctx), target);
|
|
4764
4794
|
const matches = match ? [match] : [];
|
|
4765
4795
|
const signals2 = await reliableShareSignals(ctx, matches);
|
|
4766
4796
|
emitShare(
|
|
@@ -4773,6 +4803,7 @@ async function cmdShare(target, team, opts, ctx) {
|
|
|
4773
4803
|
matches,
|
|
4774
4804
|
marketSignals: signals2,
|
|
4775
4805
|
source: source2,
|
|
4806
|
+
degraded: degraded2,
|
|
4776
4807
|
emptyNote: `No match found with id ${target}.`,
|
|
4777
4808
|
installLine: `npx @claudinho/cli match ${target}`,
|
|
4778
4809
|
tz: cfg.tz,
|
|
@@ -4787,7 +4818,7 @@ async function cmdShare(target, team, opts, ctx) {
|
|
|
4787
4818
|
const explicitDate = target && target !== "today" ? target : void 0;
|
|
4788
4819
|
precheck(cfg, t, explicitDate);
|
|
4789
4820
|
const date = explicitDate ?? localDate((/* @__PURE__ */ new Date()).toISOString(), cfg.tz);
|
|
4790
|
-
const { matches: all, source } = await getMatchesForDate(adapterFor(ctx), date);
|
|
4821
|
+
const { matches: all, degraded, source } = await getMatchesForDate(adapterFor(ctx), date);
|
|
4791
4822
|
const todays = fixturesByDate(date, all, cfg.tz);
|
|
4792
4823
|
const signals = await reliableShareSignals(ctx, todays);
|
|
4793
4824
|
const human = formatDate(`${date}T12:00:00.000Z`, { tz: cfg.tz, locale: cfg.lang });
|
|
@@ -4802,6 +4833,7 @@ async function cmdShare(target, team, opts, ctx) {
|
|
|
4802
4833
|
matches: todays,
|
|
4803
4834
|
marketSignals: signals,
|
|
4804
4835
|
source,
|
|
4836
|
+
degraded,
|
|
4805
4837
|
emptyNote: `No matches scheduled for ${human}.`,
|
|
4806
4838
|
installLine: "npx @claudinho/cli today",
|
|
4807
4839
|
tz: cfg.tz,
|
|
@@ -4882,7 +4914,7 @@ function handlePipeError(stream) {
|
|
|
4882
4914
|
}
|
|
4883
4915
|
handlePipeError(process.stdout);
|
|
4884
4916
|
handlePipeError(process.stderr);
|
|
4885
|
-
var VERSION = "0.5.
|
|
4917
|
+
var VERSION = "0.5.2";
|
|
4886
4918
|
var DISCLAIMER = "Claudinho is an independent fan project. Not affiliated with or endorsed by FIFA or Anthropic.";
|
|
4887
4919
|
function ctxFrom(cmd) {
|
|
4888
4920
|
const root = cmd.parent ?? cmd;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@claudinho/cli",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.2",
|
|
4
4
|
"description": "Live scores, fixtures, group tables, and read-only prediction-market signals for the 2026 men's football tournament — in your terminal and Claude Code statusline. No API keys. Not affiliated with FIFA or Anthropic.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"tsup": "^8.0.0",
|
|
57
57
|
"typescript": "^5.7.0",
|
|
58
58
|
"vitest": "^4.1.0",
|
|
59
|
-
"@claudinho/core": "0.5.
|
|
59
|
+
"@claudinho/core": "0.5.2"
|
|
60
60
|
},
|
|
61
61
|
"scripts": {
|
|
62
62
|
"build": "tsup",
|