ccclub 0.3.14 → 0.3.16

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 +44 -8
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1709,8 +1709,10 @@ async function getUpdateResult() {
1709
1709
 
1710
1710
  // src/commands/rank.ts
1711
1711
  var ACTIVE_THRESHOLD_MS = 15 * 60 * 1e3;
1712
+ var AGENT_ORDER = ["claude", "codex", "opencode", "amp", "pi"];
1712
1713
  async function rankCommand(options) {
1713
1714
  const config = await requireConfig();
1715
+ const includeCache = options.cache !== false;
1714
1716
  if (!isHookInstalled()) await installHook();
1715
1717
  if (!isHeartbeatInstalled()) await installHeartbeat();
1716
1718
  if (needsFullSync()) {
@@ -1805,11 +1807,15 @@ async function rankCommand(options) {
1805
1807
  const me = rankData.rankings.find((r) => r.userId === config.userId);
1806
1808
  if (me) me.usageSnapshot = localSnapshot;
1807
1809
  }
1808
- printGroup(rankData, code, period, config, options.cache, options.all);
1810
+ printGroup(rankData, code, period, config, includeCache, options.all);
1809
1811
  if (activityData) renderActivity(activityData, range);
1810
1812
  if (i < groupResults.length - 1) console.log("");
1811
1813
  }
1812
- console.log(theme.muted("\n Tokens = input + output + reasoning ") + theme.warning("(cache excluded)") + theme.muted(". Use ") + theme.text("--cache") + theme.muted(" to include cache tokens."));
1814
+ if (includeCache) {
1815
+ console.log(theme.muted("\n Tokens include cache by default. Use ") + theme.text("--no-cache") + theme.muted(" to show input + output + reasoning only."));
1816
+ } else {
1817
+ console.log(theme.muted("\n Tokens = input + output + reasoning ") + theme.warning("(cache excluded)") + theme.muted(". Cost still includes cache."));
1818
+ }
1813
1819
  const update = await getUpdateResult();
1814
1820
  if (update) {
1815
1821
  console.log(theme.warningBold("\n Update available") + theme.muted(`: ${update.current} \u2192 ${update.latest} Run `) + theme.linkText("npm i -g ccclub@latest"));
@@ -1833,7 +1839,7 @@ function formatTokens(n) {
1833
1839
  }
1834
1840
  return String(n);
1835
1841
  }
1836
- function printGroup(data, code, period, config, showCache = false, showAll = false) {
1842
+ function printGroup(data, code, period, config, showCache = true, showAll = false) {
1837
1843
  if (data.rankings.length === 0) {
1838
1844
  console.log(theme.title(`
1839
1845
  ${data.group.name}`));
@@ -1845,10 +1851,12 @@ function printGroup(data, code, period, config, showCache = false, showAll = fal
1845
1851
  ${data.group.name}`));
1846
1852
  const periodLabel = { daily: "TODAY", yesterday: "YESTERDAY", weekly: "7 DAYS", monthly: "30 DAYS", "all-time": "ALL TIME" };
1847
1853
  const now = Date.now();
1848
- const activeCount = data.rankings.filter((r) => isEntryActive(r, now)).length;
1854
+ const activeEntries = data.rankings.filter((r) => isEntryActive(r, now));
1855
+ const activeCount = activeEntries.length;
1849
1856
  console.log(theme.muted(` ${periodLabel[period] || period.toUpperCase()} \xB7 ${data.start.slice(0, 10)} \u2192 ${data.end.slice(0, 10)} \xB7 ${data.group.memberCount} members`));
1850
1857
  if (activeCount > 0) {
1851
- console.log(theme.success(` ${activeCount} active`));
1858
+ const activeSplit = formatActiveSourceSplit(activeEntries);
1859
+ console.log(theme.success(` ${activeCount} active`) + (activeSplit ? ` ${activeSplit}` : ""));
1852
1860
  }
1853
1861
  console.log("");
1854
1862
  const activeRankings = showAll || data.rankings.length <= 15 ? data.rankings : data.rankings.filter((r) => r.costUSD > 0 || r.userId === config.userId);
@@ -1945,6 +1953,34 @@ function isEntryActive(entry, now) {
1945
1953
  const activeAt = new Date(value).getTime();
1946
1954
  return Number.isFinite(activeAt) && now - activeAt < ACTIVE_THRESHOLD_MS;
1947
1955
  }
1956
+ function activeSourceForEntry(entry) {
1957
+ return entry.lastActiveSource ?? entry.agents?.[0];
1958
+ }
1959
+ function formatActiveSourceSplit(entries) {
1960
+ const counts = /* @__PURE__ */ new Map();
1961
+ for (const entry of entries) {
1962
+ const source = activeSourceForEntry(entry);
1963
+ if (!source) continue;
1964
+ counts.set(source, (counts.get(source) ?? 0) + 1);
1965
+ }
1966
+ const sources = AGENT_ORDER.filter((source) => (counts.get(source) ?? 0) > 0);
1967
+ if (sources.length === 0) return "";
1968
+ if (sources.length === 2 && sources.includes("claude") && sources.includes("codex")) {
1969
+ return [
1970
+ theme.muted("Claude"),
1971
+ theme.successBold(String(counts.get("claude") ?? 0)) + theme.faint(":"),
1972
+ theme.successBold(String(counts.get("codex") ?? 0)),
1973
+ theme.muted("Codex")
1974
+ ].join(" ");
1975
+ }
1976
+ return sources.map((source) => formatActiveSourceScore(source, counts.get(source) ?? 0, false)).join(theme.faint(" \xB7 "));
1977
+ }
1978
+ function formatActiveSourceScore(source, count, countFirst) {
1979
+ const icon = source === "claude" ? theme.gold("\u25CF") : source === "codex" ? theme.linkText("\u25CF") : theme.success("\u25CF");
1980
+ const label = source === "claude" ? "Claude" : formatAgentLabel(source);
1981
+ const coloredCount = theme.successBold(String(count));
1982
+ return countFirst ? `${coloredCount} ${icon} ${theme.muted(label)}` : `${icon} ${theme.muted(label)} ${coloredCount}`;
1983
+ }
1948
1984
  function podiumStyle(rank) {
1949
1985
  if (rank === 1) return theme.gold;
1950
1986
  if (rank === 2) return theme.silver;
@@ -2357,7 +2393,7 @@ async function hookCommand() {
2357
2393
  }
2358
2394
 
2359
2395
  // src/index.ts
2360
- var VERSION = "0.3.14";
2396
+ var VERSION = "0.3.16";
2361
2397
  startUpdateCheck(VERSION);
2362
2398
  var program = new Command();
2363
2399
  if (process.argv.slice(2).includes("-v")) {
@@ -2365,7 +2401,7 @@ if (process.argv.slice(2).includes("-v")) {
2365
2401
  process.exit(0);
2366
2402
  }
2367
2403
  program.name("ccclub").description("Claude Code, Codex, OpenCode, Amp, and pi-agent usage leaderboard among friends").version(VERSION);
2368
- program.command("rank", { isDefault: true, hidden: true }).description("Show leaderboard").option("-d, --days [days]", "Time window: 1 | 7 | 30 | all (default: today)").addOption(new Option("-p, --period [period]").hideHelp()).option("-g, --group <code>", "Group invite code").option("--global", "Show global public ranking").option("--cache", "Include cache tokens in count").option("--all", "Show all members including those with no activity").action(rankCommand);
2404
+ program.command("rank", { isDefault: true, hidden: true }).description("Show leaderboard").option("-d, --days [days]", "Time window: 1 | 7 | 30 | all (default: today)").addOption(new Option("-p, --period [period]").hideHelp()).option("-g, --group <code>", "Group invite code").option("--global", "Show global public ranking").addOption(new Option("--cache", "Include cache tokens in count (default)").hideHelp()).option("--no-cache", "Exclude cache tokens from token counts").option("--all", "Show all members including those with no activity").action(rankCommand);
2369
2405
  program.command("init").description("Create a group and get started (first-time setup)").action(initCommand);
2370
2406
  program.command("join").description("Join a group with a 6-letter invite code").argument("[invite-code]", "6-character invite code").action((code) => {
2371
2407
  if (!code) {
@@ -2402,7 +2438,7 @@ Leaderboard options:
2402
2438
  -d <period> Time window: 1 | 7 | 30 | all (default: today)
2403
2439
  -g <code> Show a specific group
2404
2440
  --global Global public leaderboard
2405
- --cache Include cache tokens in total
2441
+ --no-cache Exclude cache tokens from token totals
2406
2442
  --all Show all members including inactive ones
2407
2443
 
2408
2444
  Examples:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccclub",
3
- "version": "0.3.14",
3
+ "version": "0.3.16",
4
4
  "type": "module",
5
5
  "description": "Claude Code and Codex leaderboard among friends for coding agent tokens and costs",
6
6
  "bin": {