@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.
Files changed (2) hide show
  1. package/dist/index.js +45 -13
  2. 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 === "LIVE" || m.status === "HT");
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
- return { matches: await adapter.fetchLive(), degraded: false, source: adapter.name };
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
- live = await liveAdapter().fetchLive();
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 (matches.length === 0) {
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
- emptyNote: "No matches in play right now.",
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: degraded ? void 0 : source2,
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.0";
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.0",
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.0"
59
+ "@claudinho/core": "0.5.2"
60
60
  },
61
61
  "scripts": {
62
62
  "build": "tsup",