@przeprogramowani/10x-cli 1.9.0 → 1.11.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.
Files changed (2) hide show
  1. package/dist/index.mjs +245 -24
  2. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -2271,7 +2271,7 @@ var cac = (name = "") => new CAC(name);
2271
2271
  // package.json
2272
2272
  var package_default = {
2273
2273
  name: "@przeprogramowani/10x-cli",
2274
- version: "1.9.0",
2274
+ version: "1.11.0",
2275
2275
  description: "Open-source CLI for 10xDevs course content",
2276
2276
  repository: {
2277
2277
  type: "git",
@@ -3521,6 +3521,248 @@ function handleLoginError(ctx, status, code, error) {
3521
3521
  outputError(ctx, code || "auth_error", "Authentication failed.", ExitCodes.ERROR, error ? `Server said: ${error}` : undefined);
3522
3522
  }
3523
3523
 
3524
+ // src/lib/bench-client.ts
3525
+ var DEFAULT_BENCH_BASE = "https://10xbench.ai";
3526
+ var PROD_HOSTNAME2 = "10xbench.ai";
3527
+ var DEV_HOSTNAMES2 = new Set(["localhost", "127.0.0.1"]);
3528
+ function resolveBenchBase() {
3529
+ const override = process.env["BENCH_BASE_URL"];
3530
+ if (!override)
3531
+ return DEFAULT_BENCH_BASE;
3532
+ let url;
3533
+ try {
3534
+ url = new URL(override);
3535
+ } catch {
3536
+ throw new Error(`BENCH_BASE_URL is not a valid URL: ${JSON.stringify(override)}`);
3537
+ }
3538
+ if (url.pathname !== "/" && url.pathname !== "") {
3539
+ throw new Error(`BENCH_BASE_URL must not include a path (got ${JSON.stringify(url.pathname)})`);
3540
+ }
3541
+ if (url.search !== "" || url.hash !== "") {
3542
+ throw new Error("BENCH_BASE_URL must not include a query string or fragment");
3543
+ }
3544
+ if (url.protocol === "https:" && url.hostname === PROD_HOSTNAME2) {
3545
+ return `${url.protocol}//${url.host}`;
3546
+ }
3547
+ if (url.protocol === "http:" && DEV_HOSTNAMES2.has(url.hostname)) {
3548
+ return `${url.protocol}//${url.host}`;
3549
+ }
3550
+ throw new Error(`BENCH_BASE_URL must be ${DEFAULT_BENCH_BASE} or http://localhost[:port] (got ${JSON.stringify(override)})`);
3551
+ }
3552
+ var SUPPORTED_LEADERBOARD_SCHEMA = 1;
3553
+ var LEADERBOARD_PATH = "/api/leaderboard.json";
3554
+ var DEFAULT_TIMEOUT_MS3 = 30000;
3555
+ function isLeaderboardResponse(value) {
3556
+ if (value === null || typeof value !== "object")
3557
+ return false;
3558
+ const v2 = value;
3559
+ return typeof v2.schemaVersion === "number" && typeof v2.generatedAt === "string" && typeof v2.totalModels === "number" && Array.isArray(v2.leaderboard);
3560
+ }
3561
+ async function fetchLeaderboard(options = {}) {
3562
+ const url = `${resolveBenchBase()}${LEADERBOARD_PATH}`;
3563
+ let response;
3564
+ try {
3565
+ response = await fetch(url, {
3566
+ method: "GET",
3567
+ headers: {
3568
+ accept: "application/json",
3569
+ "user-agent": "10x-cli"
3570
+ },
3571
+ signal: options.signal ?? AbortSignal.timeout(DEFAULT_TIMEOUT_MS3)
3572
+ });
3573
+ } catch (err) {
3574
+ const message = err instanceof Error ? err.message : String(err);
3575
+ return { ok: false, status: 0, code: "network_error", error: message };
3576
+ }
3577
+ const text = await response.text();
3578
+ if (!response.ok) {
3579
+ return {
3580
+ ok: false,
3581
+ status: response.status,
3582
+ code: `http_${response.status}`,
3583
+ error: response.statusText || "Leaderboard request failed."
3584
+ };
3585
+ }
3586
+ let parsed;
3587
+ try {
3588
+ parsed = JSON.parse(text);
3589
+ } catch {
3590
+ return {
3591
+ ok: false,
3592
+ status: response.status,
3593
+ code: "bench_unavailable",
3594
+ error: "The leaderboard endpoint returned a non-JSON response."
3595
+ };
3596
+ }
3597
+ if (!isLeaderboardResponse(parsed)) {
3598
+ return {
3599
+ ok: false,
3600
+ status: response.status,
3601
+ code: "bench_unavailable",
3602
+ error: "The leaderboard endpoint returned an unexpected shape."
3603
+ };
3604
+ }
3605
+ return {
3606
+ ok: true,
3607
+ status: response.status,
3608
+ data: parsed,
3609
+ responseHeaders: response.headers,
3610
+ rawBody: text
3611
+ };
3612
+ }
3613
+
3614
+ // src/lib/format.ts
3615
+ function formatReleaseAt(iso, now = new Date) {
3616
+ const date = new Date(iso);
3617
+ if (!Number.isFinite(date.getTime()))
3618
+ return iso;
3619
+ const absolute = date.toLocaleDateString("en-US", {
3620
+ year: "numeric",
3621
+ month: "long",
3622
+ day: "numeric",
3623
+ timeZone: "UTC"
3624
+ });
3625
+ const msPerDay = 24 * 60 * 60 * 1000;
3626
+ const startOfTarget = Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate());
3627
+ const startOfNow = Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate());
3628
+ const days = Math.round((startOfTarget - startOfNow) / msPerDay);
3629
+ if (days <= 0)
3630
+ return absolute;
3631
+ if (days === 1)
3632
+ return `${absolute} (tomorrow)`;
3633
+ return `${absolute} (in ${days} days)`;
3634
+ }
3635
+
3636
+ // src/commands/bench.ts
3637
+ function registerBenchCommand(cli) {
3638
+ cli.command("bench", "Show the 10xBench top-10 model leaderboard (10xbench.ai)").option("--limit <n>", "Show only the top N models").action(async (options) => {
3639
+ const ctx = resolveContext(options);
3640
+ await runBench(ctx, options);
3641
+ });
3642
+ }
3643
+ async function runBench(ctx, options) {
3644
+ const limit = parseLimit(ctx, options.limit);
3645
+ verbose(ctx, `fetching leaderboard from ${resolveBenchBase()}`);
3646
+ const result = await fetchLeaderboard();
3647
+ if (!result.ok) {
3648
+ handleBenchError(ctx, result.status, result.code, result.error);
3649
+ }
3650
+ const data = result.data;
3651
+ if (data.schemaVersion !== SUPPORTED_LEADERBOARD_SCHEMA) {
3652
+ outputError(ctx, "unsupported_schema", `The leaderboard now uses format version ${data.schemaVersion}, but this CLI only understands version ${SUPPORTED_LEADERBOARD_SCHEMA}.`, ExitCodes.ERROR, "Run 'npm install -g @przeprogramowani/10x-cli@latest' to update, or visit https://10xbench.ai.");
3653
+ }
3654
+ renderLeaderboard(ctx, data, limit);
3655
+ }
3656
+ function parseLimit(ctx, raw) {
3657
+ if (raw === undefined)
3658
+ return null;
3659
+ const n = typeof raw === "number" ? raw : Number.parseInt(raw, 10);
3660
+ if (!Number.isInteger(n) || n < 1) {
3661
+ outputError(ctx, "invalid_limit", `'${raw}' is not a valid limit.`, ExitCodes.USAGE, "Pass a positive whole number, for example '10x bench --limit 5'.");
3662
+ }
3663
+ return n;
3664
+ }
3665
+ function handleBenchError(ctx, status, code, error) {
3666
+ if (status === 0) {
3667
+ outputError(ctx, "network_error", "Could not reach 10xbench.ai.", ExitCodes.ERROR, "Check your internet connection and run '10x bench' again.");
3668
+ }
3669
+ if (code === "bench_unavailable") {
3670
+ outputError(ctx, "bench_unavailable", "The 10xBench leaderboard is temporarily unavailable.", ExitCodes.ERROR, "Try again in a few minutes, or visit https://10xbench.ai directly.");
3671
+ }
3672
+ outputError(ctx, code || "bench_failed", "Failed to load the leaderboard.", ExitCodes.ERROR, error ? `Server said: ${error}` : undefined);
3673
+ }
3674
+ function colorsEnabled() {
3675
+ return process.env["NO_COLOR"] === undefined && process.stderr.isTTY === true;
3676
+ }
3677
+ var STYLE = {
3678
+ bold: "1",
3679
+ dim: "2",
3680
+ red: "31",
3681
+ green: "32",
3682
+ yellow: "33",
3683
+ cyan: "36"
3684
+ };
3685
+ function paint(style, text) {
3686
+ if (!colorsEnabled())
3687
+ return text;
3688
+ return `\x1B[${style}m${text}\x1B[0m`;
3689
+ }
3690
+ function scoreStyle(percentage) {
3691
+ if (percentage >= 90)
3692
+ return STYLE.green;
3693
+ if (percentage >= 60)
3694
+ return STYLE.yellow;
3695
+ return STYLE.red;
3696
+ }
3697
+ var BAR_WIDTH = 20;
3698
+ function scoreBar(percentage) {
3699
+ const clamped = Math.min(Math.max(percentage, 0), 100);
3700
+ const filled = Math.round(clamped / 100 * BAR_WIDTH);
3701
+ return "█".repeat(filled) + "░".repeat(BAR_WIDTH - filled);
3702
+ }
3703
+ function renderLeaderboard(ctx, data, limit) {
3704
+ const ranked = limit === null ? data.leaderboard : data.leaderboard.slice(0, limit);
3705
+ if (ctx.json) {
3706
+ output(ctx, "", {
3707
+ source: resolveBenchBase(),
3708
+ generatedAt: data.generatedAt,
3709
+ totalAttempts: data.totalAttempts,
3710
+ totalModels: data.totalModels,
3711
+ models: ranked.map((e2, i) => ({
3712
+ rank: i + 1,
3713
+ model: e2.modelName,
3714
+ modelBaseId: e2.modelBaseId,
3715
+ score: e2.averageScore,
3716
+ maxScore: e2.averageMaxScore,
3717
+ percentage: e2.averagePercentage,
3718
+ attempts: e2.attemptCount,
3719
+ environment: e2.agentEnvironment,
3720
+ averageCost: e2.averageCost
3721
+ }))
3722
+ });
3723
+ return;
3724
+ }
3725
+ if (ranked.length === 0) {
3726
+ output(ctx, "The leaderboard has no results yet.", undefined);
3727
+ return;
3728
+ }
3729
+ const names = ranked.map((e2) => sanitize(e2.modelName));
3730
+ const details = ranked.map((e2) => formatDetail(e2));
3731
+ const nameWidth = Math.max(...names.map((n) => n.length));
3732
+ const detailWidth = Math.max(...details.map((d2) => d2.length));
3733
+ const rankWidth = String(ranked.length).length;
3734
+ const lines = [];
3735
+ lines.push(paint(STYLE.bold, `10xBench — Top ${ranked.length} of ${data.totalModels} models`) + paint(STYLE.dim, ` (${data.totalAttempts} attempts scored)`));
3736
+ lines.push("");
3737
+ for (let i = 0;i < ranked.length; i++) {
3738
+ lines.push(formatRow(ranked[i], i + 1, names[i], details[i], rankWidth, nameWidth, detailWidth));
3739
+ }
3740
+ lines.push("");
3741
+ lines.push(paint(STYLE.dim, `Data as of ${formatReleaseAt(data.generatedAt)} — ${resolveBenchBase()}`));
3742
+ output(ctx, lines.join(`
3743
+ `), undefined);
3744
+ }
3745
+ function formatDetail(entry) {
3746
+ const score = `${entry.averageScore.toFixed(1)}/${entry.averageMaxScore.toFixed(0)}`;
3747
+ const runs = `${entry.attemptCount} run${entry.attemptCount === 1 ? "" : "s"}`;
3748
+ const cost = entry.averageCost === null || entry.averageCost === undefined ? "" : `, ~$${entry.averageCost.toFixed(2)}/run`;
3749
+ return `(${score}, ${runs}${cost})`;
3750
+ }
3751
+ function formatRow(entry, rank, name, detail, rankWidth, nameWidth, detailWidth) {
3752
+ const style = scoreStyle(entry.averagePercentage);
3753
+ const rankCell = String(rank).padStart(rankWidth);
3754
+ const nameCell = name.padEnd(nameWidth);
3755
+ const pctCell = `${entry.averagePercentage.toFixed(1)}%`.padStart(6);
3756
+ return [
3757
+ ` ${paint(rank <= 3 ? STYLE.bold : STYLE.dim, rankCell)}`,
3758
+ rank <= 3 ? paint(STYLE.bold, nameCell) : nameCell,
3759
+ paint(style, scoreBar(entry.averagePercentage)),
3760
+ paint(style, pctCell),
3761
+ detail.padEnd(detailWidth),
3762
+ paint(STYLE.dim, sanitize(entry.agentEnvironment))
3763
+ ].join(" ");
3764
+ }
3765
+
3524
3766
  // src/commands/doctor.ts
3525
3767
  import { existsSync as existsSync2, accessSync, constants } from "node:fs";
3526
3768
  import { join as join2 } from "node:path";
@@ -3732,28 +3974,6 @@ function apiBaseUrl() {
3732
3974
  return resolveApiBase();
3733
3975
  }
3734
3976
 
3735
- // src/lib/format.ts
3736
- function formatReleaseAt(iso, now = new Date) {
3737
- const date = new Date(iso);
3738
- if (!Number.isFinite(date.getTime()))
3739
- return iso;
3740
- const absolute = date.toLocaleDateString("en-US", {
3741
- year: "numeric",
3742
- month: "long",
3743
- day: "numeric",
3744
- timeZone: "UTC"
3745
- });
3746
- const msPerDay = 24 * 60 * 60 * 1000;
3747
- const startOfTarget = Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate());
3748
- const startOfNow = Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate());
3749
- const days = Math.round((startOfTarget - startOfNow) / msPerDay);
3750
- if (days <= 0)
3751
- return absolute;
3752
- if (days === 1)
3753
- return `${absolute} (tomorrow)`;
3754
- return `${absolute} (in ${days} days)`;
3755
- }
3756
-
3757
3977
  // src/lib/tool-profile.ts
3758
3978
  var SENTINEL_BEGIN = "<!-- BEGIN @przeprogramowani/10x-cli -->";
3759
3979
  var SENTINEL_END = "<!-- END @przeprogramowani/10x-cli -->";
@@ -4204,7 +4424,7 @@ function parseLessonRef(raw) {
4204
4424
  return null;
4205
4425
  if (module < MIN_MODULE || module > MAX_MODULE)
4206
4426
  return null;
4207
- if (lesson < 1)
4427
+ if (lesson < 0)
4208
4428
  return null;
4209
4429
  return { lessonId: `m${module}l${lesson}`, module, lesson };
4210
4430
  }
@@ -6297,6 +6517,7 @@ registerGetCommand(cli);
6297
6517
  registerListCommand(cli);
6298
6518
  registerSyncCommand(cli);
6299
6519
  registerDoctorCommand(cli);
6520
+ registerBenchCommand(cli);
6300
6521
  cli.help();
6301
6522
  cli.version(package_default.version);
6302
6523
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@przeprogramowani/10x-cli",
3
- "version": "1.9.0",
3
+ "version": "1.11.0",
4
4
  "description": "Open-source CLI for 10xDevs course content",
5
5
  "repository": {
6
6
  "type": "git",