@claudinho/cli 0.8.11 → 0.8.13
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 +3 -0
- package/dist/index.js +159 -58
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
**The 2026 men's football tournament, right in your terminal.** Live scores, fixtures, group tables, and market signals — TZ-aware, localized, scriptable. No API key, no signup.
|
|
4
4
|
|
|
5
|
+
> ⭐ Installing via `npx` or globally? **[Star the repo](https://github.com/arturogarrido/claudinho)** — a fan project runs on stars. (`claudinho star` shows you how anytime.)
|
|
6
|
+
|
|
5
7
|
## Install
|
|
6
8
|
|
|
7
9
|
```bash
|
|
@@ -48,6 +50,7 @@ claudinho init-cursor-statusline # (granular) wire just the Cursor CLI statusli
|
|
|
48
50
|
claudinho hook # live-score context for a Claude Code hook (silent off-match)
|
|
49
51
|
claudinho init-hook # (granular) make Claude itself score-aware (UserPromptSubmit)
|
|
50
52
|
claudinho vibe # a matchday-coder one-liner (#VibingLaVidaLoca)
|
|
53
|
+
claudinho star # how to support the project (star the repo ⭐)
|
|
51
54
|
```
|
|
52
55
|
|
|
53
56
|
### Examples
|
package/dist/index.js
CHANGED
|
@@ -496,6 +496,10 @@ function localDate(iso, tz) {
|
|
|
496
496
|
timeZone: zone
|
|
497
497
|
}).format(new Date(iso));
|
|
498
498
|
}
|
|
499
|
+
function shiftUtcDate(dateISO, days) {
|
|
500
|
+
const [y, m, d] = dateISO.slice(0, 10).split("-").map(Number);
|
|
501
|
+
return new Date(Date.UTC(y ?? 1970, (m ?? 1) - 1, (d ?? 1) + days)).toISOString().slice(0, 10);
|
|
502
|
+
}
|
|
499
503
|
function outcomeFromScore(home, away) {
|
|
500
504
|
if (home > away) return "H";
|
|
501
505
|
if (home < away) return "A";
|
|
@@ -3835,14 +3839,19 @@ async function getBracket(adapter, opts = {}) {
|
|
|
3835
3839
|
source
|
|
3836
3840
|
};
|
|
3837
3841
|
}
|
|
3838
|
-
function shiftUtcDate(dateISO, days) {
|
|
3839
|
-
const [y, m, d] = dateISO.slice(0, 10).split("-").map(Number);
|
|
3840
|
-
return new Date(Date.UTC(y ?? 1970, (m ?? 1) - 1, (d ?? 1) + days)).toISOString().slice(0, 10);
|
|
3841
|
-
}
|
|
3842
3842
|
var EXTRA_TIME_SLACK_MS = 60 * 6e4;
|
|
3843
3843
|
async function marketFixtureForTeam(adapter, code, now = /* @__PURE__ */ new Date()) {
|
|
3844
3844
|
const nowMs = now.getTime();
|
|
3845
|
-
|
|
3845
|
+
let fixtures = allFixtures();
|
|
3846
|
+
let overlayFailed = false;
|
|
3847
|
+
try {
|
|
3848
|
+
if (adapter.fetchWindow) {
|
|
3849
|
+
fixtures = mergeLive(fixtures, await adapter.fetchWindow(KNOCKOUT_WINDOW_START, KNOCKOUT_WINDOW_END));
|
|
3850
|
+
}
|
|
3851
|
+
} catch {
|
|
3852
|
+
overlayFailed = true;
|
|
3853
|
+
}
|
|
3854
|
+
const candidate = fixturesByTeam(code, fixtures).find((m) => {
|
|
3846
3855
|
const k = Date.parse(m.kickoff);
|
|
3847
3856
|
return nowMs >= k && nowMs <= k + LIVE_WINDOW_MS + EXTRA_TIME_SLACK_MS;
|
|
3848
3857
|
});
|
|
@@ -3851,8 +3860,8 @@ async function marketFixtureForTeam(adapter, code, now = /* @__PURE__ */ new Dat
|
|
|
3851
3860
|
const m = r.match ?? candidate;
|
|
3852
3861
|
if (!isFinished(m.status)) return { ...r, match: m };
|
|
3853
3862
|
}
|
|
3854
|
-
const next = nextFixtureForTeam(code, { from: now });
|
|
3855
|
-
return { match: next, degraded:
|
|
3863
|
+
const next = nextFixtureForTeam(code, { from: now, fixtures });
|
|
3864
|
+
return { match: next, degraded: overlayFailed };
|
|
3856
3865
|
}
|
|
3857
3866
|
async function getNextFixtureForTeam(adapter, code, now = /* @__PURE__ */ new Date()) {
|
|
3858
3867
|
const base = allFixtures();
|
|
@@ -3959,6 +3968,9 @@ function mapsCleanly(match, outcomes) {
|
|
|
3959
3968
|
if (match.stage === "GROUP" && !draw) return false;
|
|
3960
3969
|
return true;
|
|
3961
3970
|
}
|
|
3971
|
+
function marketSignalRendersFor(match, signal) {
|
|
3972
|
+
return signal.matchId === match.id && mapsCleanly(match, signal.outcomes);
|
|
3973
|
+
}
|
|
3962
3974
|
function hasSaneDistribution(outcomes) {
|
|
3963
3975
|
const priced = outcomes.filter((o) => Number.isFinite(o.probability) && o.probability > 0);
|
|
3964
3976
|
if (priced.length < 2) return false;
|
|
@@ -4154,12 +4166,15 @@ var PolymarketProvider = class {
|
|
|
4154
4166
|
*/
|
|
4155
4167
|
async resolveOne(match, options) {
|
|
4156
4168
|
const entry = (this.opts.mapping ?? BUNDLED_MAPPING)[match.id];
|
|
4157
|
-
const
|
|
4158
|
-
if (
|
|
4169
|
+
const slugs = entry?.eventSlug ? [entry.eventSlug] : deriveEventSlugs(match);
|
|
4170
|
+
if (slugs.length === 0) return { checked: true };
|
|
4159
4171
|
try {
|
|
4160
|
-
const
|
|
4161
|
-
|
|
4162
|
-
|
|
4172
|
+
for (const slug of slugs) {
|
|
4173
|
+
const event = await this.fetchEvent(slug, options?.timeoutMs);
|
|
4174
|
+
const signal = event ? this.toSignal(match, slug, event, options) : void 0;
|
|
4175
|
+
if (signal) return { signal, checked: true };
|
|
4176
|
+
}
|
|
4177
|
+
return { checked: true };
|
|
4163
4178
|
} catch {
|
|
4164
4179
|
return { checked: false };
|
|
4165
4180
|
}
|
|
@@ -4235,14 +4250,17 @@ var PolymarketProvider = class {
|
|
|
4235
4250
|
return signal.ambiguous ? void 0 : signal;
|
|
4236
4251
|
}
|
|
4237
4252
|
};
|
|
4238
|
-
function
|
|
4253
|
+
function deriveEventSlugs(match) {
|
|
4239
4254
|
const home = match.home.code.toLowerCase();
|
|
4240
4255
|
const away = match.away.code.toLowerCase();
|
|
4241
|
-
if (home === away || home === "tbd" || away === "tbd") return
|
|
4242
|
-
if (!/^[a-z]{3}$/.test(home) || !/^[a-z]{3}$/.test(away)) return
|
|
4243
|
-
const
|
|
4244
|
-
if (!/^\d{4}-\d{2}-\d{2}$/.test(
|
|
4245
|
-
return
|
|
4256
|
+
if (home === away || home === "tbd" || away === "tbd") return [];
|
|
4257
|
+
if (!/^[a-z]{3}$/.test(home) || !/^[a-z]{3}$/.test(away)) return [];
|
|
4258
|
+
const utcDate = match.kickoff.slice(0, 10);
|
|
4259
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(utcDate)) return [];
|
|
4260
|
+
return [
|
|
4261
|
+
`fifwc-${home}-${away}-${utcDate}`,
|
|
4262
|
+
`fifwc-${home}-${away}-${shiftUtcDate(utcDate, -1)}`
|
|
4263
|
+
];
|
|
4246
4264
|
}
|
|
4247
4265
|
function slugToken(m) {
|
|
4248
4266
|
return (m.slug ?? "").toLowerCase().split("-").pop() ?? "";
|
|
@@ -4900,6 +4918,37 @@ function writeMarketCache(source, competition, attempted, fetched, now = Date.no
|
|
|
4900
4918
|
}
|
|
4901
4919
|
}
|
|
4902
4920
|
|
|
4921
|
+
// src/starNudge.ts
|
|
4922
|
+
import { mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
4923
|
+
import { homedir as homedir2 } from "os";
|
|
4924
|
+
import { dirname, join as join2 } from "path";
|
|
4925
|
+
var REPO_URL = "https://github.com/arturogarrido/claudinho";
|
|
4926
|
+
var NUDGE_EVERY = 5;
|
|
4927
|
+
function counterPath() {
|
|
4928
|
+
const base = process.env.XDG_CACHE_HOME || join2(homedir2(), ".cache");
|
|
4929
|
+
return join2(base, "claudinho", "runs.json");
|
|
4930
|
+
}
|
|
4931
|
+
function shouldNudge(runCount, every = NUDGE_EVERY) {
|
|
4932
|
+
return runCount > 0 && runCount % every === 0;
|
|
4933
|
+
}
|
|
4934
|
+
function bumpRunCount(path = counterPath()) {
|
|
4935
|
+
try {
|
|
4936
|
+
let count = 0;
|
|
4937
|
+
try {
|
|
4938
|
+
const raw = JSON.parse(readFileSync2(path, "utf8"));
|
|
4939
|
+
if (typeof raw.count === "number" && Number.isFinite(raw.count)) count = raw.count;
|
|
4940
|
+
} catch {
|
|
4941
|
+
count = 0;
|
|
4942
|
+
}
|
|
4943
|
+
count += 1;
|
|
4944
|
+
mkdirSync2(dirname(path), { recursive: true });
|
|
4945
|
+
writeFileSync2(path, JSON.stringify({ count }), "utf8");
|
|
4946
|
+
return count;
|
|
4947
|
+
} catch {
|
|
4948
|
+
return void 0;
|
|
4949
|
+
}
|
|
4950
|
+
}
|
|
4951
|
+
|
|
4903
4952
|
// src/clipboard.ts
|
|
4904
4953
|
import { spawnSync } from "child_process";
|
|
4905
4954
|
function clipboardTools(platform) {
|
|
@@ -4929,30 +4978,30 @@ function copyToClipboard(text, platform = process.platform) {
|
|
|
4929
4978
|
// src/cache.ts
|
|
4930
4979
|
import {
|
|
4931
4980
|
closeSync,
|
|
4932
|
-
mkdirSync as
|
|
4981
|
+
mkdirSync as mkdirSync3,
|
|
4933
4982
|
openSync,
|
|
4934
|
-
readFileSync as
|
|
4983
|
+
readFileSync as readFileSync3,
|
|
4935
4984
|
renameSync as renameSync2,
|
|
4936
4985
|
rmSync,
|
|
4937
4986
|
statSync,
|
|
4938
4987
|
writeSync
|
|
4939
4988
|
} from "fs";
|
|
4940
|
-
import { homedir as
|
|
4941
|
-
import { join as
|
|
4989
|
+
import { homedir as homedir3 } from "os";
|
|
4990
|
+
import { join as join3 } from "path";
|
|
4942
4991
|
var LOCK_STALE_MS = 6e4;
|
|
4943
4992
|
function cacheDir2() {
|
|
4944
|
-
const base = process.env.XDG_CACHE_HOME ||
|
|
4945
|
-
return
|
|
4993
|
+
const base = process.env.XDG_CACHE_HOME || join3(homedir3(), ".cache");
|
|
4994
|
+
return join3(base, "claudinho");
|
|
4946
4995
|
}
|
|
4947
4996
|
function cachePath2() {
|
|
4948
|
-
return
|
|
4997
|
+
return join3(cacheDir2(), "state.json");
|
|
4949
4998
|
}
|
|
4950
4999
|
function lockPath() {
|
|
4951
|
-
return
|
|
5000
|
+
return join3(cacheDir2(), "refresh.lock");
|
|
4952
5001
|
}
|
|
4953
5002
|
function readState() {
|
|
4954
5003
|
try {
|
|
4955
|
-
return JSON.parse(
|
|
5004
|
+
return JSON.parse(readFileSync3(cachePath2(), "utf8"));
|
|
4956
5005
|
} catch {
|
|
4957
5006
|
return void 0;
|
|
4958
5007
|
}
|
|
@@ -4963,8 +5012,8 @@ function readCurrentState(source, competition) {
|
|
|
4963
5012
|
}
|
|
4964
5013
|
function writeState(state) {
|
|
4965
5014
|
const dir = cacheDir2();
|
|
4966
|
-
|
|
4967
|
-
const tmp =
|
|
5015
|
+
mkdirSync3(dir, { recursive: true });
|
|
5016
|
+
const tmp = join3(dir, `state.${process.pid}.tmp`);
|
|
4968
5017
|
writeFileSync_(tmp, JSON.stringify(state));
|
|
4969
5018
|
renameSync2(tmp, cachePath2());
|
|
4970
5019
|
}
|
|
@@ -4989,7 +5038,7 @@ function fixturesAgeMs(state, now = Date.now()) {
|
|
|
4989
5038
|
function lockAgeMs(now = Date.now()) {
|
|
4990
5039
|
const lp = lockPath();
|
|
4991
5040
|
try {
|
|
4992
|
-
const contents =
|
|
5041
|
+
const contents = readFileSync3(lp, "utf8");
|
|
4993
5042
|
const written = Number.parseInt(contents.split(/\s+/)[1] ?? "", 10);
|
|
4994
5043
|
if (Number.isFinite(written)) return now - written;
|
|
4995
5044
|
} catch {
|
|
@@ -5005,7 +5054,7 @@ function isLockFresh(now = Date.now()) {
|
|
|
5005
5054
|
return lockAgeMs(now) < LOCK_STALE_MS;
|
|
5006
5055
|
}
|
|
5007
5056
|
function acquireLock(now = Date.now()) {
|
|
5008
|
-
|
|
5057
|
+
mkdirSync3(cacheDir2(), { recursive: true });
|
|
5009
5058
|
const lp = lockPath();
|
|
5010
5059
|
try {
|
|
5011
5060
|
const fd = openSync(lp, "wx");
|
|
@@ -5249,7 +5298,7 @@ function spawnRefresh(source) {
|
|
|
5249
5298
|
}
|
|
5250
5299
|
|
|
5251
5300
|
// src/cursorPayload.ts
|
|
5252
|
-
import { readFileSync as
|
|
5301
|
+
import { readFileSync as readFileSync4 } from "fs";
|
|
5253
5302
|
function parseCursorPayload(raw) {
|
|
5254
5303
|
try {
|
|
5255
5304
|
const trimmed = raw.trim();
|
|
@@ -5262,7 +5311,7 @@ function parseCursorPayload(raw) {
|
|
|
5262
5311
|
function readCursorPayload() {
|
|
5263
5312
|
try {
|
|
5264
5313
|
if (process.stdin.isTTY) return void 0;
|
|
5265
|
-
return parseCursorPayload(
|
|
5314
|
+
return parseCursorPayload(readFileSync4(0, "utf8"));
|
|
5266
5315
|
} catch {
|
|
5267
5316
|
return void 0;
|
|
5268
5317
|
}
|
|
@@ -5305,17 +5354,17 @@ ${meta}`;
|
|
|
5305
5354
|
import {
|
|
5306
5355
|
copyFileSync,
|
|
5307
5356
|
existsSync,
|
|
5308
|
-
mkdirSync as
|
|
5309
|
-
readFileSync as
|
|
5310
|
-
writeFileSync as
|
|
5357
|
+
mkdirSync as mkdirSync4,
|
|
5358
|
+
readFileSync as readFileSync5,
|
|
5359
|
+
writeFileSync as writeFileSync3
|
|
5311
5360
|
} from "fs";
|
|
5312
|
-
import { homedir as
|
|
5313
|
-
import { dirname, join as
|
|
5361
|
+
import { homedir as homedir4 } from "os";
|
|
5362
|
+
import { dirname as dirname2, join as join4 } from "path";
|
|
5314
5363
|
function claudeSettingsPath() {
|
|
5315
|
-
return
|
|
5364
|
+
return join4(homedir4(), ".claude", "settings.json");
|
|
5316
5365
|
}
|
|
5317
5366
|
function cursorCliConfigPath() {
|
|
5318
|
-
return
|
|
5367
|
+
return join4(homedir4(), ".cursor", "cli-config.json");
|
|
5319
5368
|
}
|
|
5320
5369
|
function isSameCommand(configured, requested) {
|
|
5321
5370
|
return configured === requested;
|
|
@@ -5346,7 +5395,7 @@ function restartMessage(target) {
|
|
|
5346
5395
|
function readSettings(path, snippet) {
|
|
5347
5396
|
if (!existsSync(path)) return {};
|
|
5348
5397
|
try {
|
|
5349
|
-
return JSON.parse(
|
|
5398
|
+
return JSON.parse(readFileSync5(path, "utf8"));
|
|
5350
5399
|
} catch {
|
|
5351
5400
|
return {
|
|
5352
5401
|
action: "manual",
|
|
@@ -5377,8 +5426,8 @@ function initStatuslineFor(target, opts = {}) {
|
|
|
5377
5426
|
}
|
|
5378
5427
|
backupOnce(path);
|
|
5379
5428
|
settings.statusLine = sl;
|
|
5380
|
-
|
|
5381
|
-
|
|
5429
|
+
mkdirSync4(dirname2(path), { recursive: true });
|
|
5430
|
+
writeFileSync3(path, JSON.stringify(settings, null, 2) + "\n", "utf8");
|
|
5382
5431
|
const surface = target === "cursor" ? "Cursor CLI statusline" : "Statusline";
|
|
5383
5432
|
return {
|
|
5384
5433
|
action: "written",
|
|
@@ -5424,8 +5473,8 @@ function initHook(opts = {}) {
|
|
|
5424
5473
|
const hooks = settings.hooks;
|
|
5425
5474
|
hooks[CLAUDE_HOOK_EVENT] ??= [];
|
|
5426
5475
|
hooks[CLAUDE_HOOK_EVENT].push({ hooks: [{ type: "command", command }] });
|
|
5427
|
-
|
|
5428
|
-
|
|
5476
|
+
mkdirSync4(dirname2(path), { recursive: true });
|
|
5477
|
+
writeFileSync3(path, JSON.stringify(settings, null, 2) + "\n", "utf8");
|
|
5429
5478
|
return {
|
|
5430
5479
|
action: "written",
|
|
5431
5480
|
path,
|
|
@@ -5472,7 +5521,10 @@ async function reliableMarketSignals(ctx, matches) {
|
|
|
5472
5521
|
if (relevant.length === 0) return /* @__PURE__ */ new Map();
|
|
5473
5522
|
const raw = await marketSignalsFor(ctx, relevant, DEFAULT_ON_MARKET_OPTS);
|
|
5474
5523
|
const out2 = /* @__PURE__ */ new Map();
|
|
5475
|
-
for (const [id, s] of raw)
|
|
5524
|
+
for (const [id, s] of raw) {
|
|
5525
|
+
const m = relevant.find((x) => x.id === id);
|
|
5526
|
+
if (m && isReliableMarketSignal(s, { now }) && marketSignalRendersFor(m, s)) out2.set(id, s);
|
|
5527
|
+
}
|
|
5476
5528
|
return out2;
|
|
5477
5529
|
}
|
|
5478
5530
|
async function reliableMarketSignalFor(ctx, match) {
|
|
@@ -5547,6 +5599,7 @@ async function cmdToday(date, ctx) {
|
|
|
5547
5599
|
const src = dataSource(source, cfg.lang, c);
|
|
5548
5600
|
if (src) out(src);
|
|
5549
5601
|
out(disclaimer(t2, c));
|
|
5602
|
+
maybeStarNudge(ctx);
|
|
5550
5603
|
}
|
|
5551
5604
|
async function cmdLive(ctx) {
|
|
5552
5605
|
const { cfg, t: t2 } = ctx;
|
|
@@ -5573,6 +5626,7 @@ async function cmdLive(ctx) {
|
|
|
5573
5626
|
const src = dataSource(source, cfg.lang, c);
|
|
5574
5627
|
if (src) out(src);
|
|
5575
5628
|
out(disclaimer(t2, c));
|
|
5629
|
+
maybeStarNudge(ctx);
|
|
5576
5630
|
}
|
|
5577
5631
|
async function cmdNext(team, ctx) {
|
|
5578
5632
|
const { cfg, t: t2, now } = ctx;
|
|
@@ -5609,6 +5663,7 @@ async function cmdNext(team, ctx) {
|
|
|
5609
5663
|
const src = dataSource(source, cfg.lang, c);
|
|
5610
5664
|
if (src) out(src);
|
|
5611
5665
|
out(disclaimer(t2, c));
|
|
5666
|
+
maybeStarNudge(ctx);
|
|
5612
5667
|
}
|
|
5613
5668
|
async function cmdTable(group, ctx) {
|
|
5614
5669
|
const { cfg, t: t2 } = ctx;
|
|
@@ -5671,6 +5726,7 @@ async function cmdTable(group, ctx) {
|
|
|
5671
5726
|
const src = dataSource(source, cfg.lang, c);
|
|
5672
5727
|
if (src) out(src);
|
|
5673
5728
|
out(disclaimer(t2, c));
|
|
5729
|
+
maybeStarNudge(ctx);
|
|
5674
5730
|
}
|
|
5675
5731
|
var BRACKET_STAGES = /* @__PURE__ */ new Set(["R32", "R16", "QF", "SF", "3P", "F"]);
|
|
5676
5732
|
async function cmdBracket(stage, opts, ctx) {
|
|
@@ -5722,6 +5778,7 @@ async function cmdBracket(stage, opts, ctx) {
|
|
|
5722
5778
|
const src = dataSource(source, cfg.lang, c);
|
|
5723
5779
|
if (src) out(src);
|
|
5724
5780
|
out(disclaimer(t2, c));
|
|
5781
|
+
maybeStarNudge(ctx);
|
|
5725
5782
|
}
|
|
5726
5783
|
function cmdPrompt({ cfg }) {
|
|
5727
5784
|
try {
|
|
@@ -5767,13 +5824,19 @@ function printInitResult(res, cfg) {
|
|
|
5767
5824
|
out(`${mark} ${res.message}`);
|
|
5768
5825
|
}
|
|
5769
5826
|
function cmdInitStatusline(opts, { cfg }) {
|
|
5770
|
-
|
|
5827
|
+
const res = initStatusline({ print: opts.print, command: opts.command });
|
|
5828
|
+
printInitResult(res, cfg);
|
|
5829
|
+
if (!opts.print && res.action === "written") printInitStarCta(cfg);
|
|
5771
5830
|
}
|
|
5772
5831
|
function cmdInitHook(opts, { cfg }) {
|
|
5773
|
-
|
|
5832
|
+
const res = initHook({ print: opts.print, command: opts.command });
|
|
5833
|
+
printInitResult(res, cfg);
|
|
5834
|
+
if (!opts.print && res.action === "written") printInitStarCta(cfg);
|
|
5774
5835
|
}
|
|
5775
5836
|
function cmdInitCursorStatusline(opts, { cfg }) {
|
|
5776
|
-
|
|
5837
|
+
const res = initCursorStatusline({ print: opts.print, command: opts.command });
|
|
5838
|
+
printInitResult(res, cfg);
|
|
5839
|
+
if (!opts.print && res.action === "written") printInitStarCta(cfg);
|
|
5777
5840
|
}
|
|
5778
5841
|
var CURSOR_MCP_SNIPPET = `{
|
|
5779
5842
|
"mcpServers": {
|
|
@@ -5798,6 +5861,7 @@ function cmdInitCursor(opts, { cfg }) {
|
|
|
5798
5861
|
out("Tip: export CLAUDINHO_CURSOR_META=auto for a model + context line below the score.");
|
|
5799
5862
|
out("");
|
|
5800
5863
|
out("\u2192 Restart your agent session to see it.");
|
|
5864
|
+
printInitStarCta(cfg);
|
|
5801
5865
|
}
|
|
5802
5866
|
function cmdInitClaude(opts, { cfg }) {
|
|
5803
5867
|
if (opts.print) {
|
|
@@ -5818,6 +5882,7 @@ function cmdInitClaude(opts, { cfg }) {
|
|
|
5818
5882
|
out(` ${CLAUDE_MCP_ONELINER}`);
|
|
5819
5883
|
out("");
|
|
5820
5884
|
out("\u2192 Restart Claude Code to see it.");
|
|
5885
|
+
printInitStarCta(cfg);
|
|
5821
5886
|
}
|
|
5822
5887
|
async function cmdMatch(id, ctx) {
|
|
5823
5888
|
const { cfg, t: t2 } = ctx;
|
|
@@ -5866,10 +5931,11 @@ async function cmdMatch(id, ctx) {
|
|
|
5866
5931
|
const src = dataSource(liveSource, cfg.lang, c);
|
|
5867
5932
|
if (src) out(src);
|
|
5868
5933
|
out(disclaimer(t2, c));
|
|
5934
|
+
maybeStarNudge(ctx);
|
|
5869
5935
|
}
|
|
5870
5936
|
var MARKET_INFO = "Prediction-market data is informational only.";
|
|
5871
|
-
function marketDisplayable(sig) {
|
|
5872
|
-
return !sig.ambiguous && sig.favorite != null && hasSaneDistribution(sig.outcomes);
|
|
5937
|
+
function marketDisplayable(match, sig) {
|
|
5938
|
+
return marketSignalRendersFor(match, sig) && !sig.ambiguous && sig.favorite != null && hasSaneDistribution(sig.outcomes);
|
|
5873
5939
|
}
|
|
5874
5940
|
function marketHeaderLine(m, cfg) {
|
|
5875
5941
|
const when = formatDate(m.kickoff, { tz: cfg.tz, locale: cfg.lang });
|
|
@@ -5888,13 +5954,14 @@ async function cmdMarkets(target, team, ctx) {
|
|
|
5888
5954
|
precheck(cfg, t2);
|
|
5889
5955
|
const code = resolveTeamArg(team, "Usage: claudinho markets next <team> (or set CLAUDINHO_TEAM)");
|
|
5890
5956
|
const now2 = ctx.now ?? /* @__PURE__ */ new Date();
|
|
5891
|
-
const { match: fixture } = await marketFixtureForTeam(adapterFor(ctx), code, now2);
|
|
5957
|
+
const { match: fixture, degraded } = await marketFixtureForTeam(adapterFor(ctx), code, now2);
|
|
5892
5958
|
const sig = fixture && marketRelevant(fixture, now2) ? (await marketSignalsFor(ctx, [fixture], MARKETS_CMD_OPTS)).get(fixture.id) : void 0;
|
|
5893
|
-
const shown = sig && marketDisplayable(sig) ? sig : void 0;
|
|
5959
|
+
const shown = fixture && sig && marketDisplayable(fixture, sig) ? sig : void 0;
|
|
5894
5960
|
if (cfg.json) {
|
|
5895
5961
|
emitJson({
|
|
5896
5962
|
team: code,
|
|
5897
5963
|
matchId: fixture?.id ?? null,
|
|
5964
|
+
degraded,
|
|
5898
5965
|
informationalOnly: true,
|
|
5899
5966
|
signal: shown ?? null
|
|
5900
5967
|
});
|
|
@@ -5903,7 +5970,7 @@ async function cmdMarkets(target, team, ctx) {
|
|
|
5903
5970
|
const c2 = painterFor(cfg);
|
|
5904
5971
|
out();
|
|
5905
5972
|
if (!fixture) {
|
|
5906
|
-
out(c2.dim(" " + t2("next.none", { team: code })));
|
|
5973
|
+
out(c2.dim(" " + (degraded ? t2("live.degraded") : t2("next.none", { team: code }))));
|
|
5907
5974
|
} else {
|
|
5908
5975
|
out(header(marketHeaderLine(fixture, cfg), c2));
|
|
5909
5976
|
out();
|
|
@@ -5920,7 +5987,7 @@ async function cmdMarkets(target, team, ctx) {
|
|
|
5920
5987
|
const now2 = ctx.now ?? /* @__PURE__ */ new Date();
|
|
5921
5988
|
const { match } = await getMatchById(adapterFor(ctx), target);
|
|
5922
5989
|
const sig = match && marketRelevant(match, now2) ? (await marketSignalsFor(ctx, [match], MARKETS_CMD_OPTS)).get(match.id) : void 0;
|
|
5923
|
-
const shown = sig && marketDisplayable(sig) ? sig : void 0;
|
|
5990
|
+
const shown = match && sig && marketDisplayable(match, sig) ? sig : void 0;
|
|
5924
5991
|
if (cfg.json) {
|
|
5925
5992
|
emitJson({ matchId: target, informationalOnly: true, signal: shown ?? null });
|
|
5926
5993
|
return;
|
|
@@ -5949,7 +6016,7 @@ async function cmdMarkets(target, team, ctx) {
|
|
|
5949
6016
|
const relevant = todays.filter((m) => marketRelevant(m, now));
|
|
5950
6017
|
const signals = await marketSignalsFor(ctx, relevant, MARKETS_CMD_OPTS);
|
|
5951
6018
|
const rows = relevant.map((m) => ({ match: m, signal: signals.get(m.id) })).filter(
|
|
5952
|
-
(r) => !!r.signal && marketDisplayable(r.signal)
|
|
6019
|
+
(r) => !!r.signal && marketDisplayable(r.match, r.signal)
|
|
5953
6020
|
);
|
|
5954
6021
|
if (cfg.json) {
|
|
5955
6022
|
const marketSignals = {};
|
|
@@ -5979,7 +6046,10 @@ function pickShareStyle(v) {
|
|
|
5979
6046
|
async function reliableShareSignals(ctx, matches) {
|
|
5980
6047
|
const raw = await reliableMarketSignals(ctx, matches);
|
|
5981
6048
|
const out2 = /* @__PURE__ */ new Map();
|
|
5982
|
-
for (const [id, s] of raw)
|
|
6049
|
+
for (const [id, s] of raw) {
|
|
6050
|
+
const m = matches.find((x) => x.id === id);
|
|
6051
|
+
if (m && marketDisplayable(m, s)) out2.set(id, s);
|
|
6052
|
+
}
|
|
5983
6053
|
return out2;
|
|
5984
6054
|
}
|
|
5985
6055
|
function emitShare(ctx, e, copy) {
|
|
@@ -6286,6 +6356,34 @@ function vibePool(todayLocal, fixtures = allFixtures()) {
|
|
|
6286
6356
|
if (todayLocal === last) return [...VIBES, ...VIBES_FINAL];
|
|
6287
6357
|
return VIBES;
|
|
6288
6358
|
}
|
|
6359
|
+
function cmdStar(ctx) {
|
|
6360
|
+
const { cfg } = ctx;
|
|
6361
|
+
if (cfg.json) {
|
|
6362
|
+
emitJson({ repo: REPO_URL, hashtag: "#VibingLaVidaLoca" });
|
|
6363
|
+
return;
|
|
6364
|
+
}
|
|
6365
|
+
const c = painterFor(cfg);
|
|
6366
|
+
out();
|
|
6367
|
+
out(" " + c.bold("\u2B50 Star Claudinho on GitHub"));
|
|
6368
|
+
out(" " + c.cyan(REPO_URL));
|
|
6369
|
+
out();
|
|
6370
|
+
out(" " + c.dim("Built for devs & fans \xB7 #VibingLaVidaLoca \u26BD"));
|
|
6371
|
+
out(" " + c.dim("Live World Cup scores in your terminal, Claude Code & Cursor \u2014 no API keys."));
|
|
6372
|
+
out();
|
|
6373
|
+
}
|
|
6374
|
+
function maybeStarNudge(ctx) {
|
|
6375
|
+
if (ctx.cfg.json || !process.stdout.isTTY || process.env.CLAUDINHO_NO_STAR) return;
|
|
6376
|
+
const n = bumpRunCount();
|
|
6377
|
+
if (n === void 0 || !shouldNudge(n)) return;
|
|
6378
|
+
const c = painterFor(ctx.cfg);
|
|
6379
|
+
out();
|
|
6380
|
+
out(c.dim(` \u2B50 Enjoying Claudinho? Star it \u2192 ${REPO_URL} (claudinho star)`));
|
|
6381
|
+
}
|
|
6382
|
+
function printInitStarCta(cfg) {
|
|
6383
|
+
const c = painterFor(cfg);
|
|
6384
|
+
out("");
|
|
6385
|
+
out(c.dim(`\u2B50 If this keeps you in the flow during the match, star the repo \u2192 ${REPO_URL}`));
|
|
6386
|
+
}
|
|
6289
6387
|
function cmdVibe(ctx) {
|
|
6290
6388
|
const { cfg } = ctx;
|
|
6291
6389
|
const pool = vibePool(localDate((ctx.now ?? /* @__PURE__ */ new Date()).toISOString(), cfg.tz));
|
|
@@ -6319,7 +6417,7 @@ function handlePipeError(stream) {
|
|
|
6319
6417
|
}
|
|
6320
6418
|
handlePipeError(process.stdout);
|
|
6321
6419
|
handlePipeError(process.stderr);
|
|
6322
|
-
var VERSION = "0.8.
|
|
6420
|
+
var VERSION = "0.8.13";
|
|
6323
6421
|
var DISCLAIMER = "Claudinho is an independent fan project. Not affiliated with or endorsed by FIFA or Anthropic.";
|
|
6324
6422
|
function ctxFrom(cmd) {
|
|
6325
6423
|
let root = cmd;
|
|
@@ -6443,6 +6541,9 @@ program.command("init-hook").description("wire the live-score hook into Claude C
|
|
|
6443
6541
|
program.command("vibe").description("print a matchday-coder one-liner (#VibingLaVidaLoca)").action((_opts, cmd) => {
|
|
6444
6542
|
cmdVibe(ctxFrom(cmd));
|
|
6445
6543
|
});
|
|
6544
|
+
program.command("star").description("how to support Claudinho \u2014 star the repo \u2B50").action((_opts, cmd) => {
|
|
6545
|
+
cmdStar(ctxFrom(cmd));
|
|
6546
|
+
});
|
|
6446
6547
|
var refreshCmd = new Command("_refresh").description("(internal) refresh the statusline cache").action(async (_opts, cmd) => {
|
|
6447
6548
|
try {
|
|
6448
6549
|
await cmdRefresh(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.13",
|
|
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.13"
|
|
65
65
|
},
|
|
66
66
|
"scripts": {
|
|
67
67
|
"build": "tsup",
|