ccgather 2.0.9 → 2.0.11

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 +99 -27
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -329,7 +329,7 @@ var init_ui = __esm({
329
329
  "use strict";
330
330
  import_chalk = __toESM(require("chalk"));
331
331
  import_string_width = __toESM(require("string-width"));
332
- VERSION = true ? "2.0.9" : "0.0.0";
332
+ VERSION = true ? "2.0.11" : "0.0.0";
333
333
  colors = {
334
334
  primary: import_chalk.default.hex("#DA7756"),
335
335
  // Claude coral
@@ -1291,12 +1291,17 @@ async function submit(options) {
1291
1291
  ${colors.muted("Scanning all Claude Code sessions...")}`);
1292
1292
  const totalSessions = getAllSessionsCount();
1293
1293
  console.log(` ${colors.dim(`Found ${totalSessions} session file(s)`)}`);
1294
+ let lastProgress = 0;
1294
1295
  const scannedData = scanAllProjects({
1295
1296
  onProgress: (current, total) => {
1296
1297
  progressBar(current, total, "Scanning");
1298
+ lastProgress = current;
1297
1299
  }
1298
1300
  });
1299
- await sleep(200);
1301
+ if (lastProgress > 0) {
1302
+ process.stdout.write("\r" + " ".repeat(60) + "\r");
1303
+ }
1304
+ console.log(` ${success("Scan complete!")}`);
1300
1305
  if (!scannedData) {
1301
1306
  console.log(`
1302
1307
  ${error("No usage data found.")}`);
@@ -1305,7 +1310,6 @@ async function submit(options) {
1305
1310
  process.exit(1);
1306
1311
  }
1307
1312
  const usageData = ccgatherToUsageData(scannedData);
1308
- console.log(` ${success("Scan complete!")}`);
1309
1313
  console.log();
1310
1314
  const formatDate = (dateStr) => {
1311
1315
  if (!dateStr) return "------";
@@ -1342,20 +1346,7 @@ async function submit(options) {
1342
1346
  console.log(
1343
1347
  ` ${colors.dim(`Scanned ${projectCount} project(s), ${usageData.dailyUsage.length} day(s) of data`)}`
1344
1348
  );
1345
- const { confirmSubmit } = await import_inquirer2.default.prompt([
1346
- {
1347
- type: "confirm",
1348
- name: "confirmSubmit",
1349
- message: "Submit to CCgather leaderboard?",
1350
- default: true
1351
- }
1352
- ]);
1353
- if (!confirmSubmit) {
1354
- console.log(`
1355
- ${colors.muted("Submission cancelled.")}
1356
- `);
1357
- return;
1358
- }
1349
+ console.log();
1359
1350
  const submitSpinner = (0, import_ora2.default)({
1360
1351
  text: "Submitting to CCgather...",
1361
1352
  color: "cyan"
@@ -1371,8 +1362,40 @@ async function submit(options) {
1371
1362
  };
1372
1363
  if (result.previous) {
1373
1364
  const prev = result.previous;
1374
- const tokenDiff = usageData.totalTokens - prev.totalTokens;
1375
- const costDiff = usageData.totalCost - prev.totalCost;
1365
+ const previousDates = new Set(prev.previousDates || []);
1366
+ const previousDailyMap = /* @__PURE__ */ new Map();
1367
+ prev.previousDaily?.forEach((d) => {
1368
+ previousDailyMap.set(d.date, { tokens: d.tokens, cost: d.cost });
1369
+ });
1370
+ const currentDates = new Set(usageData.dailyUsage.map((d) => d.date));
1371
+ const newDates = usageData.dailyUsage.filter((d) => !previousDates.has(d.date));
1372
+ const expiredDates = Array.from(previousDates).filter((d) => !currentDates.has(d));
1373
+ const updatedDates = usageData.dailyUsage.filter((d) => {
1374
+ const prevData = previousDailyMap.get(d.date);
1375
+ return prevData && d.tokens > prevData.tokens;
1376
+ });
1377
+ let newTokens = 0;
1378
+ let newCost = 0;
1379
+ newDates.forEach((d) => {
1380
+ newTokens += d.tokens;
1381
+ newCost += d.cost;
1382
+ });
1383
+ updatedDates.forEach((d) => {
1384
+ const prevData = previousDailyMap.get(d.date);
1385
+ if (prevData) {
1386
+ newTokens += d.tokens - prevData.tokens;
1387
+ newCost += d.cost - prevData.cost;
1388
+ }
1389
+ });
1390
+ let expiredTokens = 0;
1391
+ let expiredCost = 0;
1392
+ expiredDates.forEach((date) => {
1393
+ const prevData = previousDailyMap.get(date);
1394
+ if (prevData) {
1395
+ expiredTokens += prevData.tokens;
1396
+ expiredCost += prevData.cost;
1397
+ }
1398
+ });
1376
1399
  const lastSubmit = new Date(prev.lastSubmissionAt);
1377
1400
  const now = /* @__PURE__ */ new Date();
1378
1401
  const hoursDiff = Math.floor((now.getTime() - lastSubmit.getTime()) / (1e3 * 60 * 60));
@@ -1381,20 +1404,69 @@ async function submit(options) {
1381
1404
  console.log(sectionHeader("\u{1F4C8}", "Since Last Submit"));
1382
1405
  console.log();
1383
1406
  console.log(` ${colors.muted("Last submitted:")} ${colors.dim(timeSince)}`);
1384
- if (tokenDiff > 0) {
1385
- console.log(
1386
- ` ${colors.muted("New tokens:")} ${colors.success(`+${formatNumber(tokenDiff)}`)}`
1387
- );
1407
+ console.log();
1408
+ if (newTokens > 0 || updatedDates.length > 0) {
1409
+ const parts = [];
1410
+ if (newTokens > 0) {
1411
+ parts.push(colors.success(`+${formatNumber(newTokens)}`));
1412
+ parts.push(colors.success(`+${formatCost(newCost)}`));
1413
+ }
1414
+ if (newDates.length > 0) {
1415
+ parts.push(
1416
+ colors.primary(`+${newDates.length} new day${newDates.length > 1 ? "s" : ""}`)
1417
+ );
1418
+ }
1419
+ if (updatedDates.length > 0 && newDates.length === 0) {
1420
+ parts.push(
1421
+ colors.primary(
1422
+ `${updatedDates.length} day${updatedDates.length > 1 ? "s" : ""} updated`
1423
+ )
1424
+ );
1425
+ }
1426
+ console.log(` ${parts.join(" ")}`);
1388
1427
  }
1389
- if (costDiff > 0) {
1428
+ if (expiredDates.length > 0) {
1429
+ console.log();
1390
1430
  console.log(
1391
- ` ${colors.muted("New spending:")} ${colors.success(`+${formatCost(costDiff)}`)}`
1431
+ ` ${colors.warning("\u26A0")} ${colors.dim(`${expiredDates.length} day${expiredDates.length > 1 ? "s" : ""} expired (30-day limit): -${formatNumber(expiredTokens)}`)}`
1392
1432
  );
1393
1433
  }
1394
- if (tokenDiff === 0 && costDiff === 0) {
1395
- console.log(` ${colors.dim("No new usage since last submission")}`);
1434
+ if (newDates.length > 0) {
1435
+ console.log();
1436
+ const displayDates = newDates.slice(-5);
1437
+ if (newDates.length > 5) {
1438
+ console.log(` ${colors.dim(`... and ${newDates.length - 5} more days`)}`);
1439
+ }
1440
+ displayDates.forEach((d) => {
1441
+ const dateStr = d.date.slice(5).replace("-", "/");
1442
+ console.log(
1443
+ ` ${colors.dim("\u2022")} ${colors.white(dateStr)}: ${colors.success(`+${formatNumber(d.tokens)}`)} ${colors.dim(`(${formatCost(d.cost)})`)}`
1444
+ );
1445
+ });
1446
+ }
1447
+ if (updatedDates.length > 0 && newDates.length === 0) {
1448
+ console.log();
1449
+ updatedDates.slice(-3).forEach((d) => {
1450
+ const prevData = previousDailyMap.get(d.date);
1451
+ if (prevData) {
1452
+ const dateStr = d.date.slice(5).replace("-", "/");
1453
+ const tokenIncrease = d.tokens - prevData.tokens;
1454
+ console.log(
1455
+ ` ${colors.dim("\u2022")} ${colors.white(dateStr)}: ${formatNumber(prevData.tokens)} \u2192 ${formatNumber(d.tokens)} ${colors.success(`(+${formatNumber(tokenIncrease)})`)}`
1456
+ );
1457
+ }
1458
+ });
1459
+ }
1460
+ if (newTokens === 0 && updatedDates.length === 0 && expiredDates.length === 0) {
1461
+ console.log(` ${colors.dim("No changes since last submission")}`);
1396
1462
  }
1397
1463
  console.log();
1464
+ const rankSpinner = (0, import_ora2.default)({
1465
+ text: colors.dim("Calculating ranking..."),
1466
+ color: "cyan"
1467
+ }).start();
1468
+ await sleep(400);
1469
+ rankSpinner.stop();
1398
1470
  }
1399
1471
  if (result.rank || result.countryRank) {
1400
1472
  console.log();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccgather",
3
- "version": "2.0.9",
3
+ "version": "2.0.11",
4
4
  "description": "CLI tool for syncing Claude Code usage data to CCgather leaderboard",
5
5
  "bin": {
6
6
  "ccgather": "dist/index.js",