@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.
- package/README.md +2 -1
- package/dist/index.js +123 -7
- 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
|
|
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
|
|
5600
|
-
if (!
|
|
5601
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
64
|
+
"@claudinho/core": "0.8.18"
|
|
65
65
|
},
|
|
66
66
|
"scripts": {
|
|
67
67
|
"build": "tsup",
|