ccclub 0.2.80 → 0.2.82

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.js +42 -36
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -452,45 +452,42 @@ async function fetchUsageLimits() {
452
452
  debug("returning null: token expired at", expiresAt);
453
453
  return null;
454
454
  }
455
- const curlCmd = `curl -sf --max-time 8 "https://api.anthropic.com/api/oauth/usage" -H "Authorization: Bearer ${accessToken}" -H "anthropic-beta: oauth-2025-04-20" -H "User-Agent: claude-code/2.1.5"`;
455
+ const curlCmd = `curl -s --max-time 8 "https://api.anthropic.com/api/oauth/usage" -H "Authorization: Bearer ${accessToken}" -H "anthropic-beta: oauth-2025-04-20" -H "User-Agent: claude-code/2.1.5"`;
456
456
  debug("running curl...");
457
457
  const { stdout: stdout5 } = await execAsync(curlCmd, { timeout: 9e3 });
458
458
  debug("curl stdout length:", stdout5.length, "first 100:", stdout5.slice(0, 100));
459
- if (!stdout5) {
460
- debug("returning null: empty stdout");
461
- return null;
462
- }
463
- const data = JSON.parse(stdout5);
464
- if (data.error) {
465
- debug("returning null: data.error =", data.error);
466
- return null;
467
- }
468
- const fiveHourRaw = data.five_hour?.utilization;
469
- const sevenDayRaw = data.seven_day?.utilization;
470
- const result = {
471
- fiveHour: parseUtilization(fiveHourRaw),
472
- sevenDay: parseUtilization(sevenDayRaw),
473
- snapshotAt: (/* @__PURE__ */ new Date()).toISOString()
474
- };
475
- debug("returning snapshot:", result.fiveHour, result.sevenDay);
476
- writeCache(result);
477
- return result;
478
- } catch (err) {
479
- debug("caught error:", err instanceof Error ? err.message : String(err));
480
- try {
481
- const tmp = JSON.parse(readFileSync2("/tmp/sl-claude-usage", "utf-8"));
482
- if (typeof tmp.fiveHour === "number" && typeof tmp.sevenDay === "number") {
483
- const result = { fiveHour: tmp.fiveHour, sevenDay: tmp.sevenDay, snapshotAt: (/* @__PURE__ */ new Date()).toISOString() };
484
- debug("returning cc-costline cache fallback:", result.fiveHour, result.sevenDay);
459
+ if (stdout5) {
460
+ const data = JSON.parse(stdout5);
461
+ if (!data.error) {
462
+ const fiveHourRaw = data.five_hour?.utilization;
463
+ const sevenDayRaw = data.seven_day?.utilization;
464
+ const result = {
465
+ fiveHour: parseUtilization(fiveHourRaw),
466
+ sevenDay: parseUtilization(sevenDayRaw),
467
+ snapshotAt: (/* @__PURE__ */ new Date()).toISOString()
468
+ };
469
+ debug("returning snapshot:", result.fiveHour, result.sevenDay);
485
470
  writeCache(result);
486
471
  return result;
487
472
  }
488
- } catch {
473
+ debug("API error response:", data.error);
489
474
  }
490
- const stale = readCache(true);
491
- if (stale) debug("returning stale cache as fallback:", stale.fiveHour, stale.sevenDay);
492
- return stale;
475
+ } catch (err) {
476
+ debug("caught error:", err instanceof Error ? err.message : String(err));
477
+ }
478
+ try {
479
+ const tmp = JSON.parse(readFileSync2("/tmp/sl-claude-usage", "utf-8"));
480
+ if (typeof tmp.fiveHour === "number" && typeof tmp.sevenDay === "number") {
481
+ const result = { fiveHour: tmp.fiveHour, sevenDay: tmp.sevenDay, snapshotAt: (/* @__PURE__ */ new Date()).toISOString() };
482
+ debug("returning cc-costline cache fallback:", result.fiveHour, result.sevenDay);
483
+ writeCache(result);
484
+ return result;
485
+ }
486
+ } catch {
493
487
  }
488
+ const stale = readCache(true);
489
+ if (stale) debug("returning stale cache as fallback:", stale.fiveHour, stale.sevenDay);
490
+ return stale;
494
491
  }
495
492
 
496
493
  // src/commands/sync.ts
@@ -858,6 +855,7 @@ async function getUpdateResult() {
858
855
  }
859
856
 
860
857
  // src/commands/rank.ts
858
+ var ACTIVE_THRESHOLD_MS = 15 * 60 * 1e3;
861
859
  async function rankCommand(options) {
862
860
  const config = await requireConfig();
863
861
  if (!isHookInstalled()) await installHook();
@@ -992,14 +990,20 @@ function printGroup(data, code, period, config, showCache = false, showAll = fal
992
990
  console.log(chalk6.bold(`
993
991
  ${data.group.name}`));
994
992
  const periodLabel = { daily: "TODAY", yesterday: "YESTERDAY", weekly: "7 DAYS", monthly: "30 DAYS", "all-time": "ALL TIME" };
995
- console.log(chalk6.dim(` ${periodLabel[period] || period.toUpperCase()} \xB7 ${data.start.slice(0, 10)} \u2192 ${data.end.slice(0, 10)} \xB7 ${data.group.memberCount} members
996
- `));
993
+ const now = Date.now();
994
+ const activeCount = data.rankings.filter((r) => r.lastSync && now - new Date(r.lastSync).getTime() < ACTIVE_THRESHOLD_MS).length;
995
+ console.log(chalk6.dim(` ${periodLabel[period] || period.toUpperCase()} \xB7 ${data.start.slice(0, 10)} \u2192 ${data.end.slice(0, 10)} \xB7 ${data.group.memberCount} members`));
996
+ if (activeCount > 0) {
997
+ console.log(chalk6.green(` ${activeCount} active`));
998
+ }
999
+ console.log("");
997
1000
  const activeRankings = showAll || data.rankings.length <= 15 ? data.rankings : data.rankings.filter((r) => r.costUSD > 0 || r.userId === config.userId);
998
1001
  const hiddenCount = data.rankings.length - activeRankings.length;
999
1002
  const hasPlan = activeRankings.some((r) => r.plan);
1000
1003
  const hasUsage = activeRankings.some((r) => r.usageSnapshot);
1001
1004
  const head = ["#", "Name", "Cost", "Tokens"];
1002
- const widths = [5, 20, 12, 10];
1005
+ const hasActive = activeRankings.some((r) => r.lastSync && now - new Date(r.lastSync).getTime() < ACTIVE_THRESHOLD_MS);
1006
+ const widths = [5, hasActive ? 30 : 20, 12, 10];
1003
1007
  if (hasPlan) {
1004
1008
  head.push("Monthly ROI");
1005
1009
  widths.push(15);
@@ -1019,12 +1023,14 @@ function printGroup(data, code, period, config, showCache = false, showAll = fal
1019
1023
  const isMe = entry.userId === config.userId;
1020
1024
  const tokens = showCache ? entry.totalTokens : entry.inputTokens + entry.outputTokens;
1021
1025
  const marker = isMe ? chalk6.green("\u2192") : " ";
1026
+ const isActive = entry.lastSync && now - new Date(entry.lastSync).getTime() < ACTIVE_THRESHOLD_MS;
1022
1027
  const id = (s) => s;
1023
1028
  const c = isMe ? chalk6.green : entry.rank === 1 ? chalk6.yellow : id;
1024
1029
  const nameC = isMe ? chalk6.green.bold : entry.rank === 1 ? chalk6.yellow.bold : id;
1030
+ const displayName = isActive ? `${entry.displayName} ${chalk6.green("(active)")}` : entry.displayName;
1025
1031
  const row = [
1026
1032
  `${marker}${c(String(entry.rank))}`,
1027
- nameC(entry.displayName),
1033
+ nameC(displayName),
1028
1034
  c(`$${entry.costUSD.toFixed(2)}`),
1029
1035
  c(formatTokens(tokens))
1030
1036
  ];
@@ -1397,7 +1403,7 @@ async function hookCommand() {
1397
1403
  }
1398
1404
 
1399
1405
  // src/index.ts
1400
- var VERSION = "0.2.80";
1406
+ var VERSION = "0.2.82";
1401
1407
  startUpdateCheck(VERSION);
1402
1408
  var program = new Command();
1403
1409
  program.name("ccclub").description("Claude Code leaderboard among friends").version(VERSION, "-v, -V, --version");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccclub",
3
- "version": "0.2.80",
3
+ "version": "0.2.82",
4
4
  "type": "module",
5
5
  "description": "Claude Code leaderboard among friends",
6
6
  "bin": {