@claudinho/cli 0.5.1 → 0.6.0
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 +27 -0
- package/dist/index.js +173 -65
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -28,6 +28,7 @@ claudinho markets [target] # prediction-market signals: today | <date> | <id> |
|
|
|
28
28
|
claudinho share [target] # copy-pasteable snippet: today | live | <date> | <id> | next <TEAM> | table <GROUP>
|
|
29
29
|
claudinho prompt # one compact status line (for statusline/tmux/Starship)
|
|
30
30
|
claudinho init-statusline # wire it into the Claude Code statusline
|
|
31
|
+
claudinho init-cursor-statusline # wire it into the Cursor CLI statusline
|
|
31
32
|
claudinho hook # live-score context for a Claude Code hook (silent off-match)
|
|
32
33
|
claudinho init-hook # make Claude itself score-aware (UserPromptSubmit)
|
|
33
34
|
claudinho vibe # a matchday-coder one-liner (#VibingLaVidaLoca)
|
|
@@ -177,6 +178,32 @@ Wires `claudinho hook` into Claude Code's `UserPromptSubmit`. During a match,
|
|
|
177
178
|
the live score is injected into Claude's context so it can mention it naturally;
|
|
178
179
|
off-match it's silent (zero added tokens). Restart Claude Code to activate.
|
|
179
180
|
|
|
181
|
+
## Statusline (Cursor CLI)
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
claudinho init-cursor-statusline # patches ~/.cursor/cli-config.json (backs up first)
|
|
185
|
+
claudinho init-cursor-statusline --print # just print the snippet
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Uses the same `claudinho prompt` hot path as Claude Code. Cursor-specific tuning
|
|
189
|
+
is applied automatically (`updateIntervalMs: 1000`, `timeoutMs: 1500`).
|
|
190
|
+
|
|
191
|
+
Optional second line with session meta (model, context %, worktree, vim mode) **below** the score:
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
export CLAUDINHO_CURSOR_META=auto # recommended for Cursor CLI
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Custom command (local dev or monorepo checkout):
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
claudinho init-cursor-statusline --command "node ./packages/cli/dist/index.js prompt"
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
> Cursor's `beforeSubmitPrompt` hook does not yet reliably inject live-score
|
|
204
|
+
> context into the model. Use `init-hook` for Claude Code; Cursor CLI is
|
|
205
|
+
> statusline-only until hook injection lands.
|
|
206
|
+
|
|
180
207
|
## How it works
|
|
181
208
|
|
|
182
209
|
The full fixture list (104 matches, groups, venues, host cities, kickoffs) ships **bundled**
|
package/dist/index.js
CHANGED
|
@@ -2814,9 +2814,15 @@ var EspnAdapter = class {
|
|
|
2814
2814
|
async fetchWindow(startDate, endDate) {
|
|
2815
2815
|
return this.fetchScoreboard(`${toEspnDate(startDate)}-${toEspnDate(endDate)}`);
|
|
2816
2816
|
}
|
|
2817
|
+
/**
|
|
2818
|
+
* In-play matches from ESPN's DEFAULT scoreboard bucket only (no `dates`). This
|
|
2819
|
+
* single bucket misses a late kickoff ESPN files under an adjacent day, so it
|
|
2820
|
+
* is a fallback for window-less callers — the domain `getLiveMatches` wraps a
|
|
2821
|
+
* ±1-day window around this to catch boundary-crossing matches. Prefer it.
|
|
2822
|
+
*/
|
|
2817
2823
|
async fetchLive() {
|
|
2818
2824
|
const today = await this.fetchScoreboard();
|
|
2819
|
-
return today.filter((m) => m.status
|
|
2825
|
+
return today.filter((m) => isLive(m.status));
|
|
2820
2826
|
}
|
|
2821
2827
|
/** Standings endpoint URL (lives under apis/v2, not site/v2; derived from base). */
|
|
2822
2828
|
standingsUrl() {
|
|
@@ -2959,9 +2965,13 @@ async function getMatchById(adapter, id) {
|
|
|
2959
2965
|
return { match: base, degraded: true };
|
|
2960
2966
|
}
|
|
2961
2967
|
}
|
|
2962
|
-
async function getLiveMatches(adapter) {
|
|
2968
|
+
async function getLiveMatches(adapter, now = /* @__PURE__ */ new Date()) {
|
|
2963
2969
|
try {
|
|
2964
|
-
|
|
2970
|
+
const day = now.toISOString().slice(0, 10);
|
|
2971
|
+
const matches = adapter.fetchWindow ? (await adapter.fetchWindow(shiftUtcDate(day, -1), shiftUtcDate(day, 1))).filter(
|
|
2972
|
+
(m) => isLive(m.status)
|
|
2973
|
+
) : await adapter.fetchLive();
|
|
2974
|
+
return { matches, degraded: false, source: adapter.name };
|
|
2965
2975
|
} catch {
|
|
2966
2976
|
return { matches: [], degraded: true };
|
|
2967
2977
|
}
|
|
@@ -4074,7 +4084,9 @@ async function runRefresh(opts = {}) {
|
|
|
4074
4084
|
let degraded = false;
|
|
4075
4085
|
if (liveWindowActive(now.getTime())) {
|
|
4076
4086
|
try {
|
|
4077
|
-
|
|
4087
|
+
const r = await getLiveMatches(liveAdapter(), now);
|
|
4088
|
+
live = r.matches;
|
|
4089
|
+
degraded = r.degraded;
|
|
4078
4090
|
} catch {
|
|
4079
4091
|
degraded = true;
|
|
4080
4092
|
}
|
|
@@ -4102,12 +4114,65 @@ function spawnRefresh(source) {
|
|
|
4102
4114
|
}
|
|
4103
4115
|
}
|
|
4104
4116
|
|
|
4117
|
+
// src/cursorPayload.ts
|
|
4118
|
+
import { readFileSync as readFileSync3 } from "fs";
|
|
4119
|
+
function parseCursorPayload(raw) {
|
|
4120
|
+
try {
|
|
4121
|
+
const trimmed = raw.trim();
|
|
4122
|
+
if (!trimmed) return void 0;
|
|
4123
|
+
return JSON.parse(trimmed);
|
|
4124
|
+
} catch {
|
|
4125
|
+
return void 0;
|
|
4126
|
+
}
|
|
4127
|
+
}
|
|
4128
|
+
function readCursorPayload() {
|
|
4129
|
+
try {
|
|
4130
|
+
if (process.stdin.isTTY) return void 0;
|
|
4131
|
+
return parseCursorPayload(readFileSync3(0, "utf8"));
|
|
4132
|
+
} catch {
|
|
4133
|
+
return void 0;
|
|
4134
|
+
}
|
|
4135
|
+
}
|
|
4136
|
+
function looksLikeCursorPayload(payload) {
|
|
4137
|
+
return !!(payload.model?.display_name || payload.context_window != null || payload.render_width_chars != null || payload.worktree?.name || payload.vim?.mode);
|
|
4138
|
+
}
|
|
4139
|
+
function cursorMetaEnabled(payload) {
|
|
4140
|
+
const v = (process.env.CLAUDINHO_CURSOR_META ?? "").toLowerCase();
|
|
4141
|
+
if (v === "0" || v === "false" || v === "no") return false;
|
|
4142
|
+
if (v === "1" || v === "true" || v === "yes") return !!payload;
|
|
4143
|
+
if (v === "auto") return !!payload && looksLikeCursorPayload(payload);
|
|
4144
|
+
return false;
|
|
4145
|
+
}
|
|
4146
|
+
function renderCursorMetaLine(payload) {
|
|
4147
|
+
const parts = [];
|
|
4148
|
+
const model = payload.model?.display_name;
|
|
4149
|
+
if (model) {
|
|
4150
|
+
let label = model;
|
|
4151
|
+
if (payload.model?.param_summary) label += ` ${payload.model.param_summary}`;
|
|
4152
|
+
parts.push(label);
|
|
4153
|
+
}
|
|
4154
|
+
const pct2 = payload.context_window?.used_percentage;
|
|
4155
|
+
if (typeof pct2 === "number" && Number.isFinite(pct2)) {
|
|
4156
|
+
parts.push(`ctx ${Math.floor(pct2)}%`);
|
|
4157
|
+
}
|
|
4158
|
+
if (payload.worktree?.name) parts.push(`wt ${payload.worktree.name}`);
|
|
4159
|
+
if (payload.vim?.mode) parts.push(payload.vim.mode);
|
|
4160
|
+
if (parts.length === 0) return void 0;
|
|
4161
|
+
return `\x1B[90m${parts.join(" ")}\x1B[0m`;
|
|
4162
|
+
}
|
|
4163
|
+
function renderPromptOutput(scoreLine, payload) {
|
|
4164
|
+
const meta = payload && cursorMetaEnabled(payload) ? renderCursorMetaLine(payload) : void 0;
|
|
4165
|
+
if (meta) return `${scoreLine}
|
|
4166
|
+
${meta}`;
|
|
4167
|
+
return scoreLine;
|
|
4168
|
+
}
|
|
4169
|
+
|
|
4105
4170
|
// src/install.ts
|
|
4106
4171
|
import {
|
|
4107
4172
|
copyFileSync,
|
|
4108
4173
|
existsSync,
|
|
4109
4174
|
mkdirSync as mkdirSync3,
|
|
4110
|
-
readFileSync as
|
|
4175
|
+
readFileSync as readFileSync4,
|
|
4111
4176
|
writeFileSync as writeFileSync2
|
|
4112
4177
|
} from "fs";
|
|
4113
4178
|
import { homedir as homedir3 } from "os";
|
|
@@ -4115,80 +4180,116 @@ import { dirname, join as join3 } from "path";
|
|
|
4115
4180
|
function claudeSettingsPath() {
|
|
4116
4181
|
return join3(homedir3(), ".claude", "settings.json");
|
|
4117
4182
|
}
|
|
4183
|
+
function cursorCliConfigPath() {
|
|
4184
|
+
return join3(homedir3(), ".cursor", "cli-config.json");
|
|
4185
|
+
}
|
|
4186
|
+
function isSameCommand(configured, requested) {
|
|
4187
|
+
return configured === requested;
|
|
4188
|
+
}
|
|
4118
4189
|
function backupOnce(path) {
|
|
4119
4190
|
const bak = `${path}.claudinho.bak`;
|
|
4120
4191
|
if (existsSync(path) && !existsSync(bak)) copyFileSync(path, bak);
|
|
4121
4192
|
}
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4193
|
+
var DEFAULT_PROMPT_COMMAND = "claudinho prompt";
|
|
4194
|
+
var HOOK_COMMAND = "claudinho hook";
|
|
4195
|
+
var CURSOR_STATUSLINE_DEFAULTS = {
|
|
4196
|
+
padding: 0,
|
|
4197
|
+
updateIntervalMs: 1e3,
|
|
4198
|
+
timeoutMs: 1500
|
|
4199
|
+
};
|
|
4200
|
+
function configPathFor(target, override) {
|
|
4201
|
+
if (override) return override;
|
|
4202
|
+
return target === "cursor" ? cursorCliConfigPath() : claudeSettingsPath();
|
|
4203
|
+
}
|
|
4204
|
+
function defaultStatusLineConfig(target, command) {
|
|
4205
|
+
const base = { type: "command", command };
|
|
4206
|
+
if (target === "cursor") return { ...base, ...CURSOR_STATUSLINE_DEFAULTS };
|
|
4207
|
+
return base;
|
|
4208
|
+
}
|
|
4209
|
+
function restartMessage(target) {
|
|
4210
|
+
return target === "cursor" ? "Restart Cursor CLI (or start a new session) to see it." : "Restart Claude Code to see it.";
|
|
4211
|
+
}
|
|
4212
|
+
function readSettings(path, snippet) {
|
|
4213
|
+
if (!existsSync(path)) return {};
|
|
4214
|
+
try {
|
|
4215
|
+
return JSON.parse(readFileSync4(path, "utf8"));
|
|
4216
|
+
} catch {
|
|
4217
|
+
return {
|
|
4218
|
+
action: "manual",
|
|
4219
|
+
path,
|
|
4220
|
+
message: `Could not parse ${path}. Add this manually:
|
|
4221
|
+
${snippet}`
|
|
4222
|
+
};
|
|
4223
|
+
}
|
|
4224
|
+
}
|
|
4225
|
+
function isInitResult(v) {
|
|
4226
|
+
return "action" in v && typeof v.action === "string";
|
|
4227
|
+
}
|
|
4228
|
+
function initStatuslineFor(target, opts = {}) {
|
|
4229
|
+
const path = configPathFor(target, opts.path);
|
|
4230
|
+
const command = opts.command ?? DEFAULT_PROMPT_COMMAND;
|
|
4231
|
+
const sl = defaultStatusLineConfig(target, command);
|
|
4125
4232
|
const snippet = JSON.stringify({ statusLine: sl }, null, 2);
|
|
4126
4233
|
if (opts.print) {
|
|
4127
4234
|
return { action: "printed", path, message: snippet };
|
|
4128
4235
|
}
|
|
4129
|
-
|
|
4130
|
-
if (
|
|
4131
|
-
|
|
4132
|
-
settings = JSON.parse(readFileSync3(path, "utf8"));
|
|
4133
|
-
} catch {
|
|
4134
|
-
return {
|
|
4135
|
-
action: "manual",
|
|
4136
|
-
path,
|
|
4137
|
-
message: `Could not parse ${path}. Add this manually:
|
|
4138
|
-
${snippet}`
|
|
4139
|
-
};
|
|
4140
|
-
}
|
|
4141
|
-
}
|
|
4236
|
+
const parsed = readSettings(path, snippet);
|
|
4237
|
+
if (isInitResult(parsed)) return parsed;
|
|
4238
|
+
const settings = parsed;
|
|
4142
4239
|
const existing = settings.statusLine;
|
|
4143
|
-
if (existing?.command
|
|
4144
|
-
|
|
4240
|
+
if (isSameCommand(existing?.command, command)) {
|
|
4241
|
+
const label = target === "cursor" ? "Cursor CLI statusline" : "Statusline";
|
|
4242
|
+
return { action: "already", path, message: `${label} already configured (${path}).` };
|
|
4145
4243
|
}
|
|
4146
4244
|
backupOnce(path);
|
|
4147
4245
|
settings.statusLine = sl;
|
|
4148
4246
|
mkdirSync3(dirname(path), { recursive: true });
|
|
4149
4247
|
writeFileSync2(path, JSON.stringify(settings, null, 2) + "\n", "utf8");
|
|
4248
|
+
const surface = target === "cursor" ? "Cursor CLI statusline" : "Statusline";
|
|
4150
4249
|
return {
|
|
4151
4250
|
action: "written",
|
|
4152
4251
|
path,
|
|
4153
|
-
message:
|
|
4252
|
+
message: `${surface} configured in ${path}. ${restartMessage(target)}`
|
|
4154
4253
|
};
|
|
4155
4254
|
}
|
|
4156
|
-
|
|
4157
|
-
|
|
4255
|
+
function initStatusline(opts = {}) {
|
|
4256
|
+
return initStatuslineFor("claude", opts);
|
|
4257
|
+
}
|
|
4258
|
+
function initCursorStatusline(opts = {}) {
|
|
4259
|
+
return initStatuslineFor("cursor", opts);
|
|
4260
|
+
}
|
|
4261
|
+
var CLAUDE_HOOK_EVENT = "UserPromptSubmit";
|
|
4262
|
+
function claudeHookCommands(settings) {
|
|
4263
|
+
const hooks = settings.hooks;
|
|
4264
|
+
const matchers = hooks?.[CLAUDE_HOOK_EVENT] ?? [];
|
|
4265
|
+
return matchers.flatMap(
|
|
4266
|
+
(m) => (m.hooks ?? []).map((h) => h.command).filter((c) => typeof c === "string")
|
|
4267
|
+
);
|
|
4268
|
+
}
|
|
4158
4269
|
function initHook(opts = {}) {
|
|
4159
4270
|
const path = opts.path ?? claudeSettingsPath();
|
|
4160
4271
|
const command = opts.command ?? HOOK_COMMAND;
|
|
4161
4272
|
const snippet = JSON.stringify(
|
|
4162
|
-
{ hooks: { [
|
|
4273
|
+
{ hooks: { [CLAUDE_HOOK_EVENT]: [{ hooks: [{ type: "command", command }] }] } },
|
|
4163
4274
|
null,
|
|
4164
4275
|
2
|
|
4165
4276
|
);
|
|
4166
4277
|
if (opts.print) return { action: "printed", path, message: snippet };
|
|
4167
|
-
|
|
4168
|
-
if (
|
|
4169
|
-
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
|
|
4173
|
-
|
|
4174
|
-
|
|
4175
|
-
|
|
4176
|
-
${snippet}`
|
|
4177
|
-
};
|
|
4178
|
-
}
|
|
4278
|
+
const parsed = readSettings(path, snippet);
|
|
4279
|
+
if (isInitResult(parsed)) return parsed;
|
|
4280
|
+
const settings = parsed;
|
|
4281
|
+
if (claudeHookCommands(settings).some((c) => isSameCommand(c, command))) {
|
|
4282
|
+
return {
|
|
4283
|
+
action: "already",
|
|
4284
|
+
path,
|
|
4285
|
+
message: `UserPromptSubmit hook already configured (${path}).`
|
|
4286
|
+
};
|
|
4179
4287
|
}
|
|
4288
|
+
backupOnce(path);
|
|
4180
4289
|
settings.hooks ??= {};
|
|
4181
4290
|
const hooks = settings.hooks;
|
|
4182
|
-
hooks[
|
|
4183
|
-
|
|
4184
|
-
const already = matchers.some(
|
|
4185
|
-
(m) => (m.hooks ?? []).some((h) => typeof h.command === "string" && h.command.includes("claudinho"))
|
|
4186
|
-
);
|
|
4187
|
-
if (already) {
|
|
4188
|
-
return { action: "already", path, message: `UserPromptSubmit hook already uses claudinho (${path}).` };
|
|
4189
|
-
}
|
|
4190
|
-
backupOnce(path);
|
|
4191
|
-
matchers.push({ hooks: [{ type: "command", command }] });
|
|
4291
|
+
hooks[CLAUDE_HOOK_EVENT] ??= [];
|
|
4292
|
+
hooks[CLAUDE_HOOK_EVENT].push({ hooks: [{ type: "command", command }] });
|
|
4192
4293
|
mkdirSync3(dirname(path), { recursive: true });
|
|
4193
4294
|
writeFileSync2(path, JSON.stringify(settings, null, 2) + "\n", "utf8");
|
|
4194
4295
|
return {
|
|
@@ -4427,6 +4528,7 @@ async function cmdTable(group, ctx) {
|
|
|
4427
4528
|
}
|
|
4428
4529
|
function cmdPrompt({ cfg }) {
|
|
4429
4530
|
try {
|
|
4531
|
+
const payload = readCursorPayload();
|
|
4430
4532
|
const team = process.env.CLAUDINHO_TEAM;
|
|
4431
4533
|
const compact = !["0", "false", "no"].includes(
|
|
4432
4534
|
(process.env.CLAUDINHO_COMPACT ?? "").toLowerCase()
|
|
@@ -4434,7 +4536,8 @@ function cmdPrompt({ cfg }) {
|
|
|
4434
4536
|
const maxRaw = Number.parseInt(process.env.CLAUDINHO_MAX ?? "", 10);
|
|
4435
4537
|
const max = Number.isFinite(maxRaw) && maxRaw > 0 ? maxRaw : void 0;
|
|
4436
4538
|
const state = readCurrentState(cfg.source, resolveCompetition());
|
|
4437
|
-
|
|
4539
|
+
const scoreLine = renderPrompt(state, { team, compact, max });
|
|
4540
|
+
out(renderPromptOutput(scoreLine, payload));
|
|
4438
4541
|
if (!state || shouldRefresh()) spawnRefresh(cfg.source);
|
|
4439
4542
|
} catch {
|
|
4440
4543
|
out("");
|
|
@@ -4453,8 +4556,7 @@ function cmdHook({ cfg }) {
|
|
|
4453
4556
|
async function cmdRefresh({ cfg }) {
|
|
4454
4557
|
await runRefresh({ source: cfg.source });
|
|
4455
4558
|
}
|
|
4456
|
-
function
|
|
4457
|
-
const res = initStatusline({ print: opts.print });
|
|
4559
|
+
function printInitResult(res, cfg) {
|
|
4458
4560
|
const c = painterFor(cfg);
|
|
4459
4561
|
if (res.action === "printed") {
|
|
4460
4562
|
out(res.message);
|
|
@@ -4463,15 +4565,14 @@ function cmdInitStatusline(opts, { cfg }) {
|
|
|
4463
4565
|
const mark = res.action === "written" ? c.green("\u2713") : res.action === "already" ? c.cyan("\u2022") : c.yellow("!");
|
|
4464
4566
|
out(`${mark} ${res.message}`);
|
|
4465
4567
|
}
|
|
4568
|
+
function cmdInitStatusline(opts, { cfg }) {
|
|
4569
|
+
printInitResult(initStatusline({ print: opts.print, command: opts.command }), cfg);
|
|
4570
|
+
}
|
|
4466
4571
|
function cmdInitHook(opts, { cfg }) {
|
|
4467
|
-
|
|
4468
|
-
|
|
4469
|
-
|
|
4470
|
-
|
|
4471
|
-
return;
|
|
4472
|
-
}
|
|
4473
|
-
const mark = res.action === "written" ? c.green("\u2713") : res.action === "already" ? c.cyan("\u2022") : c.yellow("!");
|
|
4474
|
-
out(`${mark} ${res.message}`);
|
|
4572
|
+
printInitResult(initHook({ print: opts.print, command: opts.command }), cfg);
|
|
4573
|
+
}
|
|
4574
|
+
function cmdInitCursorStatusline(opts, { cfg }) {
|
|
4575
|
+
printInitResult(initCursorStatusline({ print: opts.print, command: opts.command }), cfg);
|
|
4475
4576
|
}
|
|
4476
4577
|
async function cmdMatch(id, ctx) {
|
|
4477
4578
|
const { cfg, t } = ctx;
|
|
@@ -4902,7 +5003,7 @@ function handlePipeError(stream) {
|
|
|
4902
5003
|
}
|
|
4903
5004
|
handlePipeError(process.stdout);
|
|
4904
5005
|
handlePipeError(process.stderr);
|
|
4905
|
-
var VERSION = "0.
|
|
5006
|
+
var VERSION = "0.6.0";
|
|
4906
5007
|
var DISCLAIMER = "Claudinho is an independent fan project. Not affiliated with or endorsed by FIFA or Anthropic.";
|
|
4907
5008
|
function ctxFrom(cmd) {
|
|
4908
5009
|
const root = cmd.parent ?? cmd;
|
|
@@ -4918,7 +5019,7 @@ function fail(err) {
|
|
|
4918
5019
|
}
|
|
4919
5020
|
var program = new Command();
|
|
4920
5021
|
program.name("claudinho").description(
|
|
4921
|
-
"The 2026 men\u2019s football tournament in your terminal, your Claude Code statusline, and any MCP client.\n" + DISCLAIMER
|
|
5022
|
+
"The 2026 men\u2019s football tournament in your terminal, your Claude Code / Cursor CLI statusline, and any MCP client.\n" + DISCLAIMER
|
|
4922
5023
|
).version(VERSION, "-v, --version").option("--lang <code>", "language: en, es, pt, fr").option("--tz <zone>", "IANA timezone, e.g. America/Mexico_City").option("--json", "output JSON (for scripting)").option("--no-color", "disable ANSI colors").option("--source <name>", "live data provider (advanced)").option("--flavor <level>", "commentary flair: off, subtle, full (default: full)").option("--no-markets", "hide prediction-market signals (informational only)");
|
|
4923
5024
|
program.addHelpText("after", "\n#VibingLaVidaLoca \u26BD");
|
|
4924
5025
|
program.command("today").description("show a day's fixtures (default: today)").argument("[date]", "date as YYYY-MM-DD").action(async (date, _opts, cmd) => {
|
|
@@ -4973,20 +5074,27 @@ program.command("share").description("print a shareable, copy-pasteable match sn
|
|
|
4973
5074
|
fail(e);
|
|
4974
5075
|
}
|
|
4975
5076
|
});
|
|
4976
|
-
program.command("prompt").description("print a
|
|
5077
|
+
program.command("prompt").description("print a status line (Claude Code / Cursor CLI statusline, tmux, Starship, \u2026)").action((_opts, cmd) => {
|
|
4977
5078
|
cmdPrompt(ctxFrom(cmd));
|
|
4978
5079
|
});
|
|
4979
|
-
program.command("init-statusline").description("configure the Claude Code statusline to use claudinho").option("--print", "print the settings snippet instead of writing it").action((opts, cmd) => {
|
|
5080
|
+
program.command("init-statusline").description("configure the Claude Code statusline to use claudinho").option("--print", "print the settings snippet instead of writing it").option("--command <cmd>", "command to run (default: claudinho prompt)").action((opts, cmd) => {
|
|
4980
5081
|
try {
|
|
4981
5082
|
cmdInitStatusline(opts, ctxFrom(cmd));
|
|
4982
5083
|
} catch (e) {
|
|
4983
5084
|
fail(e);
|
|
4984
5085
|
}
|
|
4985
5086
|
});
|
|
5087
|
+
program.command("init-cursor-statusline").description("configure the Cursor CLI statusline to use claudinho").option("--print", "print the settings snippet instead of writing it").option("--command <cmd>", "command to run (default: claudinho prompt)").action((opts, cmd) => {
|
|
5088
|
+
try {
|
|
5089
|
+
cmdInitCursorStatusline(opts, ctxFrom(cmd));
|
|
5090
|
+
} catch (e) {
|
|
5091
|
+
fail(e);
|
|
5092
|
+
}
|
|
5093
|
+
});
|
|
4986
5094
|
program.command("hook").description("print live-score context for a Claude Code UserPromptSubmit hook (silent off-match)").action((_opts, cmd) => {
|
|
4987
5095
|
cmdHook(ctxFrom(cmd));
|
|
4988
5096
|
});
|
|
4989
|
-
program.command("init-hook").description("wire the live-score hook into Claude Code (UserPromptSubmit)").option("--print", "print the settings snippet instead of writing it").action((opts, cmd) => {
|
|
5097
|
+
program.command("init-hook").description("wire the live-score hook into Claude Code (UserPromptSubmit)").option("--print", "print the settings snippet instead of writing it").option("--command <cmd>", "command to run (default: claudinho hook)").action((opts, cmd) => {
|
|
4990
5098
|
try {
|
|
4991
5099
|
cmdInitHook(opts, ctxFrom(cmd));
|
|
4992
5100
|
} catch (e) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@claudinho/cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Live scores, fixtures, group tables, and read-only prediction-market signals for the 2026 men's football tournament — in your terminal
|
|
3
|
+
"version": "0.6.0",
|
|
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",
|
|
7
7
|
"author": "Arturo Garrido",
|
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
"terminal",
|
|
44
44
|
"statusline",
|
|
45
45
|
"claude-code",
|
|
46
|
+
"cursor-cli",
|
|
46
47
|
"2026",
|
|
47
48
|
"vibinglavidaloca"
|
|
48
49
|
],
|
|
@@ -56,7 +57,7 @@
|
|
|
56
57
|
"tsup": "^8.0.0",
|
|
57
58
|
"typescript": "^5.7.0",
|
|
58
59
|
"vitest": "^4.1.0",
|
|
59
|
-
"@claudinho/core": "0.
|
|
60
|
+
"@claudinho/core": "0.6.0"
|
|
60
61
|
},
|
|
61
62
|
"scripts": {
|
|
62
63
|
"build": "tsup",
|