@claudinho/mcp 0.3.0 → 0.4.1
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 +7 -0
- package/dist/index.js +272 -4
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -49,6 +49,7 @@ any other MCP client with no changes.
|
|
|
49
49
|
| `get_standings` | group table(s) — one group `A`–`L`, or all |
|
|
50
50
|
| `get_next_fixture` | a team's next match (3-letter code, e.g. `MEX`) |
|
|
51
51
|
| `get_market_signal` | read-only prediction-market odds for a match, a team's next fixture, or a date — informational only |
|
|
52
|
+
| `get_share_snippet` | a copy-pasteable match-card snippet for a match, a team's next fixture, a date, or live — plain text, ready to paste |
|
|
52
53
|
|
|
53
54
|
All tools are **read-only** (annotated `readOnlyHint`) and accept optional
|
|
54
55
|
`tz` (IANA timezone), `lang` (`en`/`es`/`pt`/`fr`), and `flavor`
|
|
@@ -64,6 +65,12 @@ cleanly to the result. Disable it with `CLAUDINHO_MARKETS=off`; set
|
|
|
64
65
|
`CLAUDINHO_MARKETS_SOURCE=fake` (in the server `env`) for a network-free synthetic
|
|
65
66
|
preview.
|
|
66
67
|
|
|
68
|
+
`get_share_snippet` returns a polished, **copy-pasteable** match card (the same
|
|
69
|
+
artifact as the CLI's `claudinho share`) for a match, a team's next fixture, a
|
|
70
|
+
date, or live matches — plain text, no links, with the non-affiliation disclaimer
|
|
71
|
+
baked in. Hand the returned `snippet` to the user as-is. `style` picks `social`
|
|
72
|
+
(default) or `compact`; market lines (when reliable) stay **informational only**.
|
|
73
|
+
|
|
67
74
|
## Resources & prompts
|
|
68
75
|
|
|
69
76
|
- Resources: `standings://{group}` (e.g. `standings://A`), `fixtures://{date}` (UTC date, e.g. `fixtures://2026-06-11`)
|
package/dist/index.js
CHANGED
|
@@ -315,6 +315,25 @@ function formatKickoff(iso, opts = {}) {
|
|
|
315
315
|
timeZone: tz
|
|
316
316
|
}).format(new Date(iso));
|
|
317
317
|
}
|
|
318
|
+
function formatDate(iso, opts = {}) {
|
|
319
|
+
const tz = resolveTz(opts.tz);
|
|
320
|
+
const locale = safeLocale(opts.locale);
|
|
321
|
+
return new Intl.DateTimeFormat(locale, {
|
|
322
|
+
month: "short",
|
|
323
|
+
day: "numeric",
|
|
324
|
+
timeZone: tz
|
|
325
|
+
}).format(new Date(iso));
|
|
326
|
+
}
|
|
327
|
+
function formatTime(iso, opts = {}) {
|
|
328
|
+
const tz = resolveTz(opts.tz);
|
|
329
|
+
const locale = safeLocale(opts.locale);
|
|
330
|
+
return new Intl.DateTimeFormat(locale, {
|
|
331
|
+
hour: "2-digit",
|
|
332
|
+
minute: "2-digit",
|
|
333
|
+
hour12: false,
|
|
334
|
+
timeZone: tz
|
|
335
|
+
}).format(new Date(iso));
|
|
336
|
+
}
|
|
318
337
|
function countdown(iso, from = /* @__PURE__ */ new Date()) {
|
|
319
338
|
const ms = new Date(iso).getTime() - from.getTime();
|
|
320
339
|
if (ms <= 0) return "now";
|
|
@@ -335,6 +354,9 @@ function localDate(iso, tz) {
|
|
|
335
354
|
timeZone: zone
|
|
336
355
|
}).format(new Date(iso));
|
|
337
356
|
}
|
|
357
|
+
function isLive(status) {
|
|
358
|
+
return status === "LIVE" || status === "HT";
|
|
359
|
+
}
|
|
338
360
|
function isFinished(status) {
|
|
339
361
|
return status === "FT";
|
|
340
362
|
}
|
|
@@ -2989,6 +3011,11 @@ function marketAttributionText(signal) {
|
|
|
2989
3011
|
const src = `Source: ${marketSourceLabel(signal.source)}`;
|
|
2990
3012
|
return time ? `${src} \xB7 updated ${time}` : src;
|
|
2991
3013
|
}
|
|
3014
|
+
function marketLine(signal, match) {
|
|
3015
|
+
return `Market: ${marketProbabilityText(signal, match)} \xB7 ${marketSourceLabel(
|
|
3016
|
+
signal.source
|
|
3017
|
+
)} \xB7 informational only`;
|
|
3018
|
+
}
|
|
2992
3019
|
function marketBlock(signal, match) {
|
|
2993
3020
|
const lines = [];
|
|
2994
3021
|
if (signal.stale) lines.push("Market signal is stale; the reading may be out of date.");
|
|
@@ -3272,6 +3299,87 @@ async function getMarketSignals(provider, matches, options) {
|
|
|
3272
3299
|
return { signals: /* @__PURE__ */ new Map(), checked: /* @__PURE__ */ new Set() };
|
|
3273
3300
|
}
|
|
3274
3301
|
}
|
|
3302
|
+
var SHARE_HASHTAG = "#VibingLaVidaLoca";
|
|
3303
|
+
var SHARE_DISCLAIMER = "Independent fan project \xB7 not affiliated with FIFA or Anthropic.";
|
|
3304
|
+
function mid(m) {
|
|
3305
|
+
return isLive(m.status) || m.status === "FT" ? scoreline(m) : "vs";
|
|
3306
|
+
}
|
|
3307
|
+
function statusTail(m) {
|
|
3308
|
+
switch (m.status) {
|
|
3309
|
+
case "LIVE":
|
|
3310
|
+
return m.minute ? `${m.minute}'` : "LIVE";
|
|
3311
|
+
case "HT":
|
|
3312
|
+
return "HT";
|
|
3313
|
+
case "FT":
|
|
3314
|
+
return "FT";
|
|
3315
|
+
case "POSTPONED":
|
|
3316
|
+
return "postponed";
|
|
3317
|
+
case "CANCELLED":
|
|
3318
|
+
return "cancelled";
|
|
3319
|
+
default:
|
|
3320
|
+
return "";
|
|
3321
|
+
}
|
|
3322
|
+
}
|
|
3323
|
+
function compactLine(m, input, single) {
|
|
3324
|
+
const home = `${m.home.flag} ${m.home.code}`;
|
|
3325
|
+
const away = `${m.away.code} ${m.away.flag}`;
|
|
3326
|
+
const opts = { tz: input.tz, locale: input.locale };
|
|
3327
|
+
let tail;
|
|
3328
|
+
if (m.status === "SCHEDULED") {
|
|
3329
|
+
const time = formatTime(m.kickoff, opts);
|
|
3330
|
+
tail = single ? `${formatDate(m.kickoff, opts)} ${time}` : time;
|
|
3331
|
+
} else {
|
|
3332
|
+
tail = statusTail(m);
|
|
3333
|
+
}
|
|
3334
|
+
return `${home} ${mid(m)} ${away}${tail ? ` \xB7 ${tail}` : ""}`;
|
|
3335
|
+
}
|
|
3336
|
+
function socialCard(m, input) {
|
|
3337
|
+
const lines = [];
|
|
3338
|
+
const head = `${m.home.flag} ${m.home.name} ${mid(m)} ${m.away.name} ${m.away.flag}`;
|
|
3339
|
+
if (m.status === "SCHEDULED") {
|
|
3340
|
+
lines.push(head);
|
|
3341
|
+
const date = formatDate(m.kickoff, { tz: input.tz, locale: input.locale });
|
|
3342
|
+
const time = formatTime(m.kickoff, { tz: input.tz, locale: input.locale });
|
|
3343
|
+
const zone = input.tz ? ` ${input.tz}` : "";
|
|
3344
|
+
lines.push(`${date} \xB7 ${time}${zone}`);
|
|
3345
|
+
} else {
|
|
3346
|
+
const tail = statusTail(m);
|
|
3347
|
+
lines.push(tail ? `${head} \xB7 ${tail}` : head);
|
|
3348
|
+
}
|
|
3349
|
+
const loc = matchLocation(m);
|
|
3350
|
+
if (loc) lines.push(loc);
|
|
3351
|
+
return lines;
|
|
3352
|
+
}
|
|
3353
|
+
function formatShareSnippet(input, options = {}) {
|
|
3354
|
+
const style = options.style ?? "social";
|
|
3355
|
+
const includeMarkets = options.includeMarkets !== false;
|
|
3356
|
+
const includeHashtag = options.includeHashtag !== false;
|
|
3357
|
+
const includeInstall = options.includeInstallLine !== false;
|
|
3358
|
+
const signals = input.marketSignals ?? /* @__PURE__ */ new Map();
|
|
3359
|
+
const single = input.matches.length === 1;
|
|
3360
|
+
const blocks = [input.title];
|
|
3361
|
+
if (input.matches.length === 0) {
|
|
3362
|
+
if (input.emptyNote) blocks.push(input.emptyNote);
|
|
3363
|
+
} else if (style === "compact") {
|
|
3364
|
+
blocks.push(input.matches.map((m) => compactLine(m, input, single)).join("\n"));
|
|
3365
|
+
} else {
|
|
3366
|
+
for (const m of input.matches) {
|
|
3367
|
+
const card = socialCard(m, input);
|
|
3368
|
+
const sig = includeMarkets ? signals.get(m.id) : void 0;
|
|
3369
|
+
if (sig) {
|
|
3370
|
+
if (single) card.push("", ...marketBlock(sig, m));
|
|
3371
|
+
else card.push(marketLine(sig, m));
|
|
3372
|
+
}
|
|
3373
|
+
blocks.push(card.join("\n"));
|
|
3374
|
+
}
|
|
3375
|
+
}
|
|
3376
|
+
const footer = [];
|
|
3377
|
+
if (input.source) footer.push(`Live data: ${liveSourceLabel(input.source)}`);
|
|
3378
|
+
footer.push([includeHashtag ? SHARE_HASHTAG : "", SHARE_DISCLAIMER].filter(Boolean).join(" \xB7 "));
|
|
3379
|
+
if (includeInstall && input.installLine) footer.push(`Try it: ${input.installLine}`);
|
|
3380
|
+
blocks.push(footer.join("\n"));
|
|
3381
|
+
return blocks.join("\n\n");
|
|
3382
|
+
}
|
|
3275
3383
|
|
|
3276
3384
|
// src/format.ts
|
|
3277
3385
|
var STATUS_LABEL = {
|
|
@@ -3596,15 +3704,154 @@ ${shown.map(({ match, signal }) => marketText(match, signal)).join("\n\n")}` : `
|
|
|
3596
3704
|
}
|
|
3597
3705
|
};
|
|
3598
3706
|
}
|
|
3707
|
+
async function reliableSignalMap(args, matches) {
|
|
3708
|
+
if (!marketsEnabled()) return /* @__PURE__ */ new Map();
|
|
3709
|
+
const signals = await cachedMarketSignals(args, matches);
|
|
3710
|
+
const now = /* @__PURE__ */ new Date();
|
|
3711
|
+
const out = /* @__PURE__ */ new Map();
|
|
3712
|
+
for (const m of matches) {
|
|
3713
|
+
const s = signals.get(m.id);
|
|
3714
|
+
if (s && isReliableMarketSignal(s, { now }) && marketDisplayable(s)) out.set(m.id, s);
|
|
3715
|
+
}
|
|
3716
|
+
return out;
|
|
3717
|
+
}
|
|
3718
|
+
function shareOptions(args) {
|
|
3719
|
+
return {
|
|
3720
|
+
style: args.style === "compact" ? "compact" : "social",
|
|
3721
|
+
includeMarkets: marketsEnabled() && args.includeMarkets !== false,
|
|
3722
|
+
includeHashtag: args.includeHashtag !== false,
|
|
3723
|
+
includeInstallLine: args.includeInstallLine !== false
|
|
3724
|
+
};
|
|
3725
|
+
}
|
|
3726
|
+
function shareResult(kind, target, team, input, options) {
|
|
3727
|
+
const snippet = formatShareSnippet(input, options);
|
|
3728
|
+
return {
|
|
3729
|
+
// The snippet is self-contained: it carries its own non-affiliation
|
|
3730
|
+
// disclaimer (and, for any market line, the "informational only" caveat +
|
|
3731
|
+
// attribution), so it is deliberately NOT wrapped with withDisclaimer —
|
|
3732
|
+
// that would duplicate the disclaimer inside a paste-ready artifact.
|
|
3733
|
+
text: snippet,
|
|
3734
|
+
data: {
|
|
3735
|
+
kind,
|
|
3736
|
+
target,
|
|
3737
|
+
...team ? { team } : {},
|
|
3738
|
+
source: input.source ?? null,
|
|
3739
|
+
informationalOnly: true,
|
|
3740
|
+
style: options.style ?? "social",
|
|
3741
|
+
snippet,
|
|
3742
|
+
matches: input.matches,
|
|
3743
|
+
marketSignals: Object.fromEntries(
|
|
3744
|
+
[...input.marketSignals ?? /* @__PURE__ */ new Map()].map(([id, s]) => [
|
|
3745
|
+
id,
|
|
3746
|
+
marketData(s)
|
|
3747
|
+
])
|
|
3748
|
+
)
|
|
3749
|
+
}
|
|
3750
|
+
};
|
|
3751
|
+
}
|
|
3752
|
+
async function toolGetShareSnippet(args) {
|
|
3753
|
+
const options = shareOptions(args);
|
|
3754
|
+
const signalsFor = (ms) => args.includeMarkets === false ? Promise.resolve(/* @__PURE__ */ new Map()) : reliableSignalMap(args, ms);
|
|
3755
|
+
if (args.live) {
|
|
3756
|
+
const { matches, source: source2 } = await getLiveMatches(resolveAdapter(args));
|
|
3757
|
+
return shareResult(
|
|
3758
|
+
"live",
|
|
3759
|
+
"live",
|
|
3760
|
+
void 0,
|
|
3761
|
+
{
|
|
3762
|
+
title: "Live match pulse",
|
|
3763
|
+
matches,
|
|
3764
|
+
source: source2,
|
|
3765
|
+
emptyNote: "No matches in play right now.",
|
|
3766
|
+
installLine: "npx @claudinho/cli live",
|
|
3767
|
+
tz: args.tz,
|
|
3768
|
+
locale: args.lang
|
|
3769
|
+
},
|
|
3770
|
+
{ ...options, includeMarkets: false }
|
|
3771
|
+
);
|
|
3772
|
+
}
|
|
3773
|
+
if (args.matchId) {
|
|
3774
|
+
let match = allFixtures().find((m) => m.id === args.matchId);
|
|
3775
|
+
let source2;
|
|
3776
|
+
if (match) {
|
|
3777
|
+
try {
|
|
3778
|
+
const adapter = resolveAdapter(args);
|
|
3779
|
+
const live = await adapter.fetchByDate(match.kickoff.slice(0, 10));
|
|
3780
|
+
match = live.find((m) => m.id === args.matchId) ?? match;
|
|
3781
|
+
source2 = adapter.name;
|
|
3782
|
+
} catch {
|
|
3783
|
+
}
|
|
3784
|
+
}
|
|
3785
|
+
const matches = match ? [match] : [];
|
|
3786
|
+
return shareResult(
|
|
3787
|
+
"match",
|
|
3788
|
+
args.matchId,
|
|
3789
|
+
void 0,
|
|
3790
|
+
{
|
|
3791
|
+
title: "Match pulse",
|
|
3792
|
+
matches,
|
|
3793
|
+
marketSignals: await signalsFor(matches),
|
|
3794
|
+
source: source2,
|
|
3795
|
+
emptyNote: `No match found with id ${args.matchId}.`,
|
|
3796
|
+
installLine: `npx @claudinho/cli match ${args.matchId}`,
|
|
3797
|
+
tz: args.tz,
|
|
3798
|
+
locale: args.lang
|
|
3799
|
+
},
|
|
3800
|
+
options
|
|
3801
|
+
);
|
|
3802
|
+
}
|
|
3803
|
+
if (args.team) {
|
|
3804
|
+
const code = args.team.toUpperCase();
|
|
3805
|
+
const fixture = nextFixtureForTeam(code);
|
|
3806
|
+
const matches = fixture ? [fixture] : [];
|
|
3807
|
+
const teamName = fixture ? fixture.home.code === code ? fixture.home.name : fixture.away.name : code;
|
|
3808
|
+
return shareResult(
|
|
3809
|
+
"next",
|
|
3810
|
+
"next",
|
|
3811
|
+
code,
|
|
3812
|
+
{
|
|
3813
|
+
title: `Next up for ${teamName}`,
|
|
3814
|
+
matches,
|
|
3815
|
+
marketSignals: await signalsFor(matches),
|
|
3816
|
+
emptyNote: `No upcoming fixture found for ${code}.`,
|
|
3817
|
+
installLine: `npx @claudinho/cli next ${code}`,
|
|
3818
|
+
tz: args.tz,
|
|
3819
|
+
locale: args.lang
|
|
3820
|
+
},
|
|
3821
|
+
options
|
|
3822
|
+
);
|
|
3823
|
+
}
|
|
3824
|
+
const date = args.date ?? localDate((/* @__PURE__ */ new Date()).toISOString(), args.tz);
|
|
3825
|
+
const { matches: all, source } = await getMatchesForDate(resolveAdapter(args), date);
|
|
3826
|
+
const todays = fixturesByDate(date, all, args.tz);
|
|
3827
|
+
const human = formatDate(`${date}T12:00:00.000Z`, { tz: args.tz, locale: args.lang });
|
|
3828
|
+
return shareResult(
|
|
3829
|
+
"today",
|
|
3830
|
+
date,
|
|
3831
|
+
void 0,
|
|
3832
|
+
{
|
|
3833
|
+
title: args.date ? `Matches \xB7 ${human}` : `Today's matches \xB7 ${human}`,
|
|
3834
|
+
matches: todays,
|
|
3835
|
+
marketSignals: await signalsFor(todays),
|
|
3836
|
+
source,
|
|
3837
|
+
emptyNote: `No matches scheduled for ${human}.`,
|
|
3838
|
+
installLine: "npx @claudinho/cli today",
|
|
3839
|
+
tz: args.tz,
|
|
3840
|
+
locale: args.lang
|
|
3841
|
+
},
|
|
3842
|
+
options
|
|
3843
|
+
);
|
|
3844
|
+
}
|
|
3599
3845
|
|
|
3600
3846
|
// src/server.ts
|
|
3601
3847
|
var SERVER_NAME = "claudinho";
|
|
3602
|
-
var SERVER_VERSION = "0.
|
|
3848
|
+
var SERVER_VERSION = "0.4.1";
|
|
3603
3849
|
var VOICE = asFlavorLevel(process.env.CLAUDINHO_FLAVOR) === "off" ? "" : `
|
|
3604
3850
|
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.`;
|
|
3605
3851
|
var INSTRUCTIONS = `Claudinho serves live scores, fixtures, and group standings for the 2026 men's football tournament.
|
|
3606
3852
|
Use get_live during matches, get_today for a day's schedule, get_next_fixture for a specific team (3-letter code, e.g. MEX), and get_standings for group tables.
|
|
3607
|
-
Use get_market_signal for read-only prediction-market odds (a match, a team's next fixture, or a date). Market data is informational only \u2014 relay the percentages factually and never frame it as betting or trading advice
|
|
3853
|
+
Use get_market_signal for read-only prediction-market odds (a match, a team's next fixture, or a date). Market data is informational only \u2014 relay the percentages factually and never frame it as betting or trading advice.
|
|
3854
|
+
Use get_share_snippet to produce a ready-to-paste match card (for a match, a team's next fixture, a date, or live matches) \u2014 hand the user the returned snippet text verbatim.${VOICE}
|
|
3608
3855
|
${DISCLAIMER}`;
|
|
3609
3856
|
var dateArg = z.string().refine(isValidDate, "must be a real calendar date in YYYY-MM-DD form");
|
|
3610
3857
|
var groupArg = z.string().regex(/^[A-La-l]$/, "a group letter A\u2013L");
|
|
@@ -3702,6 +3949,27 @@ function buildServer() {
|
|
|
3702
3949
|
},
|
|
3703
3950
|
async (args) => toContent(await toolGetMarketSignal(args))
|
|
3704
3951
|
);
|
|
3952
|
+
server.registerTool(
|
|
3953
|
+
"get_share_snippet",
|
|
3954
|
+
{
|
|
3955
|
+
title: "Shareable match snippet",
|
|
3956
|
+
description: "A polished, copy-pasteable match card (plain text) for a match (matchId), a team's next fixture (team), a date (default: today), or live matches (live: true). Returns the ready-to-paste snippet plus structured data \u2014 hand the snippet text to the user verbatim. No links; it carries a non-affiliation disclaimer, and any market line stays informational only.",
|
|
3957
|
+
inputSchema: {
|
|
3958
|
+
matchId: z.string().optional().describe("Match id (most specific)"),
|
|
3959
|
+
team: teamArg.optional().describe("3-letter team code for that team's next fixture, e.g. MEX"),
|
|
3960
|
+
date: dateArg.optional().describe("Date as YYYY-MM-DD (default: today)"),
|
|
3961
|
+
live: z.boolean().optional().describe("Snapshot of matches in play right now"),
|
|
3962
|
+
style: z.enum(["social", "compact"]).optional().describe("social (default, full card) or compact (one line per match)"),
|
|
3963
|
+
includeHashtag: z.boolean().optional().describe("Include the #VibingLaVidaLoca tag (default true)"),
|
|
3964
|
+
includeInstallLine: z.boolean().optional().describe('Include the "Try it: \u2026" run cue (default true)'),
|
|
3965
|
+
includeMarkets: z.boolean().optional().describe("Include the reliable market line when available (default true)"),
|
|
3966
|
+
...commonArgs
|
|
3967
|
+
},
|
|
3968
|
+
// Read-only; may reach the live/market data providers (live/today/match).
|
|
3969
|
+
annotations: { readOnlyHint: true, openWorldHint: true }
|
|
3970
|
+
},
|
|
3971
|
+
async (args) => toContent(await toolGetShareSnippet(args))
|
|
3972
|
+
);
|
|
3705
3973
|
server.registerResource(
|
|
3706
3974
|
"standings",
|
|
3707
3975
|
new ResourceTemplate("standings://{group}", { list: void 0 }),
|
|
@@ -3755,7 +4023,7 @@ function buildServer() {
|
|
|
3755
4023
|
"my_team",
|
|
3756
4024
|
{
|
|
3757
4025
|
title: "My team",
|
|
3758
|
-
description: "Focus on one team's next match and
|
|
4026
|
+
description: "Focus on one team's next match, group situation, and the prediction-market read.",
|
|
3759
4027
|
argsSchema: { team: teamArg.describe("3-letter team code, e.g. MEX") }
|
|
3760
4028
|
},
|
|
3761
4029
|
({ team }) => ({
|
|
@@ -3764,7 +4032,7 @@ function buildServer() {
|
|
|
3764
4032
|
role: "user",
|
|
3765
4033
|
content: {
|
|
3766
4034
|
type: "text",
|
|
3767
|
-
text: `Using get_next_fixture and
|
|
4035
|
+
text: `Using get_next_fixture, get_standings, and get_market_signal, tell me about ${team}'s next match in the 2026 tournament, their current group standing, and what prediction markets currently say about that match. Treat the market percentages as informational context only \u2014 relay them factually, never as betting or trading advice.`
|
|
3768
4036
|
}
|
|
3769
4037
|
}
|
|
3770
4038
|
]
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@claudinho/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "Claudinho MCP server — ask your agent about the 2026 men's football tournament: live scores, fixtures, standings, prediction-market odds. Not affiliated with FIFA or Anthropic.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"tsup": "^8.0.0",
|
|
48
48
|
"typescript": "^5.7.0",
|
|
49
49
|
"vitest": "^4.1.0",
|
|
50
|
-
"@claudinho/core": "0.
|
|
50
|
+
"@claudinho/core": "0.4.1"
|
|
51
51
|
},
|
|
52
52
|
"scripts": {
|
|
53
53
|
"build": "tsup",
|