ccgather 1.3.24 → 1.3.26
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 +151 -69
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -156,9 +156,11 @@ Welcome, ${import_chalk2.default.white(pollData.username)}!`));
|
|
|
156
156
|
process.exit(1);
|
|
157
157
|
} catch (error2) {
|
|
158
158
|
spinner.fail(import_chalk2.default.red("Authentication failed"));
|
|
159
|
-
console.log(
|
|
159
|
+
console.log(
|
|
160
|
+
import_chalk2.default.red(`
|
|
160
161
|
Error: ${error2 instanceof Error ? error2.message : "Unknown error"}
|
|
161
|
-
`)
|
|
162
|
+
`)
|
|
163
|
+
);
|
|
162
164
|
process.exit(1);
|
|
163
165
|
}
|
|
164
166
|
}
|
|
@@ -191,9 +193,11 @@ Welcome, ${import_chalk2.default.white(data.username)}!`));
|
|
|
191
193
|
console.log(import_chalk2.default.dim("You can now submit your usage data.\n"));
|
|
192
194
|
} catch (error2) {
|
|
193
195
|
spinner.fail(import_chalk2.default.red("Authentication failed"));
|
|
194
|
-
console.log(
|
|
196
|
+
console.log(
|
|
197
|
+
import_chalk2.default.red(`
|
|
195
198
|
Error: ${error2 instanceof Error ? error2.message : "Unknown error"}
|
|
196
|
-
`)
|
|
199
|
+
`)
|
|
200
|
+
);
|
|
197
201
|
process.exit(1);
|
|
198
202
|
}
|
|
199
203
|
}
|
|
@@ -398,7 +402,13 @@ function scanUsageData(options = {}) {
|
|
|
398
402
|
totalOutputTokens += outputTokens;
|
|
399
403
|
totalCacheRead += cacheRead;
|
|
400
404
|
totalCacheWrite += cacheWrite;
|
|
401
|
-
const messageCost = estimateCost(
|
|
405
|
+
const messageCost = estimateCost(
|
|
406
|
+
model,
|
|
407
|
+
inputTokens,
|
|
408
|
+
outputTokens,
|
|
409
|
+
cacheWrite,
|
|
410
|
+
cacheRead
|
|
411
|
+
);
|
|
402
412
|
totalCost += messageCost;
|
|
403
413
|
const totalModelTokens = inputTokens + outputTokens + cacheWrite + cacheRead;
|
|
404
414
|
models[model] = (models[model] || 0) + totalModelTokens;
|
|
@@ -593,20 +603,30 @@ function createProfessionalHeader() {
|
|
|
593
603
|
` ${colors.primary("\u2580\u2588\u2584\u2584 \u2580\u2588\u2584\u2584")} ${colors.secondary("\u2580\u2588\u2584\u2584\u2580 \u2588 \u2588 \u2588 \u2588 \u2588 \u2588\u2584\u2584 \u2588 \u2588")} `
|
|
594
604
|
];
|
|
595
605
|
for (const l of logoLines) {
|
|
596
|
-
lines.push(
|
|
606
|
+
lines.push(
|
|
607
|
+
colors.dim(` ${v}`) + l + " ".repeat(Math.max(0, HEADER_WIDTH - stripAnsi(l).length)) + colors.dim(v)
|
|
608
|
+
);
|
|
597
609
|
}
|
|
598
610
|
const versionStr = `v${VERSION}`;
|
|
599
611
|
const versionPad = HEADER_WIDTH - versionStr.length - 2;
|
|
600
|
-
lines.push(
|
|
612
|
+
lines.push(
|
|
613
|
+
colors.dim(` ${v}`) + " ".repeat(versionPad) + colors.dim(versionStr) + " " + colors.dim(v)
|
|
614
|
+
);
|
|
601
615
|
lines.push(colors.dim(` ${boxRound.leftT}${h.repeat(HEADER_WIDTH)}${boxRound.rightT}`));
|
|
602
|
-
lines.push(
|
|
603
|
-
|
|
616
|
+
lines.push(
|
|
617
|
+
colors.dim(` ${v}`) + centerText(colors.muted("Where Claude Code Developers Gather"), HEADER_WIDTH) + colors.dim(v)
|
|
618
|
+
);
|
|
619
|
+
lines.push(
|
|
620
|
+
colors.dim(` ${v}`) + centerText(colors.dim("Gather \xB7 Compete \xB7 Rise"), HEADER_WIDTH) + colors.dim(v)
|
|
621
|
+
);
|
|
604
622
|
lines.push(colors.dim(` ${v}`) + " ".repeat(HEADER_WIDTH) + colors.dim(v));
|
|
605
623
|
const siteLabel = " \u{1F310} ccgather.com ";
|
|
606
624
|
const siteLink = hyperlink(colors.secondary(siteLabel), "https://ccgather.com");
|
|
607
625
|
const leftDashes = 13;
|
|
608
626
|
const rightDashes = HEADER_WIDTH - leftDashes - siteLabel.length;
|
|
609
|
-
lines.push(
|
|
627
|
+
lines.push(
|
|
628
|
+
colors.dim(` ${boxRound.bottomLeft}${h.repeat(leftDashes)}`) + siteLink + colors.dim(`${h.repeat(rightDashes)}${boxRound.bottomRight}`)
|
|
629
|
+
);
|
|
610
630
|
return lines;
|
|
611
631
|
}
|
|
612
632
|
function createBox(lines, width = 47) {
|
|
@@ -656,23 +676,61 @@ function getCCplanBadge(ccplan) {
|
|
|
656
676
|
};
|
|
657
677
|
return badges[ccplan.toLowerCase()] || "";
|
|
658
678
|
}
|
|
679
|
+
var LEVELS = [
|
|
680
|
+
{ min: 0, level: 1, name: "Novice", icon: "\u{1F331}", color: colors.dim },
|
|
681
|
+
{ min: 1e5, level: 2, name: "Apprentice", icon: "\u{1F4DA}", color: colors.muted },
|
|
682
|
+
{ min: 5e5, level: 3, name: "Journeyman", icon: "\u26A1", color: colors.cyan },
|
|
683
|
+
{ min: 1e6, level: 4, name: "Expert", icon: "\u{1F48E}", color: colors.pro },
|
|
684
|
+
{ min: 5e6, level: 5, name: "Master", icon: "\u{1F525}", color: colors.warning },
|
|
685
|
+
{ min: 1e7, level: 6, name: "Grandmaster", icon: "\u{1F451}", color: colors.max },
|
|
686
|
+
{ min: 5e7, level: 7, name: "Legend", icon: "\u{1F31F}", color: colors.primary },
|
|
687
|
+
{ min: 1e8, level: 8, name: "Mythic", icon: "\u{1F3C6}", color: colors.secondary }
|
|
688
|
+
];
|
|
659
689
|
function getLevelInfo(tokens) {
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
690
|
+
for (let i = LEVELS.length - 1; i >= 0; i--) {
|
|
691
|
+
if (tokens >= LEVELS[i].min) {
|
|
692
|
+
return LEVELS[i];
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
return LEVELS[0];
|
|
696
|
+
}
|
|
697
|
+
function getLevelProgress(tokens) {
|
|
698
|
+
let currentIndex = 0;
|
|
699
|
+
for (let i = LEVELS.length - 1; i >= 0; i--) {
|
|
700
|
+
if (tokens >= LEVELS[i].min) {
|
|
701
|
+
currentIndex = i;
|
|
702
|
+
break;
|
|
673
703
|
}
|
|
674
704
|
}
|
|
675
|
-
|
|
705
|
+
const current = LEVELS[currentIndex];
|
|
706
|
+
const isMaxLevel = currentIndex === LEVELS.length - 1;
|
|
707
|
+
if (isMaxLevel) {
|
|
708
|
+
return {
|
|
709
|
+
current,
|
|
710
|
+
next: null,
|
|
711
|
+
progress: 100,
|
|
712
|
+
tokensToNext: 0,
|
|
713
|
+
isMaxLevel: true
|
|
714
|
+
};
|
|
715
|
+
}
|
|
716
|
+
const nextLevel = LEVELS[currentIndex + 1];
|
|
717
|
+
const currentMin = current.min;
|
|
718
|
+
const nextMin = nextLevel.min;
|
|
719
|
+
const progressInLevel = tokens - currentMin;
|
|
720
|
+
const levelRange = nextMin - currentMin;
|
|
721
|
+
const progress = Math.min(100, Math.round(progressInLevel / levelRange * 100));
|
|
722
|
+
return {
|
|
723
|
+
current,
|
|
724
|
+
next: {
|
|
725
|
+
level: nextLevel.level,
|
|
726
|
+
name: nextLevel.name,
|
|
727
|
+
icon: nextLevel.icon,
|
|
728
|
+
threshold: nextLevel.min
|
|
729
|
+
},
|
|
730
|
+
progress,
|
|
731
|
+
tokensToNext: nextMin - tokens,
|
|
732
|
+
isMaxLevel: false
|
|
733
|
+
};
|
|
676
734
|
}
|
|
677
735
|
function countryCodeToFlag(countryCode) {
|
|
678
736
|
if (!countryCode || countryCode.length !== 2) return "\u{1F310}";
|
|
@@ -744,7 +802,9 @@ async function printAnimatedWelcomeBox(user) {
|
|
|
744
802
|
const maxVisibleLength = Math.max(...lines.map((l) => stripAnsi(l).length));
|
|
745
803
|
const boxWidth = Math.max(maxVisibleLength + 4, 47);
|
|
746
804
|
const top = colors.dim(` ${box.topLeft}${box.horizontal.repeat(boxWidth)}${box.topRight}`);
|
|
747
|
-
const bottom = colors.dim(
|
|
805
|
+
const bottom = colors.dim(
|
|
806
|
+
` ${box.bottomLeft}${box.horizontal.repeat(boxWidth)}${box.bottomRight}`
|
|
807
|
+
);
|
|
748
808
|
console.log(top);
|
|
749
809
|
await sleep(20);
|
|
750
810
|
for (const line of lines) {
|
|
@@ -825,35 +885,28 @@ function getRarityColor(rarity) {
|
|
|
825
885
|
return colors.muted;
|
|
826
886
|
}
|
|
827
887
|
}
|
|
888
|
+
function formatBadgeDate(dateStr) {
|
|
889
|
+
if (!dateStr) return (/* @__PURE__ */ new Date()).toISOString().split("T")[0].replace(/-/g, ".");
|
|
890
|
+
return dateStr.split("T")[0].replace(/-/g, ".");
|
|
891
|
+
}
|
|
828
892
|
function displayNewBadges(badges) {
|
|
829
893
|
if (badges.length === 0) return;
|
|
830
894
|
console.log();
|
|
831
|
-
console.log(` ${colors.max("\u{1F389} NEW BADGE" + (badges.length > 1 ? "S" : "") + " UNLOCKED!")}`);
|
|
832
|
-
console.log();
|
|
833
895
|
for (const badge of badges) {
|
|
834
896
|
const rarityColor = getRarityColor(badge.rarity);
|
|
835
897
|
const rarityLabel = badge.rarity.toUpperCase();
|
|
836
|
-
console.log(
|
|
837
|
-
|
|
898
|
+
console.log(
|
|
899
|
+
` ${badge.icon} ${colors.white.bold(badge.name)} ${rarityColor(`[${rarityLabel}]`)}`
|
|
900
|
+
);
|
|
901
|
+
console.log(` ${colors.muted(badge.description)}`);
|
|
838
902
|
if (badge.praise) {
|
|
839
|
-
console.log(`
|
|
903
|
+
console.log(` ${colors.cyan(`"${badge.praise}"`)}`);
|
|
904
|
+
}
|
|
905
|
+
if (badge.category === "rank") {
|
|
906
|
+
console.log(` ${colors.dim(`\u{1F4C5} Achieved: ${formatBadgeDate(badge.earnedAt)}`)}`);
|
|
840
907
|
}
|
|
841
|
-
console.log();
|
|
842
908
|
}
|
|
843
909
|
}
|
|
844
|
-
function displayBadgeProgress(progress, totalBadges) {
|
|
845
|
-
if (progress.length === 0) return;
|
|
846
|
-
console.log(` ${colors.muted("Badge Progress")} ${colors.dim(`(${totalBadges} earned)`)}`);
|
|
847
|
-
for (const p of progress) {
|
|
848
|
-
const barWidth = 16;
|
|
849
|
-
const filled = Math.round(p.percent / 100 * barWidth);
|
|
850
|
-
const empty = barWidth - filled;
|
|
851
|
-
const bar = colors.primary("\u2588".repeat(filled)) + colors.dim("\u2591".repeat(empty));
|
|
852
|
-
const badgeName = p.id.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
853
|
-
console.log(` ${colors.dim("\u2022")} ${colors.muted(badgeName.padEnd(18))} [${bar}] ${colors.white(`${p.percent}%`)}`);
|
|
854
|
-
}
|
|
855
|
-
console.log();
|
|
856
|
-
}
|
|
857
910
|
async function submit(options) {
|
|
858
911
|
console.log(header("Submit Usage Data", "\u{1F4E4}"));
|
|
859
912
|
if (!isAuthenticated()) {
|
|
@@ -870,8 +923,10 @@ async function submit(options) {
|
|
|
870
923
|
let usageData = null;
|
|
871
924
|
const totalFiles = getSessionFileCount();
|
|
872
925
|
if (totalFiles > 0) {
|
|
873
|
-
console.log(
|
|
874
|
-
|
|
926
|
+
console.log(
|
|
927
|
+
`
|
|
928
|
+
${colors.muted("Scanning")} ${colors.white(totalFiles.toString())} ${colors.muted("sessions...")}`
|
|
929
|
+
);
|
|
875
930
|
const scannedData = scanUsageData({
|
|
876
931
|
onProgress: (current, total) => {
|
|
877
932
|
progressBar(current, total, "Scanning");
|
|
@@ -932,32 +987,57 @@ async function submit(options) {
|
|
|
932
987
|
if (result.success) {
|
|
933
988
|
submitSpinner.succeed(colors.success("Successfully submitted!"));
|
|
934
989
|
console.log();
|
|
990
|
+
const sectionHeader = (icon, title) => {
|
|
991
|
+
const text = `${icon} ${title} `;
|
|
992
|
+
const lineLength = 40 - text.length;
|
|
993
|
+
return ` ${colors.white.bold(text)}${colors.dim("\u2500".repeat(Math.max(0, lineLength)))}`;
|
|
994
|
+
};
|
|
995
|
+
if (result.rank || result.countryRank) {
|
|
996
|
+
console.log();
|
|
997
|
+
console.log(sectionHeader("\u{1F4CA}", "Your Ranking"));
|
|
998
|
+
console.log();
|
|
999
|
+
if (result.rank) {
|
|
1000
|
+
const medal = result.rank === 1 ? "\u{1F947}" : result.rank === 2 ? "\u{1F948}" : result.rank === 3 ? "\u{1F949}" : result.rank <= 10 ? "\u{1F3C5}" : "\u{1F30D}";
|
|
1001
|
+
console.log(
|
|
1002
|
+
` ${medal} ${colors.muted("Global:")} ${colors.primary.bold(`#${result.rank}`)}`
|
|
1003
|
+
);
|
|
1004
|
+
}
|
|
1005
|
+
if (result.countryRank) {
|
|
1006
|
+
const countryMedal = result.countryRank === 1 ? "\u{1F947}" : result.countryRank <= 3 ? "\u{1F3C6}" : "\u{1F3E0}";
|
|
1007
|
+
console.log(
|
|
1008
|
+
` ${countryMedal} ${colors.muted("Country:")} ${colors.primary.bold(`#${result.countryRank}`)}`
|
|
1009
|
+
);
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
console.log();
|
|
1013
|
+
console.log(sectionHeader("\u2B06\uFE0F", "Level Progress"));
|
|
1014
|
+
console.log();
|
|
1015
|
+
const levelProgress = getLevelProgress(usageData.totalTokens);
|
|
1016
|
+
const currentLevel = levelProgress.current;
|
|
1017
|
+
console.log(
|
|
1018
|
+
` ${currentLevel.icon} ${currentLevel.color(`Level ${currentLevel.level}`)} ${colors.muted("\u2022")} ${colors.white(currentLevel.name)}`
|
|
1019
|
+
);
|
|
1020
|
+
if (!levelProgress.isMaxLevel && levelProgress.next) {
|
|
1021
|
+
const barWidth = 20;
|
|
1022
|
+
const filled = Math.round(levelProgress.progress / 100 * barWidth);
|
|
1023
|
+
const empty = barWidth - filled;
|
|
1024
|
+
const bar = colors.primary("\u2588".repeat(filled)) + colors.dim("\u2591".repeat(empty));
|
|
1025
|
+
console.log(` [${bar}] ${colors.white(`${levelProgress.progress}%`)}`);
|
|
1026
|
+
console.log(
|
|
1027
|
+
` ${colors.dim("\u2192")} ${levelProgress.next.icon} ${colors.white(levelProgress.next.name)} ${colors.muted("in")} ${colors.primary(formatNumber(levelProgress.tokensToNext))}`
|
|
1028
|
+
);
|
|
1029
|
+
} else {
|
|
1030
|
+
console.log(` ${colors.max("\u2605")} ${colors.max("MAX LEVEL ACHIEVED!")}`);
|
|
1031
|
+
}
|
|
935
1032
|
if (result.newBadges && result.newBadges.length > 0) {
|
|
1033
|
+
console.log();
|
|
1034
|
+
console.log(sectionHeader("\u{1F389}", "New Badge Unlocked"));
|
|
936
1035
|
displayNewBadges(result.newBadges);
|
|
937
1036
|
}
|
|
938
|
-
|
|
939
|
-
displayBadgeProgress(result.badgeProgress, result.totalBadges || 0);
|
|
940
|
-
}
|
|
941
|
-
const levelInfo = getLevelInfo(usageData.totalTokens);
|
|
1037
|
+
console.log();
|
|
942
1038
|
const leaderboardUrl = `https://ccgather.com/leaderboard?u=${username}`;
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
"",
|
|
946
|
-
`${levelInfo.icon} ${levelInfo.color(`Level ${levelInfo.level}`)} ${colors.muted("\u2022")} ${colors.white(levelInfo.name)}`,
|
|
947
|
-
""
|
|
948
|
-
];
|
|
949
|
-
if (result.rank) {
|
|
950
|
-
successLines.push(`${colors.muted("Global Rank:")} ${colors.primary(`#${result.rank}`)}`);
|
|
951
|
-
}
|
|
952
|
-
if (result.countryRank) {
|
|
953
|
-
successLines.push(`${colors.muted("Country Rank:")} ${colors.primary(`#${result.countryRank}`)}`);
|
|
954
|
-
}
|
|
955
|
-
if (result.rank || result.countryRank) {
|
|
956
|
-
successLines.push("");
|
|
957
|
-
}
|
|
958
|
-
successLines.push(`${colors.muted("Check your rank on the leaderboard:")}`);
|
|
959
|
-
successLines.push(`${link(leaderboardUrl)}`);
|
|
960
|
-
console.log(createBox(successLines));
|
|
1039
|
+
console.log(` ${colors.dim("\u2500".repeat(40))}`);
|
|
1040
|
+
console.log(` ${colors.muted("View full stats:")} ${link(leaderboardUrl)}`);
|
|
961
1041
|
console.log();
|
|
962
1042
|
} else {
|
|
963
1043
|
submitSpinner.fail(colors.error("Failed to submit"));
|
|
@@ -1039,7 +1119,9 @@ async function status(options) {
|
|
|
1039
1119
|
if (stats.countryRank && stats.countryCode) {
|
|
1040
1120
|
const countryFlag = countryCodeToFlag(stats.countryCode);
|
|
1041
1121
|
const countryMedal = getRankMedal(stats.countryRank);
|
|
1042
|
-
console.log(
|
|
1122
|
+
console.log(
|
|
1123
|
+
` ${countryFlag} ${colors.muted("Country")} ${countryMedal} ${colors.white.bold(`#${stats.countryRank}`)}`
|
|
1124
|
+
);
|
|
1043
1125
|
}
|
|
1044
1126
|
console.log(` ${colors.dim(`Top ${stats.percentile.toFixed(1)}% globally`)}`);
|
|
1045
1127
|
console.log();
|