@claudinho/cli 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 +67 -0
- package/dist/index.js +295 -3
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -24,6 +24,7 @@ claudinho next <TEAM> # a team's next fixture + countdown (e.g. next MEX
|
|
|
24
24
|
claudinho table [GROUP] # group standings (default: all groups)
|
|
25
25
|
claudinho match <id> # a single match's detail
|
|
26
26
|
claudinho markets [target] # prediction-market odds: today | <date> | <id> | next <TEAM>
|
|
27
|
+
claudinho share [target] # copy-pasteable match snippet: today | live | <date> | <id> | next <TEAM>
|
|
27
28
|
claudinho prompt # one compact status line (for statusline/tmux/Starship)
|
|
28
29
|
claudinho init-statusline # wire it into the Claude Code statusline
|
|
29
30
|
claudinho hook # live-score context for a Claude Code hook (silent off-match)
|
|
@@ -39,6 +40,7 @@ claudinho next BRA --tz America/Sao_Paulo --lang pt
|
|
|
39
40
|
claudinho table A
|
|
40
41
|
claudinho live --json | jq '.matches[].status'
|
|
41
42
|
claudinho today --flavor off # just the facts, no commentary
|
|
43
|
+
claudinho share next MEX --copy # a shareable card, copied to your clipboard
|
|
42
44
|
```
|
|
43
45
|
|
|
44
46
|
## Global options
|
|
@@ -95,6 +97,71 @@ statusline and hook **never** show market data — it stays off the hot path.
|
|
|
95
97
|
> nothing. For an offline preview, set `CLAUDINHO_MARKETS_SOURCE=fake` to render
|
|
96
98
|
> clearly-labeled synthetic **"demo data"** odds.
|
|
97
99
|
|
|
100
|
+
## Shareable snippets
|
|
101
|
+
|
|
102
|
+
`claudinho share` prints a polished, **copy-pasteable** match card for chats,
|
|
103
|
+
social posts, READMEs, and issue comments — your terminal football, ready to post:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
claudinho share # today's matches
|
|
107
|
+
claudinho share live # matches in play
|
|
108
|
+
claudinho share next MEX # a team's next fixture (+ market read, when reliable)
|
|
109
|
+
claudinho share 760415 # one match by id
|
|
110
|
+
claudinho share next MEX --copy # …and copy it straight to the clipboard
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
```text
|
|
114
|
+
Next up for Mexico
|
|
115
|
+
|
|
116
|
+
🇲🇽 Mexico vs South Africa 🇿🇦
|
|
117
|
+
Jun 11 · 13:00 America/Mexico_City
|
|
118
|
+
Estadio Banorte, Mexico City, Mexico
|
|
119
|
+
|
|
120
|
+
Prediction markets slightly favor Mexico.
|
|
121
|
+
Mexico 56% · Draw 25% · South Africa 19%
|
|
122
|
+
Source: Polymarket · informational only
|
|
123
|
+
|
|
124
|
+
#VibingLaVidaLoca · Independent fan project · not affiliated with FIFA or Anthropic.
|
|
125
|
+
Try it: npx @claudinho/cli next MEX
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Snippets are **plain text** (no color codes — they paste cleanly everywhere) and
|
|
129
|
+
carry the non-affiliation disclaimer on every paste. The market line uses the
|
|
130
|
+
same reliable gate as `today`/`match` (**informational only — never betting
|
|
131
|
+
advice**) and disappears when no reliable market exists. Per-command options:
|
|
132
|
+
|
|
133
|
+
| Flag | Description |
|
|
134
|
+
|---|---|
|
|
135
|
+
| `--style <social\|compact>` | `social` (default) is the full card; `compact` is one terse line per match |
|
|
136
|
+
| `--copy` | also copy the snippet to the clipboard (best-effort: `pbcopy`/`clip`/`wl-copy`/`xclip`/`xsel`) |
|
|
137
|
+
| `--no-hashtag` | omit the `#VibingLaVidaLoca` tag |
|
|
138
|
+
| `--no-install-line` | omit the `Try it: …` run cue |
|
|
139
|
+
|
|
140
|
+
`--json` returns the structured snippet (`{ kind, snippet, matches, marketSignals, … }`)
|
|
141
|
+
for scripts and future reuse. No clipboard tool? `claudinho share … | pbcopy` works too.
|
|
142
|
+
|
|
143
|
+
### Want an image?
|
|
144
|
+
|
|
145
|
+
The snippet is plain text, so a **screenshot is your share card** — the disclaimer
|
|
146
|
+
and emoji flags come along automatically. Grab it with your OS screenshot tool, or
|
|
147
|
+
render a crisp terminal image with an existing tool (no Claudinho dependency, no
|
|
148
|
+
account):
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
# capture the command's output directly (charmbracelet/freeze)
|
|
152
|
+
freeze --execute "claudinho share next MEX" -o card.png
|
|
153
|
+
|
|
154
|
+
# …or pipe the text into freeze / silicon
|
|
155
|
+
claudinho share next MEX | freeze --language text -o card.png
|
|
156
|
+
claudinho share next MEX | silicon -l txt -o card.png
|
|
157
|
+
|
|
158
|
+
# …or paste it into a web tool like carbon.now.sh or ray.so
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Claudinho stays text-first — it doesn't ship an image renderer, so there's nothing
|
|
162
|
+
extra to install in the CLI and no fonts/licensing to worry about: whatever your
|
|
163
|
+
terminal or the screenshot tool already draws (including the flags) is what you get.
|
|
164
|
+
|
|
98
165
|
## Statusline (Claude Code)
|
|
99
166
|
|
|
100
167
|
```bash
|
package/dist/index.js
CHANGED
|
@@ -311,6 +311,25 @@ function formatKickoff(iso, opts = {}) {
|
|
|
311
311
|
timeZone: tz
|
|
312
312
|
}).format(new Date(iso));
|
|
313
313
|
}
|
|
314
|
+
function formatDate(iso, opts = {}) {
|
|
315
|
+
const tz = resolveTz(opts.tz);
|
|
316
|
+
const locale = safeLocale(opts.locale);
|
|
317
|
+
return new Intl.DateTimeFormat(locale, {
|
|
318
|
+
month: "short",
|
|
319
|
+
day: "numeric",
|
|
320
|
+
timeZone: tz
|
|
321
|
+
}).format(new Date(iso));
|
|
322
|
+
}
|
|
323
|
+
function formatTime(iso, opts = {}) {
|
|
324
|
+
const tz = resolveTz(opts.tz);
|
|
325
|
+
const locale = safeLocale(opts.locale);
|
|
326
|
+
return new Intl.DateTimeFormat(locale, {
|
|
327
|
+
hour: "2-digit",
|
|
328
|
+
minute: "2-digit",
|
|
329
|
+
hour12: false,
|
|
330
|
+
timeZone: tz
|
|
331
|
+
}).format(new Date(iso));
|
|
332
|
+
}
|
|
314
333
|
function countdown(iso, from = /* @__PURE__ */ new Date()) {
|
|
315
334
|
const ms = new Date(iso).getTime() - from.getTime();
|
|
316
335
|
if (ms <= 0) return "now";
|
|
@@ -3269,6 +3288,87 @@ async function getMarketSignals(provider, matches, options) {
|
|
|
3269
3288
|
return { signals: /* @__PURE__ */ new Map(), checked: /* @__PURE__ */ new Set() };
|
|
3270
3289
|
}
|
|
3271
3290
|
}
|
|
3291
|
+
var SHARE_HASHTAG = "#VibingLaVidaLoca";
|
|
3292
|
+
var SHARE_DISCLAIMER = "Independent fan project \xB7 not affiliated with FIFA or Anthropic.";
|
|
3293
|
+
function mid(m) {
|
|
3294
|
+
return isLive(m.status) || m.status === "FT" ? scoreline(m) : "vs";
|
|
3295
|
+
}
|
|
3296
|
+
function statusTail(m) {
|
|
3297
|
+
switch (m.status) {
|
|
3298
|
+
case "LIVE":
|
|
3299
|
+
return m.minute ? `${m.minute}'` : "LIVE";
|
|
3300
|
+
case "HT":
|
|
3301
|
+
return "HT";
|
|
3302
|
+
case "FT":
|
|
3303
|
+
return "FT";
|
|
3304
|
+
case "POSTPONED":
|
|
3305
|
+
return "postponed";
|
|
3306
|
+
case "CANCELLED":
|
|
3307
|
+
return "cancelled";
|
|
3308
|
+
default:
|
|
3309
|
+
return "";
|
|
3310
|
+
}
|
|
3311
|
+
}
|
|
3312
|
+
function compactLine(m, input, single) {
|
|
3313
|
+
const home = `${m.home.flag} ${m.home.code}`;
|
|
3314
|
+
const away = `${m.away.code} ${m.away.flag}`;
|
|
3315
|
+
const opts = { tz: input.tz, locale: input.locale };
|
|
3316
|
+
let tail;
|
|
3317
|
+
if (m.status === "SCHEDULED") {
|
|
3318
|
+
const time = formatTime(m.kickoff, opts);
|
|
3319
|
+
tail = single ? `${formatDate(m.kickoff, opts)} ${time}` : time;
|
|
3320
|
+
} else {
|
|
3321
|
+
tail = statusTail(m);
|
|
3322
|
+
}
|
|
3323
|
+
return `${home} ${mid(m)} ${away}${tail ? ` \xB7 ${tail}` : ""}`;
|
|
3324
|
+
}
|
|
3325
|
+
function socialCard(m, input) {
|
|
3326
|
+
const lines = [];
|
|
3327
|
+
const head = `${m.home.flag} ${m.home.name} ${mid(m)} ${m.away.name} ${m.away.flag}`;
|
|
3328
|
+
if (m.status === "SCHEDULED") {
|
|
3329
|
+
lines.push(head);
|
|
3330
|
+
const date = formatDate(m.kickoff, { tz: input.tz, locale: input.locale });
|
|
3331
|
+
const time = formatTime(m.kickoff, { tz: input.tz, locale: input.locale });
|
|
3332
|
+
const zone = input.tz ? ` ${input.tz}` : "";
|
|
3333
|
+
lines.push(`${date} \xB7 ${time}${zone}`);
|
|
3334
|
+
} else {
|
|
3335
|
+
const tail = statusTail(m);
|
|
3336
|
+
lines.push(tail ? `${head} \xB7 ${tail}` : head);
|
|
3337
|
+
}
|
|
3338
|
+
const loc = matchLocation(m);
|
|
3339
|
+
if (loc) lines.push(loc);
|
|
3340
|
+
return lines;
|
|
3341
|
+
}
|
|
3342
|
+
function formatShareSnippet(input, options = {}) {
|
|
3343
|
+
const style = options.style ?? "social";
|
|
3344
|
+
const includeMarkets = options.includeMarkets !== false;
|
|
3345
|
+
const includeHashtag = options.includeHashtag !== false;
|
|
3346
|
+
const includeInstall = options.includeInstallLine !== false;
|
|
3347
|
+
const signals = input.marketSignals ?? /* @__PURE__ */ new Map();
|
|
3348
|
+
const single = input.matches.length === 1;
|
|
3349
|
+
const blocks = [input.title];
|
|
3350
|
+
if (input.matches.length === 0) {
|
|
3351
|
+
if (input.emptyNote) blocks.push(input.emptyNote);
|
|
3352
|
+
} else if (style === "compact") {
|
|
3353
|
+
blocks.push(input.matches.map((m) => compactLine(m, input, single)).join("\n"));
|
|
3354
|
+
} else {
|
|
3355
|
+
for (const m of input.matches) {
|
|
3356
|
+
const card = socialCard(m, input);
|
|
3357
|
+
const sig = includeMarkets ? signals.get(m.id) : void 0;
|
|
3358
|
+
if (sig) {
|
|
3359
|
+
if (single) card.push("", ...marketBlock(sig, m));
|
|
3360
|
+
else card.push(marketLine(sig, m));
|
|
3361
|
+
}
|
|
3362
|
+
blocks.push(card.join("\n"));
|
|
3363
|
+
}
|
|
3364
|
+
}
|
|
3365
|
+
const footer = [];
|
|
3366
|
+
if (input.source) footer.push(`Live data: ${liveSourceLabel(input.source)}`);
|
|
3367
|
+
footer.push([includeHashtag ? SHARE_HASHTAG : "", SHARE_DISCLAIMER].filter(Boolean).join(" \xB7 "));
|
|
3368
|
+
if (includeInstall && input.installLine) footer.push(`Try it: ${input.installLine}`);
|
|
3369
|
+
blocks.push(footer.join("\n"));
|
|
3370
|
+
return blocks.join("\n\n");
|
|
3371
|
+
}
|
|
3272
3372
|
|
|
3273
3373
|
// src/config.ts
|
|
3274
3374
|
var SUPPORTED_LANGS = ["en", "es", "pt", "fr"];
|
|
@@ -3494,8 +3594,8 @@ function statusToken(m, t, c) {
|
|
|
3494
3594
|
function matchLine(m, cfg, t, c) {
|
|
3495
3595
|
const home = `${m.home.flag} ${m.home.name}`;
|
|
3496
3596
|
const away = `${m.away.name} ${m.away.flag}`;
|
|
3497
|
-
const
|
|
3498
|
-
const left = `${home.padEnd(22)} ${
|
|
3597
|
+
const mid2 = isLive(m.status) || m.status === "FT" ? c.bold(scoreline(m)) : c.dim("vs");
|
|
3598
|
+
const left = `${home.padEnd(22)} ${mid2.padStart(3)} ${away}`;
|
|
3499
3599
|
let right = "";
|
|
3500
3600
|
if (m.status === "SCHEDULED") {
|
|
3501
3601
|
right = c.dim(
|
|
@@ -3572,6 +3672,32 @@ function writeMarketCache(source, competition, attempted, fetched, now = Date.no
|
|
|
3572
3672
|
}
|
|
3573
3673
|
}
|
|
3574
3674
|
|
|
3675
|
+
// src/clipboard.ts
|
|
3676
|
+
import { spawnSync } from "child_process";
|
|
3677
|
+
function clipboardTools(platform) {
|
|
3678
|
+
if (platform === "darwin") return [{ cmd: "pbcopy", args: [] }];
|
|
3679
|
+
if (platform === "win32") return [{ cmd: "clip", args: [] }];
|
|
3680
|
+
return [
|
|
3681
|
+
{ cmd: "wl-copy", args: [] },
|
|
3682
|
+
{ cmd: "xclip", args: ["-selection", "clipboard"] },
|
|
3683
|
+
{ cmd: "xsel", args: ["--clipboard", "--input"] }
|
|
3684
|
+
];
|
|
3685
|
+
}
|
|
3686
|
+
function copyToClipboard(text, platform = process.platform) {
|
|
3687
|
+
for (const { cmd, args } of clipboardTools(platform)) {
|
|
3688
|
+
try {
|
|
3689
|
+
const res = spawnSync(cmd, args, {
|
|
3690
|
+
input: text,
|
|
3691
|
+
stdio: ["pipe", "ignore", "ignore"],
|
|
3692
|
+
timeout: 1e3
|
|
3693
|
+
});
|
|
3694
|
+
if (!res.error && res.status === 0) return true;
|
|
3695
|
+
} catch {
|
|
3696
|
+
}
|
|
3697
|
+
}
|
|
3698
|
+
return false;
|
|
3699
|
+
}
|
|
3700
|
+
|
|
3575
3701
|
// src/cache.ts
|
|
3576
3702
|
import {
|
|
3577
3703
|
closeSync,
|
|
@@ -4319,6 +4445,165 @@ async function cmdMarkets(target, team, ctx) {
|
|
|
4319
4445
|
out(disclaimer(t, c));
|
|
4320
4446
|
out(c.dim(MARKET_INFO));
|
|
4321
4447
|
}
|
|
4448
|
+
function pickShareStyle(v) {
|
|
4449
|
+
return v === "compact" ? "compact" : "social";
|
|
4450
|
+
}
|
|
4451
|
+
async function reliableShareSignals(ctx, matches) {
|
|
4452
|
+
const raw = await reliableMarketSignals(ctx, matches);
|
|
4453
|
+
const out2 = /* @__PURE__ */ new Map();
|
|
4454
|
+
for (const [id, s] of raw) if (marketDisplayable(s)) out2.set(id, s);
|
|
4455
|
+
return out2;
|
|
4456
|
+
}
|
|
4457
|
+
function emitShare(ctx, e, copy) {
|
|
4458
|
+
const snippet = formatShareSnippet(e.input, e.options);
|
|
4459
|
+
if (ctx.cfg.json) {
|
|
4460
|
+
emitJson({
|
|
4461
|
+
kind: e.kind,
|
|
4462
|
+
target: e.target,
|
|
4463
|
+
...e.team ? { team: e.team } : {},
|
|
4464
|
+
source: e.input.source ?? null,
|
|
4465
|
+
informationalOnly: true,
|
|
4466
|
+
style: e.options.style ?? "social",
|
|
4467
|
+
snippet,
|
|
4468
|
+
matches: e.input.matches,
|
|
4469
|
+
marketSignals: Object.fromEntries(e.input.marketSignals ?? /* @__PURE__ */ new Map())
|
|
4470
|
+
});
|
|
4471
|
+
} else {
|
|
4472
|
+
out(snippet);
|
|
4473
|
+
}
|
|
4474
|
+
if (copy) {
|
|
4475
|
+
const ok = (ctx.copy ?? copyToClipboard)(snippet);
|
|
4476
|
+
process.stderr.write(
|
|
4477
|
+
(ok ? "Copied share snippet to clipboard." : "Clipboard unavailable; printed snippet instead.") + "\n"
|
|
4478
|
+
);
|
|
4479
|
+
}
|
|
4480
|
+
}
|
|
4481
|
+
async function cmdShare(target, team, opts, ctx) {
|
|
4482
|
+
const { cfg, t } = ctx;
|
|
4483
|
+
const baseOptions = {
|
|
4484
|
+
style: pickShareStyle(opts.style),
|
|
4485
|
+
includeMarkets: cfg.markets !== false,
|
|
4486
|
+
includeHashtag: opts.hashtag !== false,
|
|
4487
|
+
includeInstallLine: opts.installLine !== false
|
|
4488
|
+
};
|
|
4489
|
+
const copy = opts.copy === true;
|
|
4490
|
+
if (target === "live") {
|
|
4491
|
+
precheck(cfg, t);
|
|
4492
|
+
const { matches, source: source2 } = await getLiveMatches(adapterFor(ctx));
|
|
4493
|
+
emitShare(
|
|
4494
|
+
ctx,
|
|
4495
|
+
{
|
|
4496
|
+
kind: "live",
|
|
4497
|
+
target: "live",
|
|
4498
|
+
input: {
|
|
4499
|
+
title: "Live match pulse",
|
|
4500
|
+
matches,
|
|
4501
|
+
source: source2,
|
|
4502
|
+
emptyNote: "No matches in play right now.",
|
|
4503
|
+
installLine: "npx @claudinho/cli live",
|
|
4504
|
+
tz: cfg.tz,
|
|
4505
|
+
locale: cfg.lang
|
|
4506
|
+
},
|
|
4507
|
+
// Live snippets stay lean: no market enrichment (and no extra fetch).
|
|
4508
|
+
options: { ...baseOptions, includeMarkets: false }
|
|
4509
|
+
},
|
|
4510
|
+
copy
|
|
4511
|
+
);
|
|
4512
|
+
return;
|
|
4513
|
+
}
|
|
4514
|
+
if (target === "next") {
|
|
4515
|
+
precheck(cfg, t);
|
|
4516
|
+
if (!team) throw new InputError("Usage: claudinho share next <team>");
|
|
4517
|
+
const code = team.toUpperCase();
|
|
4518
|
+
const fixture = nextFixtureForTeam(code);
|
|
4519
|
+
const matches = fixture ? [fixture] : [];
|
|
4520
|
+
const signals2 = await reliableShareSignals(ctx, matches);
|
|
4521
|
+
const teamName = fixture ? fixture.home.code === code ? fixture.home.name : fixture.away.name : code;
|
|
4522
|
+
emitShare(
|
|
4523
|
+
ctx,
|
|
4524
|
+
{
|
|
4525
|
+
kind: "next",
|
|
4526
|
+
target: "next",
|
|
4527
|
+
team: code,
|
|
4528
|
+
input: {
|
|
4529
|
+
title: `Next up for ${teamName}`,
|
|
4530
|
+
matches,
|
|
4531
|
+
marketSignals: signals2,
|
|
4532
|
+
emptyNote: `No upcoming fixture found for ${code}.`,
|
|
4533
|
+
installLine: `npx @claudinho/cli next ${code}`,
|
|
4534
|
+
tz: cfg.tz,
|
|
4535
|
+
locale: cfg.lang
|
|
4536
|
+
},
|
|
4537
|
+
options: baseOptions
|
|
4538
|
+
},
|
|
4539
|
+
copy
|
|
4540
|
+
);
|
|
4541
|
+
return;
|
|
4542
|
+
}
|
|
4543
|
+
if (target && target !== "today" && !isValidDate(target)) {
|
|
4544
|
+
precheck(cfg, t);
|
|
4545
|
+
const adapter = adapterFor(ctx);
|
|
4546
|
+
let match = allFixtures().find((m) => m.id === target);
|
|
4547
|
+
let source2;
|
|
4548
|
+
try {
|
|
4549
|
+
if (match) {
|
|
4550
|
+
const live = await adapter.fetchByDate(match.kickoff.slice(0, 10));
|
|
4551
|
+
match = live.find((m) => m.id === target) ?? match;
|
|
4552
|
+
source2 = adapter.name;
|
|
4553
|
+
}
|
|
4554
|
+
} catch {
|
|
4555
|
+
}
|
|
4556
|
+
const matches = match ? [match] : [];
|
|
4557
|
+
const signals2 = await reliableShareSignals(ctx, matches);
|
|
4558
|
+
emitShare(
|
|
4559
|
+
ctx,
|
|
4560
|
+
{
|
|
4561
|
+
kind: "match",
|
|
4562
|
+
target,
|
|
4563
|
+
input: {
|
|
4564
|
+
title: "Match pulse",
|
|
4565
|
+
matches,
|
|
4566
|
+
marketSignals: signals2,
|
|
4567
|
+
source: source2,
|
|
4568
|
+
emptyNote: `No match found with id ${target}.`,
|
|
4569
|
+
installLine: `npx @claudinho/cli match ${target}`,
|
|
4570
|
+
tz: cfg.tz,
|
|
4571
|
+
locale: cfg.lang
|
|
4572
|
+
},
|
|
4573
|
+
options: baseOptions
|
|
4574
|
+
},
|
|
4575
|
+
copy
|
|
4576
|
+
);
|
|
4577
|
+
return;
|
|
4578
|
+
}
|
|
4579
|
+
const explicitDate = target && target !== "today" ? target : void 0;
|
|
4580
|
+
precheck(cfg, t, explicitDate);
|
|
4581
|
+
const date = explicitDate ?? localDate((/* @__PURE__ */ new Date()).toISOString(), cfg.tz);
|
|
4582
|
+
const { matches: all, source } = await getMatchesForDate(adapterFor(ctx), date);
|
|
4583
|
+
const todays = fixturesByDate(date, all, cfg.tz);
|
|
4584
|
+
const signals = await reliableShareSignals(ctx, todays);
|
|
4585
|
+
const human = formatDate(`${date}T12:00:00.000Z`, { tz: cfg.tz, locale: cfg.lang });
|
|
4586
|
+
const title = explicitDate ? `Matches \xB7 ${human}` : `Today's matches \xB7 ${human}`;
|
|
4587
|
+
emitShare(
|
|
4588
|
+
ctx,
|
|
4589
|
+
{
|
|
4590
|
+
kind: "today",
|
|
4591
|
+
target: date,
|
|
4592
|
+
input: {
|
|
4593
|
+
title,
|
|
4594
|
+
matches: todays,
|
|
4595
|
+
marketSignals: signals,
|
|
4596
|
+
source,
|
|
4597
|
+
emptyNote: `No matches scheduled for ${human}.`,
|
|
4598
|
+
installLine: "npx @claudinho/cli today",
|
|
4599
|
+
tz: cfg.tz,
|
|
4600
|
+
locale: cfg.lang
|
|
4601
|
+
},
|
|
4602
|
+
options: baseOptions
|
|
4603
|
+
},
|
|
4604
|
+
copy
|
|
4605
|
+
);
|
|
4606
|
+
}
|
|
4322
4607
|
var VIBES = [
|
|
4323
4608
|
"Shipping code, watching goals.",
|
|
4324
4609
|
"Green tests, green pitch.",
|
|
@@ -4352,7 +4637,7 @@ function handlePipeError(stream) {
|
|
|
4352
4637
|
}
|
|
4353
4638
|
handlePipeError(process.stdout);
|
|
4354
4639
|
handlePipeError(process.stderr);
|
|
4355
|
-
var VERSION = "0.
|
|
4640
|
+
var VERSION = "0.4.1";
|
|
4356
4641
|
var DISCLAIMER = "Claudinho is an independent fan project. Not affiliated with or endorsed by FIFA or Anthropic.";
|
|
4357
4642
|
function ctxFrom(cmd) {
|
|
4358
4643
|
const root = cmd.parent ?? cmd;
|
|
@@ -4411,6 +4696,13 @@ program.command("markets").description("show prediction-market signals (read-onl
|
|
|
4411
4696
|
fail(e);
|
|
4412
4697
|
}
|
|
4413
4698
|
});
|
|
4699
|
+
program.command("share").description("print a shareable, copy-pasteable match snippet (#VibingLaVidaLoca)").argument("[target]", '"today" (default), "live", a date, a match id, or "next"').argument("[team]", 'team code when target is "next" (e.g. MEX)').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) => {
|
|
4700
|
+
try {
|
|
4701
|
+
await cmdShare(target, team, opts, ctxFrom(cmd));
|
|
4702
|
+
} catch (e) {
|
|
4703
|
+
fail(e);
|
|
4704
|
+
}
|
|
4705
|
+
});
|
|
4414
4706
|
program.command("prompt").description("print a one-line status (Claude Code statusline, tmux, Starship, \u2026)").action((_opts, cmd) => {
|
|
4415
4707
|
cmdPrompt(ctxFrom(cmd));
|
|
4416
4708
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@claudinho/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "Claudinho CLI — the 2026 men's football tournament in your terminal: live scores, fixtures, group tables, prediction-market odds. Not affiliated with FIFA or Anthropic.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"tsup": "^8.0.0",
|
|
49
49
|
"typescript": "^5.7.0",
|
|
50
50
|
"vitest": "^4.1.0",
|
|
51
|
-
"@claudinho/core": "0.
|
|
51
|
+
"@claudinho/core": "0.4.1"
|
|
52
52
|
},
|
|
53
53
|
"scripts": {
|
|
54
54
|
"build": "tsup",
|