ccclub 0.2.67 → 0.2.68
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/dist/index.js +63 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -391,6 +391,48 @@ function formatFetchError(err) {
|
|
|
391
391
|
return causes.length > 1 ? causes[causes.length - 1] : detail;
|
|
392
392
|
}
|
|
393
393
|
|
|
394
|
+
// src/usage-limits.ts
|
|
395
|
+
import { execSync as execSync2 } from "child_process";
|
|
396
|
+
import { userInfo as userInfo2 } from "os";
|
|
397
|
+
function parseUtilization(value) {
|
|
398
|
+
if (typeof value === "number") return Math.round(value * 100) / 100;
|
|
399
|
+
if (typeof value === "string") {
|
|
400
|
+
const n = parseFloat(value.replace("%", ""));
|
|
401
|
+
return isNaN(n) ? 0 : Math.round(n * 100) / 100;
|
|
402
|
+
}
|
|
403
|
+
return 0;
|
|
404
|
+
}
|
|
405
|
+
async function fetchUsageLimits() {
|
|
406
|
+
try {
|
|
407
|
+
const username = userInfo2().username;
|
|
408
|
+
const raw = execSync2(
|
|
409
|
+
`security find-generic-password -s "Claude Code-credentials" -a "${username}" -w`,
|
|
410
|
+
{ encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], timeout: 5e3 }
|
|
411
|
+
).trim();
|
|
412
|
+
const credentials = JSON.parse(raw);
|
|
413
|
+
const accessToken = credentials?.claudeAiOauth?.accessToken;
|
|
414
|
+
if (!accessToken || typeof accessToken !== "string") return null;
|
|
415
|
+
const res = await fetch("https://api.anthropic.com/api/oauth/usage", {
|
|
416
|
+
headers: {
|
|
417
|
+
Authorization: `Bearer ${accessToken}`,
|
|
418
|
+
"anthropic-beta": "oauth-2025-04-20"
|
|
419
|
+
},
|
|
420
|
+
signal: AbortSignal.timeout(8e3)
|
|
421
|
+
});
|
|
422
|
+
if (!res.ok) return null;
|
|
423
|
+
const data = await res.json();
|
|
424
|
+
const fiveHourRaw = data.five_hour?.utilization;
|
|
425
|
+
const sevenDayRaw = data.seven_day?.utilization;
|
|
426
|
+
return {
|
|
427
|
+
fiveHour: parseUtilization(fiveHourRaw),
|
|
428
|
+
sevenDay: parseUtilization(sevenDayRaw),
|
|
429
|
+
snapshotAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
430
|
+
};
|
|
431
|
+
} catch {
|
|
432
|
+
return null;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
394
436
|
// src/commands/sync.ts
|
|
395
437
|
var SYNC_FORMAT_VERSION = "6";
|
|
396
438
|
function getSyncVersionPath() {
|
|
@@ -443,7 +485,10 @@ async function doSync(firstSync = false, silent = false) {
|
|
|
443
485
|
} : console.log;
|
|
444
486
|
const spinner = silent ? null : ora("Collecting usage data...").start();
|
|
445
487
|
try {
|
|
446
|
-
const { entries, humanTurns } = await
|
|
488
|
+
const [{ entries, humanTurns }, usageSnapshot] = await Promise.all([
|
|
489
|
+
collectUsageEntries(),
|
|
490
|
+
fetchUsageLimits().catch(() => null)
|
|
491
|
+
]);
|
|
447
492
|
if (spinner) spinner.text = `Found ${entries.length} entries`;
|
|
448
493
|
if (entries.length === 0) {
|
|
449
494
|
if (spinner) spinner.warn("No usage data found in ~/.claude/projects/");
|
|
@@ -468,13 +513,15 @@ async function doSync(firstSync = false, silent = false) {
|
|
|
468
513
|
return;
|
|
469
514
|
}
|
|
470
515
|
if (spinner) spinner.text = `Uploading ${blocksToSync.length} blocks...`;
|
|
516
|
+
const syncBody = { blocks: blocksToSync };
|
|
517
|
+
if (usageSnapshot) syncBody.usageSnapshot = usageSnapshot;
|
|
471
518
|
const res = await fetch(`${config.apiUrl}/api/sync`, {
|
|
472
519
|
method: "POST",
|
|
473
520
|
headers: {
|
|
474
521
|
"Content-Type": "application/json",
|
|
475
522
|
Authorization: `Bearer ${config.token}`
|
|
476
523
|
},
|
|
477
|
-
body: JSON.stringify(
|
|
524
|
+
body: JSON.stringify(syncBody),
|
|
478
525
|
signal: AbortSignal.timeout(6e4)
|
|
479
526
|
});
|
|
480
527
|
if (!res.ok) {
|
|
@@ -852,8 +899,13 @@ function printGroup(data, code, period, config, showCache = false) {
|
|
|
852
899
|
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
|
|
853
900
|
`));
|
|
854
901
|
const hasPlan = data.rankings.some((r) => r.plan);
|
|
902
|
+
const hasUsage = data.rankings.some((r) => r.usageSnapshot);
|
|
855
903
|
const head = ["#", "Name", "Cost", "Tokens"];
|
|
856
904
|
const widths = [5, 20, 12, 10];
|
|
905
|
+
if (hasUsage) {
|
|
906
|
+
head.push("Usage (5h/7d)");
|
|
907
|
+
widths.push(14);
|
|
908
|
+
}
|
|
857
909
|
if (hasPlan) {
|
|
858
910
|
head.push("Monthly ROI");
|
|
859
911
|
widths.push(15);
|
|
@@ -878,6 +930,14 @@ function printGroup(data, code, period, config, showCache = false) {
|
|
|
878
930
|
c(`$${entry.costUSD.toFixed(2)}`),
|
|
879
931
|
c(formatTokens(tokens))
|
|
880
932
|
];
|
|
933
|
+
if (hasUsage) {
|
|
934
|
+
if (entry.usageSnapshot) {
|
|
935
|
+
const { fiveHour, sevenDay } = entry.usageSnapshot;
|
|
936
|
+
row.push(c(`${Math.round(fiveHour)}%/${Math.round(sevenDay)}%`));
|
|
937
|
+
} else {
|
|
938
|
+
row.push(chalk6.dim("\u2014"));
|
|
939
|
+
}
|
|
940
|
+
}
|
|
881
941
|
if (hasPlan) {
|
|
882
942
|
if (entry.plan && entry.plan !== "api") {
|
|
883
943
|
const price = PLAN_PRICES[entry.plan];
|
|
@@ -1243,7 +1303,7 @@ async function hookCommand() {
|
|
|
1243
1303
|
}
|
|
1244
1304
|
|
|
1245
1305
|
// src/index.ts
|
|
1246
|
-
var VERSION = "0.2.
|
|
1306
|
+
var VERSION = "0.2.68";
|
|
1247
1307
|
startUpdateCheck(VERSION);
|
|
1248
1308
|
var program = new Command();
|
|
1249
1309
|
program.name("ccclub").description("Claude Code leaderboard among friends").version(VERSION, "-v, -V, --version");
|