ccclub 0.2.77 → 0.2.79
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 -18
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -206,9 +206,9 @@ function isHookInstalled() {
|
|
|
206
206
|
|
|
207
207
|
// src/commands/sync.ts
|
|
208
208
|
import { readFile as readFile4, writeFile as writeFile3 } from "fs/promises";
|
|
209
|
-
import { existsSync as existsSync3, readFileSync as
|
|
210
|
-
import { join as
|
|
211
|
-
import { homedir as
|
|
209
|
+
import { existsSync as existsSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
|
|
210
|
+
import { join as join5 } from "path";
|
|
211
|
+
import { homedir as homedir5 } from "os";
|
|
212
212
|
import chalk2 from "chalk";
|
|
213
213
|
import ora from "ora";
|
|
214
214
|
|
|
@@ -394,11 +394,30 @@ function formatFetchError(err) {
|
|
|
394
394
|
// src/usage-limits.ts
|
|
395
395
|
import { execSync as execSync2, exec } from "child_process";
|
|
396
396
|
import { promisify } from "util";
|
|
397
|
-
import { userInfo as userInfo2 } from "os";
|
|
397
|
+
import { userInfo as userInfo2, homedir as homedir4 } from "os";
|
|
398
|
+
import { join as join4 } from "path";
|
|
399
|
+
import { readFileSync as readFileSync2, writeFileSync } from "fs";
|
|
398
400
|
var execAsync = promisify(exec);
|
|
399
401
|
var debug = (...args) => {
|
|
400
402
|
if (process.env.CCCLUB_DEBUG) console.error("[usage-debug]", ...args);
|
|
401
403
|
};
|
|
404
|
+
var CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
405
|
+
var CACHE_PATH = join4(homedir4(), CCCLUB_CONFIG_DIR, "usage-cache.json");
|
|
406
|
+
function readCache(allowStale = false) {
|
|
407
|
+
try {
|
|
408
|
+
const raw = readFileSync2(CACHE_PATH, "utf-8");
|
|
409
|
+
const { snapshot, fetchedAt } = JSON.parse(raw);
|
|
410
|
+
if (allowStale || Date.now() - fetchedAt < CACHE_TTL_MS) return snapshot;
|
|
411
|
+
} catch {
|
|
412
|
+
}
|
|
413
|
+
return null;
|
|
414
|
+
}
|
|
415
|
+
function writeCache(snapshot) {
|
|
416
|
+
try {
|
|
417
|
+
writeFileSync(CACHE_PATH, JSON.stringify({ snapshot, fetchedAt: Date.now() }));
|
|
418
|
+
} catch {
|
|
419
|
+
}
|
|
420
|
+
}
|
|
402
421
|
function parseUtilization(value) {
|
|
403
422
|
if (typeof value === "number") return Math.round(value * 100) / 100;
|
|
404
423
|
if (typeof value === "string") {
|
|
@@ -408,6 +427,11 @@ function parseUtilization(value) {
|
|
|
408
427
|
return 0;
|
|
409
428
|
}
|
|
410
429
|
async function fetchUsageLimits() {
|
|
430
|
+
const cached = readCache();
|
|
431
|
+
if (cached) {
|
|
432
|
+
debug("returning cached snapshot:", cached.fiveHour, cached.sevenDay);
|
|
433
|
+
return cached;
|
|
434
|
+
}
|
|
411
435
|
try {
|
|
412
436
|
const username = process.env.USER || process.env.USERNAME || userInfo2().username;
|
|
413
437
|
debug("username:", username);
|
|
@@ -428,7 +452,7 @@ async function fetchUsageLimits() {
|
|
|
428
452
|
debug("returning null: token expired at", expiresAt);
|
|
429
453
|
return null;
|
|
430
454
|
}
|
|
431
|
-
const curlCmd = `curl -sf --max-time 8
|
|
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"`;
|
|
432
456
|
debug("running curl...");
|
|
433
457
|
const { stdout: stdout5 } = await execAsync(curlCmd, { timeout: 9e3 });
|
|
434
458
|
debug("curl stdout length:", stdout5.length, "first 100:", stdout5.slice(0, 100));
|
|
@@ -449,23 +473,26 @@ async function fetchUsageLimits() {
|
|
|
449
473
|
snapshotAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
450
474
|
};
|
|
451
475
|
debug("returning snapshot:", result.fiveHour, result.sevenDay);
|
|
476
|
+
writeCache(result);
|
|
452
477
|
return result;
|
|
453
478
|
} catch (err) {
|
|
454
479
|
debug("caught error:", err instanceof Error ? err.message : String(err));
|
|
455
|
-
|
|
480
|
+
const stale = readCache(true);
|
|
481
|
+
if (stale) debug("returning stale cache as fallback:", stale.fiveHour, stale.sevenDay);
|
|
482
|
+
return stale;
|
|
456
483
|
}
|
|
457
484
|
}
|
|
458
485
|
|
|
459
486
|
// src/commands/sync.ts
|
|
460
487
|
var SYNC_FORMAT_VERSION = "6";
|
|
461
488
|
function getSyncVersionPath() {
|
|
462
|
-
return
|
|
489
|
+
return join5(homedir5(), CCCLUB_CONFIG_DIR, "sync-version");
|
|
463
490
|
}
|
|
464
491
|
function needsFullSync() {
|
|
465
492
|
const path = getSyncVersionPath();
|
|
466
493
|
if (!existsSync3(path)) return true;
|
|
467
494
|
try {
|
|
468
|
-
const stored =
|
|
495
|
+
const stored = readFileSync3(path, "utf-8").trim();
|
|
469
496
|
return stored !== SYNC_FORMAT_VERSION;
|
|
470
497
|
} catch {
|
|
471
498
|
return true;
|
|
@@ -477,13 +504,13 @@ async function syncCommand(options) {
|
|
|
477
504
|
if (options.silent && !options.full) {
|
|
478
505
|
if (existsSync3(timePath)) {
|
|
479
506
|
try {
|
|
480
|
-
const ts = parseInt(
|
|
507
|
+
const ts = parseInt(readFileSync3(timePath, "utf-8").trim(), 10);
|
|
481
508
|
if (Date.now() - ts < THROTTLE_MS) return;
|
|
482
509
|
} catch {
|
|
483
510
|
}
|
|
484
511
|
}
|
|
485
512
|
try {
|
|
486
|
-
|
|
513
|
+
writeFileSync2(timePath, String(Date.now()));
|
|
487
514
|
} catch {
|
|
488
515
|
}
|
|
489
516
|
}
|
|
@@ -492,7 +519,7 @@ async function syncCommand(options) {
|
|
|
492
519
|
} catch {
|
|
493
520
|
if (options.silent) {
|
|
494
521
|
try {
|
|
495
|
-
|
|
522
|
+
writeFileSync2(timePath, "0");
|
|
496
523
|
} catch {
|
|
497
524
|
}
|
|
498
525
|
}
|
|
@@ -533,6 +560,15 @@ async function doSync(firstSync = false, silent = false) {
|
|
|
533
560
|
if (blocksToSync.length === 0) {
|
|
534
561
|
if (spinner) spinner.succeed("Already up to date");
|
|
535
562
|
await writeFile3(getSyncVersionPath(), SYNC_FORMAT_VERSION);
|
|
563
|
+
if (usageSnapshot) {
|
|
564
|
+
fetch(`${config.apiUrl}/api/usage`, {
|
|
565
|
+
method: "POST",
|
|
566
|
+
headers: { "Content-Type": "application/json", Authorization: `Bearer ${config.token}` },
|
|
567
|
+
body: JSON.stringify({ usageSnapshot }),
|
|
568
|
+
signal: AbortSignal.timeout(8e3)
|
|
569
|
+
}).catch(() => {
|
|
570
|
+
});
|
|
571
|
+
}
|
|
536
572
|
return;
|
|
537
573
|
}
|
|
538
574
|
if (spinner) spinner.text = `Uploading ${blocksToSync.length} blocks...`;
|
|
@@ -771,17 +807,17 @@ import Table from "cli-table3";
|
|
|
771
807
|
import ora4 from "ora";
|
|
772
808
|
|
|
773
809
|
// src/update-check.ts
|
|
774
|
-
import { readFileSync as
|
|
775
|
-
import { join as
|
|
776
|
-
import { homedir as
|
|
810
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync4 } from "fs";
|
|
811
|
+
import { join as join6 } from "path";
|
|
812
|
+
import { homedir as homedir6 } from "os";
|
|
777
813
|
var CHECK_INTERVAL_MS = 12 * 60 * 60 * 1e3;
|
|
778
|
-
var CHECK_FILE =
|
|
814
|
+
var CHECK_FILE = join6(homedir6(), CCCLUB_CONFIG_DIR, "last-update-check");
|
|
779
815
|
var pendingCheck = null;
|
|
780
816
|
function startUpdateCheck(currentVersion) {
|
|
781
817
|
if (process.argv.includes("--silent") || process.argv.includes("-s")) return;
|
|
782
818
|
try {
|
|
783
819
|
if (existsSync4(CHECK_FILE)) {
|
|
784
|
-
const ts = parseInt(
|
|
820
|
+
const ts = parseInt(readFileSync4(CHECK_FILE, "utf-8").trim(), 10);
|
|
785
821
|
if (Date.now() - ts < CHECK_INTERVAL_MS) return;
|
|
786
822
|
}
|
|
787
823
|
} catch {
|
|
@@ -797,7 +833,7 @@ function startUpdateCheck(currentVersion) {
|
|
|
797
833
|
return { latest: data.version, current: currentVersion };
|
|
798
834
|
}
|
|
799
835
|
try {
|
|
800
|
-
|
|
836
|
+
writeFileSync3(CHECK_FILE, String(Date.now()));
|
|
801
837
|
} catch {
|
|
802
838
|
}
|
|
803
839
|
return null;
|
|
@@ -883,6 +919,15 @@ async function rankCommand(options) {
|
|
|
883
919
|
);
|
|
884
920
|
spinner.stop();
|
|
885
921
|
const localSnapshot = await localUsagePromise;
|
|
922
|
+
if (localSnapshot) {
|
|
923
|
+
fetch(`${config.apiUrl}/api/usage`, {
|
|
924
|
+
method: "POST",
|
|
925
|
+
headers: { "Content-Type": "application/json", Authorization: `Bearer ${config.token}` },
|
|
926
|
+
body: JSON.stringify({ usageSnapshot: localSnapshot }),
|
|
927
|
+
signal: AbortSignal.timeout(8e3)
|
|
928
|
+
}).catch(() => {
|
|
929
|
+
});
|
|
930
|
+
}
|
|
886
931
|
if (process.env.CCCLUB_DEBUG) {
|
|
887
932
|
console.error("[usage-debug] localSnapshot:", localSnapshot);
|
|
888
933
|
console.error("[usage-debug] config.userId:", config.userId);
|
|
@@ -1342,7 +1387,7 @@ async function hookCommand() {
|
|
|
1342
1387
|
}
|
|
1343
1388
|
|
|
1344
1389
|
// src/index.ts
|
|
1345
|
-
var VERSION = "0.2.
|
|
1390
|
+
var VERSION = "0.2.79";
|
|
1346
1391
|
startUpdateCheck(VERSION);
|
|
1347
1392
|
var program = new Command();
|
|
1348
1393
|
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.
|
|
3
|
+
"version": "0.2.79",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Claude Code leaderboard among friends",
|
|
6
6
|
"bin": {
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
],
|
|
13
13
|
"scripts": {
|
|
14
14
|
"build": "tsup src/index.ts --format esm --dts --clean",
|
|
15
|
+
"prepublishOnly": "npm run build",
|
|
15
16
|
"postinstall": "node scripts/postinstall.cjs",
|
|
16
17
|
"dev": "tsx src/index.ts",
|
|
17
18
|
"test": "vitest run"
|