@claudinho/cli 0.8.17 → 0.8.18

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 (3) hide show
  1. package/README.md +2 -1
  2. package/dist/index.js +123 -7
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -35,10 +35,11 @@ All 104 fixtures ship bundled, so the schedule works offline; only live scores h
35
35
  ```bash
36
36
  claudinho today [date] # a day's fixtures in your timezone (default: today), live scores inline
37
37
  claudinho live # matches in play right now
38
- claudinho next [TEAM] # a team's next fixture + countdown (default: $CLAUDINHO_TEAM)
38
+ claudinho next [TEAM] # a team's next fixture + countdown — TEAM is a name OR code (Mexico | MEX | "DR Congo"); default $CLAUDINHO_TEAM
39
39
  claudinho table [GROUP] # live cumulative group standings (default: all groups)
40
40
  claudinho bracket [STAGE] # knockout bracket (R32, R16, QF, SF, 3P, F); --tree for ASCII tree
41
41
  claudinho match <id> # a single match's detail
42
+ claudinho team <query> # resolve a name/code to its FIFA code, flag, and group (e.g. team "DR Congo")
42
43
  claudinho markets [target] # prediction-market signals: today | <date> | <id> | next <TEAM>
43
44
  # (next prefers the team's IN-PLAY match while one is live)
44
45
  claudinho share [target] # copy-pasteable snippet: today | live | <date> | <id> | next <TEAM> | table <GROUP> | bracket [STAGE]
package/dist/index.js CHANGED
@@ -2808,6 +2808,60 @@ function groups(fixtures = SCHEDULE) {
2808
2808
  for (const m of fixtures) if (m.group) set.add(m.group);
2809
2809
  return [...set].sort();
2810
2810
  }
2811
+ function norm2(s) {
2812
+ return s.toLowerCase().normalize("NFD").replace(/[̀-ͯ]/g, "").replace(/[^a-z]/g, "");
2813
+ }
2814
+ function allTeams(fixtures = allFixtures()) {
2815
+ const seen = /* @__PURE__ */ new Map();
2816
+ for (const m of fixtures) {
2817
+ if (m.stage !== "GROUP") continue;
2818
+ for (const t2 of [m.home, m.away]) {
2819
+ if (!/^[A-Z]{3}$/.test(t2.code) || t2.flag === "\u{1F3F3}\uFE0F") continue;
2820
+ if (!seen.has(t2.code)) seen.set(t2.code, { ...t2, group: m.group ?? void 0 });
2821
+ }
2822
+ }
2823
+ return [...seen.values()].sort((a, b) => a.name.localeCompare(b.name));
2824
+ }
2825
+ var TEAM_ALIASES = {
2826
+ turkey: "TUR",
2827
+ holland: "NED",
2828
+ korea: "KOR",
2829
+ skorea: "KOR",
2830
+ korearepublic: "KOR",
2831
+ republicofkorea: "KOR",
2832
+ czechrepublic: "CZE",
2833
+ congo: "COD",
2834
+ drcongo: "COD",
2835
+ drc: "COD",
2836
+ democraticrepublicofcongo: "COD",
2837
+ democraticrepublicofthecongo: "COD",
2838
+ cotedivoire: "CIV",
2839
+ caboverde: "CPV",
2840
+ bosnia: "BIH",
2841
+ bosniaandherzegovina: "BIH",
2842
+ us: "USA",
2843
+ america: "USA",
2844
+ unitedstatesofamerica: "USA"
2845
+ };
2846
+ function lookupTeam(query, fixtures = allFixtures()) {
2847
+ const roster = allTeams(fixtures);
2848
+ const q = norm2(query);
2849
+ if (!q) return { query, team: null, matches: [] };
2850
+ const byCode = roster.find((t2) => norm2(t2.code) === q);
2851
+ if (byCode) return { query, team: byCode, matches: [byCode] };
2852
+ const byName = roster.find((t2) => norm2(t2.name) === q);
2853
+ if (byName) return { query, team: byName, matches: [byName] };
2854
+ const aliasCode = TEAM_ALIASES[q];
2855
+ if (aliasCode) {
2856
+ const t2 = roster.find((r) => r.code === aliasCode);
2857
+ if (t2) return { query, team: t2, matches: [t2] };
2858
+ }
2859
+ if (q.length < 3) return { query, team: null, matches: [] };
2860
+ const prefix = roster.filter((t2) => norm2(t2.name).startsWith(q));
2861
+ const substr = roster.filter((t2) => norm2(t2.name).includes(q) && !prefix.includes(t2));
2862
+ const matches = [...prefix, ...substr];
2863
+ return { query, team: matches.length === 1 ? matches[0] : null, matches };
2864
+ }
2811
2865
  function blankRow(team) {
2812
2866
  return {
2813
2867
  team,
@@ -4690,6 +4744,10 @@ var EN2 = {
4690
4744
  "next.none": "No upcoming fixture found for {team}.",
4691
4745
  "next.label": "Next up for {team}",
4692
4746
  "next.in": "in {countdown}",
4747
+ "team.group": "Group {group}",
4748
+ "team.ambiguous": '"{query}" is ambiguous. Did you mean:',
4749
+ "team.none": 'No team found for "{query}". Try a nation name or 3-letter code (e.g. Mexico, MEX).',
4750
+ "team.usage": "Usage: claudinho team <name or code> (e.g. claudinho team Mexico)",
4693
4751
  "table.title": "Group {group}",
4694
4752
  "table.none": "No group found for {group}.",
4695
4753
  "table.degraded": "Live standings unavailable \u2014 showing the group roster.",
@@ -4724,6 +4782,10 @@ var ES2 = {
4724
4782
  "next.none": "No se encontr\xF3 pr\xF3ximo partido para {team}.",
4725
4783
  "next.label": "Pr\xF3ximo partido de {team}",
4726
4784
  "next.in": "en {countdown}",
4785
+ "team.group": "Grupo {group}",
4786
+ "team.ambiguous": '"{query}" es ambiguo. \xBFQuisiste decir:',
4787
+ "team.none": 'No se encontr\xF3 ning\xFAn equipo para "{query}". Prueba un nombre de pa\xEDs o un c\xF3digo de 3 letras (p. ej. Mexico, MEX).',
4788
+ "team.usage": "Uso: claudinho team <nombre o c\xF3digo> (p. ej. claudinho team Mexico)",
4727
4789
  "table.title": "Grupo {group}",
4728
4790
  "table.none": "No se encontr\xF3 el grupo {group}.",
4729
4791
  "table.degraded": "Tabla en vivo no disponible \u2014 mostrando la lista del grupo.",
@@ -4758,6 +4820,10 @@ var PT2 = {
4758
4820
  "next.none": "Nenhum pr\xF3ximo jogo encontrado para {team}.",
4759
4821
  "next.label": "Pr\xF3ximo jogo de {team}",
4760
4822
  "next.in": "em {countdown}",
4823
+ "team.group": "Grupo {group}",
4824
+ "team.ambiguous": '"{query}" \xE9 amb\xEDguo. Voc\xEA quis dizer:',
4825
+ "team.none": 'Nenhuma sele\xE7\xE3o encontrada para "{query}". Tente um nome de pa\xEDs ou um c\xF3digo de 3 letras (ex. Mexico, MEX).',
4826
+ "team.usage": "Uso: claudinho team <nome ou c\xF3digo> (ex. claudinho team Mexico)",
4761
4827
  "table.title": "Grupo {group}",
4762
4828
  "table.none": "Grupo {group} n\xE3o encontrado.",
4763
4829
  "table.degraded": "Classifica\xE7\xE3o ao vivo indispon\xEDvel \u2014 mostrando os times do grupo.",
@@ -4792,6 +4858,10 @@ var FR2 = {
4792
4858
  "next.none": "Aucun prochain match trouv\xE9 pour {team}.",
4793
4859
  "next.label": "Prochain match de {team}",
4794
4860
  "next.in": "dans {countdown}",
4861
+ "team.group": "Groupe {group}",
4862
+ "team.ambiguous": '"{query}" est ambigu. Vouliez-vous dire :',
4863
+ "team.none": 'Aucune \xE9quipe trouv\xE9e pour "{query}". Essayez un nom de pays ou un code \xE0 3 lettres (p. ex. Mexico, MEX).',
4864
+ "team.usage": "Usage : claudinho team <nom ou code> (p. ex. claudinho team Mexico)",
4795
4865
  "table.title": "Groupe {group}",
4796
4866
  "table.none": "Groupe {group} introuvable.",
4797
4867
  "table.degraded": "Classement en direct indisponible \u2014 affichage de la composition du groupe.",
@@ -5596,9 +5666,17 @@ function precheck(cfg, t2, date) {
5596
5666
  }
5597
5667
  }
5598
5668
  function resolveTeamArg(team, usage) {
5599
- const code = team ?? process.env.CLAUDINHO_TEAM;
5600
- if (!code) throw new InputError(usage);
5601
- return code.toUpperCase();
5669
+ const raw = team ?? process.env.CLAUDINHO_TEAM;
5670
+ if (!raw) throw new InputError(usage);
5671
+ const { team: hit, matches } = lookupTeam(raw);
5672
+ if (hit) return hit.code;
5673
+ if (matches.length > 1) {
5674
+ throw new InputError(
5675
+ `"${raw}" is ambiguous \u2014 did you mean ${matches.map((m) => `${m.name} (${m.code})`).join(", ")}? Use the 3-letter code.`
5676
+ );
5677
+ }
5678
+ if (/^[A-Za-z]{3}$/.test(raw)) return raw.toUpperCase();
5679
+ throw new InputError(`No team found for "${raw}". Use a nation name or 3-letter code (e.g. Mexico, MEX).`);
5602
5680
  }
5603
5681
  async function cmdToday(date, ctx) {
5604
5682
  const { cfg, t: t2 } = ctx;
@@ -5704,6 +5782,37 @@ async function cmdNext(team, ctx) {
5704
5782
  out(disclaimer(t2, c));
5705
5783
  maybeStarNudge(ctx);
5706
5784
  }
5785
+ function cmdTeam(query, ctx) {
5786
+ const { cfg, t: t2 } = ctx;
5787
+ precheck(cfg, t2);
5788
+ const q = (query ?? "").trim();
5789
+ const { team, matches } = lookupTeam(q);
5790
+ if (cfg.json) {
5791
+ emitJson({ query: q, team: team ?? null, matches, count: matches.length });
5792
+ return;
5793
+ }
5794
+ const c = painterFor(cfg);
5795
+ const flags = flagsEnabled();
5796
+ const label = (tm) => {
5797
+ const flag = flags ? `${tm.flag} ` : "";
5798
+ const grp = tm.group ? ` \xB7 ${t2("team.group", { group: tm.group })}` : "";
5799
+ return ` ${flag}${c.bold(tm.name)} ${c.dim(tm.code + grp)}`;
5800
+ };
5801
+ out();
5802
+ if (!q) {
5803
+ out(" " + c.dim(t2("team.usage")));
5804
+ } else if (team) {
5805
+ out(label(team));
5806
+ } else if (matches.length > 0) {
5807
+ out(" " + c.dim(t2("team.ambiguous", { query: q })));
5808
+ for (const m of matches) out(label(m));
5809
+ } else {
5810
+ out(" " + c.dim(t2("team.none", { query: q })));
5811
+ }
5812
+ out();
5813
+ out(disclaimer(t2, c));
5814
+ maybeStarNudge(ctx);
5815
+ }
5707
5816
  async function cmdTable(group, ctx) {
5708
5817
  const { cfg, t: t2 } = ctx;
5709
5818
  precheck(cfg, t2);
@@ -6456,7 +6565,7 @@ function handlePipeError(stream) {
6456
6565
  }
6457
6566
  handlePipeError(process.stdout);
6458
6567
  handlePipeError(process.stderr);
6459
- var VERSION = "0.8.17";
6568
+ var VERSION = "0.8.18";
6460
6569
  var DISCLAIMER = "Claudinho is an independent fan project. Not affiliated with or endorsed by FIFA or Anthropic.";
6461
6570
  function ctxFrom(cmd) {
6462
6571
  let root = cmd;
@@ -6490,13 +6599,20 @@ program.command("live").description("show matches in play right now").action(asy
6490
6599
  fail(e);
6491
6600
  }
6492
6601
  });
6493
- program.command("next").description("show a team's next fixture").argument("[team]", "team code, e.g. MEX (default: $CLAUDINHO_TEAM)").action(async (team, _opts, cmd) => {
6602
+ program.command("next").description("show a team's next fixture").argument("[team]", "team name or code, e.g. Mexico or MEX (default: $CLAUDINHO_TEAM)").action(async (team, _opts, cmd) => {
6494
6603
  try {
6495
6604
  await cmdNext(team, ctxFrom(cmd));
6496
6605
  } catch (e) {
6497
6606
  fail(e);
6498
6607
  }
6499
6608
  });
6609
+ program.command("team").description("resolve a nation name or code to its FIFA code, flag, and group").argument("<query>", 'team name or 3-letter code, e.g. Mexico, MEX, "DR Congo"').action((query, _opts, cmd) => {
6610
+ try {
6611
+ cmdTeam(query, ctxFrom(cmd));
6612
+ } catch (e) {
6613
+ fail(e);
6614
+ }
6615
+ });
6500
6616
  program.command("table").description("show group standings (default: all groups)").argument("[group]", "group letter A-L").action(async (group, _opts, cmd) => {
6501
6617
  try {
6502
6618
  await cmdTable(group, ctxFrom(cmd));
@@ -6518,7 +6634,7 @@ program.command("match").description("show a single match by id").argument("<id>
6518
6634
  fail(e);
6519
6635
  }
6520
6636
  });
6521
- program.command("markets").description("show prediction-market signals (read-only, informational only)").argument("[target]", 'date (YYYY-MM-DD), match id, "today", or "next"').argument("[team]", 'team code when target is "next" (default: $CLAUDINHO_TEAM)').action(async (target, team, _opts, cmd) => {
6637
+ program.command("markets").description("show prediction-market signals (read-only, informational only)").argument("[target]", 'date (YYYY-MM-DD), match id, "today", or "next"').argument("[team]", 'team name or code when target is "next", e.g. Mexico or MEX (default: $CLAUDINHO_TEAM)').action(async (target, team, _opts, cmd) => {
6522
6638
  try {
6523
6639
  await cmdMarkets(target, team, ctxFrom(cmd));
6524
6640
  } catch (e) {
@@ -6527,7 +6643,7 @@ program.command("markets").description("show prediction-market signals (read-onl
6527
6643
  });
6528
6644
  program.command("share").description("print a shareable, copy-pasteable match snippet (#VibingLaVidaLoca)").argument("[target]", '"today" (default), "live", a date, a match id, "next", "table", or "bracket"').argument(
6529
6645
  "[team]",
6530
- 'team code for "next" (default: $CLAUDINHO_TEAM), group letter for "table", or stage for "bracket"'
6646
+ 'team name or code for "next" (default: $CLAUDINHO_TEAM), group letter for "table", or stage for "bracket"'
6531
6647
  ).option("--style <style>", "snippet style: social (default) or compact").option("--copy", "also copy the snippet to the clipboard (best-effort)").option("--no-hashtag", "omit the #VibingLaVidaLoca tag").option("--no-install-line", "omit the install/run cue").action(async (target, team, opts, cmd) => {
6532
6648
  try {
6533
6649
  await cmdShare(target, team, opts, ctxFrom(cmd));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@claudinho/cli",
3
- "version": "0.8.17",
3
+ "version": "0.8.18",
4
4
  "description": "Live scores, fixtures, group tables, and read-only prediction-market signals for the 2026 men's football tournament — in your terminal, Claude Code, and Cursor CLI statusline. No API keys. Not affiliated with FIFA or Anthropic.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -61,7 +61,7 @@
61
61
  "tsup": "^8.0.0",
62
62
  "typescript": "^5.7.0",
63
63
  "vitest": "^4.1.9",
64
- "@claudinho/core": "0.8.17"
64
+ "@claudinho/core": "0.8.18"
65
65
  },
66
66
  "scripts": {
67
67
  "build": "tsup",