@claudinho/mcp 0.8.2 → 0.8.4

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 +15 -12
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -454,6 +454,7 @@ function formatKickoff(iso, opts = {}) {
454
454
  const locale = safeLocale(opts.locale);
455
455
  return new Intl.DateTimeFormat(locale, {
456
456
  weekday: "short",
457
+ ...opts.date ? { month: "short", day: "numeric" } : {},
457
458
  hour: "2-digit",
458
459
  minute: "2-digit",
459
460
  hour12: false,
@@ -3035,18 +3036,17 @@ function teamFromMatch(match, code) {
3035
3036
  function matchKey(stage, index) {
3036
3037
  return `${stage}:${index}`;
3037
3038
  }
3038
- function isGroupComplete(group, tables, standingsDegraded) {
3039
- if (standingsDegraded) return false;
3040
- const table = tables.find((t2) => t2.group === group);
3041
- if (!table?.rows.length || table.rows.length !== 4) return false;
3042
- return table.rows.every((r) => r.played >= 3);
3043
- }
3044
3039
  function teamFromStandings(group, position, tables) {
3045
3040
  const table = tables.find((t2) => t2.group === group);
3046
3041
  if (!table) return void 0;
3047
3042
  const row = table.rows[position - 1];
3048
3043
  return row?.team;
3049
3044
  }
3045
+ function hasGroupStarted(group, tables) {
3046
+ const table = tables.find((t2) => t2.group === group);
3047
+ if (!table?.rows.length) return false;
3048
+ return table.rows.some((r) => r.played > 0);
3049
+ }
3050
3050
  function resolveWinner(match) {
3051
3051
  if (!isFinished(match.status)) return void 0;
3052
3052
  if (match.winnerCode) {
@@ -3093,7 +3093,7 @@ function resolveSlot(ref, ctx) {
3093
3093
  case "seed":
3094
3094
  return tbd(ref.label);
3095
3095
  case "group": {
3096
- if (isGroupComplete(ref.group, ctx.tables, ctx.standingsDegraded)) {
3096
+ if (!ctx.standingsDegraded && hasGroupStarted(ref.group, ctx.tables)) {
3097
3097
  const team = teamFromStandings(ref.group, ref.position, ctx.tables);
3098
3098
  if (team) return participant(team, "projected");
3099
3099
  }
@@ -4405,6 +4405,9 @@ function statusTail2(m) {
4405
4405
  if (isLive(m.status)) return " LIVE";
4406
4406
  return "";
4407
4407
  }
4408
+ function formatBracketKickoff(iso, opts) {
4409
+ return formatKickoff(iso, { tz: opts.tz, locale: opts.locale, date: true });
4410
+ }
4408
4411
  function formatBracketMatchLine(mv, opts = {}) {
4409
4412
  const flags = opts.flags !== false;
4410
4413
  const home = formatParticipant(mv.home, "home", flags, opts.locale);
@@ -4413,7 +4416,7 @@ function formatBracketMatchLine(mv, opts = {}) {
4413
4416
  if (isFinished(m.status) || isLive(m.status)) {
4414
4417
  return ` ${home} ${scoreline(m)} ${away}${statusTail2(m)}`;
4415
4418
  }
4416
- const kickoff = mv.kickoff ? formatKickoff(mv.kickoff, { tz: opts.tz, locale: opts.locale }) : "";
4419
+ const kickoff = mv.kickoff ? formatBracketKickoff(mv.kickoff, opts) : "";
4417
4420
  return ` ${home} vs ${away}${kickoff ? ` \xB7 ${kickoff}` : ""}`;
4418
4421
  }
4419
4422
  function formatBracketList(view, opts = {}) {
@@ -4481,7 +4484,7 @@ function formatBracketCompactLine(mv, opts = {}) {
4481
4484
  const away = formatParticipant(mv.away, "away", flags, opts.locale);
4482
4485
  const m = mv.match;
4483
4486
  const mid2 = isFinished(m.status) || isLive(m.status) ? scoreline(m) : "vs";
4484
- const tail = m.status === "SCHEDULED" && mv.kickoff ? ` \xB7 ${formatKickoff(mv.kickoff, { tz: opts.tz, locale: opts.locale })}` : statusTail2(m);
4487
+ const tail = m.status === "SCHEDULED" && mv.kickoff ? ` \xB7 ${formatBracketKickoff(mv.kickoff, opts)}` : statusTail2(m);
4485
4488
  return `${stageLabelI18n(opts.locale, mv.stage)} \xB7 ${home} ${mid2} ${away}${tail}`;
4486
4489
  }
4487
4490
 
@@ -4730,7 +4733,7 @@ async function toolGetBracket(args) {
4730
4733
  resolveAdapter(args),
4731
4734
  filter ? { stage: filter, lang: args.lang } : { lang: args.lang }
4732
4735
  );
4733
- let text = formatBracketList(view, { footer: false, locale: args.lang });
4736
+ let text = formatBracketList(view, { footer: false, locale: args.lang, tz: args.tz });
4734
4737
  if (degraded) {
4735
4738
  text += `
4736
4739
 
@@ -5028,7 +5031,7 @@ async function toolGetShareSnippet(args) {
5028
5031
 
5029
5032
  // src/server.ts
5030
5033
  var SERVER_NAME = "claudinho";
5031
- var SERVER_VERSION = "0.8.2";
5034
+ var SERVER_VERSION = "0.8.4";
5032
5035
  var VOICE = asFlavorLevel(process.env.CLAUDINHO_FLAVOR) === "off" ? "" : `
5033
5036
  Voice: when relaying scores, narrate with lively, regionally-appropriate football-commentary energy in the user's language. Each match line may end with a short exclamation ("\u2014 \xA1GOOOOL!") \u2014 use it as a tone cue. Keep every fact exact; never invent details and never impersonate or name a real commentator.`;
5034
5037
  var INSTRUCTIONS = `Claudinho serves live scores, fixtures, and group standings for the 2026 men's football tournament.
@@ -5109,7 +5112,7 @@ function buildServer() {
5109
5112
  "get_bracket",
5110
5113
  {
5111
5114
  title: "Knockout bracket",
5112
- description: "Knockout bracket from the Round of 32 through the final, with live scores overlaid. Group slots project only when a group is fully played; winner slots need a confirmed FT result. Pass an optional stage (R32, R16, QF, SF, 3P, F) to filter one round. Falls back to structure-only when live data is unavailable.",
5115
+ description: "Knockout bracket from the Round of 32 through the final, with live scores overlaid. Group slots project from live standings once a group has started; winner slots need a confirmed FT result. Pass an optional stage (R32, R16, QF, SF, 3P, F) to filter one round. Falls back to structure-only when live data is unavailable.",
5113
5116
  inputSchema: {
5114
5117
  stage: z.enum(["R32", "R16", "QF", "SF", "3P", "F"]).optional().describe("Knockout round to show (omit for the full bracket)"),
5115
5118
  ...commonArgs
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@claudinho/mcp",
3
- "version": "0.8.2",
3
+ "version": "0.8.4",
4
4
  "mcpName": "io.github.arturogarrido/claudinho",
5
5
  "description": "MCP server for the 2026 men's football tournament — live scores, fixtures, standings, read-only prediction-market signals, and paste-ready match cards. Works with Claude Code, Cursor, Codex, Windsurf, Zed. Not affiliated with FIFA or Anthropic.",
6
6
  "type": "module",
@@ -57,7 +57,7 @@
57
57
  "tsup": "^8.0.0",
58
58
  "typescript": "^5.7.0",
59
59
  "vitest": "^4.1.9",
60
- "@claudinho/core": "0.8.2"
60
+ "@claudinho/core": "0.8.4"
61
61
  },
62
62
  "scripts": {
63
63
  "build": "tsup",