whoburnedmore 0.3.0 → 0.4.0
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 +101 -12
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -29,16 +29,34 @@ function parseBoard(args) {
|
|
|
29
29
|
function apiBase() {
|
|
30
30
|
return process.env.WHOBURNEDMORE_API ?? "https://api.whoburnedmore.com";
|
|
31
31
|
}
|
|
32
|
+
async function readJson(res) {
|
|
33
|
+
const text = await res.text();
|
|
34
|
+
if (!text) return {};
|
|
35
|
+
try {
|
|
36
|
+
return JSON.parse(text);
|
|
37
|
+
} catch {
|
|
38
|
+
return {
|
|
39
|
+
error: res.status >= 500 ? "the leaderboard server is temporarily unavailable \u2014 try again in a minute" : `unexpected response from the server (HTTP ${res.status})`
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
}
|
|
32
43
|
async function post(path, body, token) {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
44
|
+
let res;
|
|
45
|
+
try {
|
|
46
|
+
res = await fetch(`${apiBase()}${path}`, {
|
|
47
|
+
method: "POST",
|
|
48
|
+
headers: {
|
|
49
|
+
"Content-Type": "application/json",
|
|
50
|
+
...token ? { Authorization: `Bearer ${token}` } : {}
|
|
51
|
+
},
|
|
52
|
+
body: JSON.stringify(body)
|
|
53
|
+
});
|
|
54
|
+
} catch {
|
|
55
|
+
throw new Error(
|
|
56
|
+
"couldn't reach the leaderboard server \u2014 check your connection and try again"
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
return { status: res.status, body: await readJson(res) };
|
|
42
60
|
}
|
|
43
61
|
async function deviceStart() {
|
|
44
62
|
const { status, body } = await post("/v1/auth/device", {});
|
|
@@ -660,6 +678,46 @@ function resolveCcusageBin() {
|
|
|
660
678
|
}
|
|
661
679
|
return { cmd: binPath, prefixArgs: [] };
|
|
662
680
|
}
|
|
681
|
+
function dedupeDaily(entries) {
|
|
682
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
683
|
+
for (const e of entries) {
|
|
684
|
+
const key = `${e.date}|${e.tool}|${e.model}|${e.origin}`;
|
|
685
|
+
const prev = byKey.get(key);
|
|
686
|
+
if (!prev) {
|
|
687
|
+
byKey.set(key, { ...e });
|
|
688
|
+
continue;
|
|
689
|
+
}
|
|
690
|
+
prev.inputTokens += e.inputTokens;
|
|
691
|
+
prev.outputTokens += e.outputTokens;
|
|
692
|
+
prev.cacheCreationTokens += e.cacheCreationTokens;
|
|
693
|
+
prev.cacheReadTokens += e.cacheReadTokens;
|
|
694
|
+
prev.costUSD = Number((prev.costUSD + e.costUSD).toFixed(6));
|
|
695
|
+
prev.verified = prev.verified && e.verified;
|
|
696
|
+
}
|
|
697
|
+
return [...byKey.values()];
|
|
698
|
+
}
|
|
699
|
+
function dedupeSessions(sessions) {
|
|
700
|
+
const byId = /* @__PURE__ */ new Map();
|
|
701
|
+
const total = (s) => s.inputTokens + s.outputTokens + s.cacheCreationTokens + s.cacheReadTokens;
|
|
702
|
+
for (const s of sessions) {
|
|
703
|
+
const prev = byId.get(s.sessionId);
|
|
704
|
+
if (!prev || total(s) >= total(prev)) byId.set(s.sessionId, s);
|
|
705
|
+
}
|
|
706
|
+
return [...byId.values()];
|
|
707
|
+
}
|
|
708
|
+
function dedupeBlocks(blocks) {
|
|
709
|
+
const byStart = /* @__PURE__ */ new Map();
|
|
710
|
+
for (const b of blocks) {
|
|
711
|
+
const prev = byStart.get(b.startTime);
|
|
712
|
+
if (!prev) {
|
|
713
|
+
byStart.set(b.startTime, { ...b });
|
|
714
|
+
continue;
|
|
715
|
+
}
|
|
716
|
+
prev.totalTokens += b.totalTokens;
|
|
717
|
+
prev.costUSD = Number((prev.costUSD + b.costUSD).toFixed(6));
|
|
718
|
+
}
|
|
719
|
+
return [...byStart.values()];
|
|
720
|
+
}
|
|
663
721
|
function runCcusage(cmd, args) {
|
|
664
722
|
const res = spawnSync4(cmd, args, {
|
|
665
723
|
encoding: "utf8",
|
|
@@ -702,7 +760,12 @@ async function collectAll() {
|
|
|
702
760
|
blocks.push(...cursor.blocks);
|
|
703
761
|
toolsFound.push("cursor");
|
|
704
762
|
}
|
|
705
|
-
return {
|
|
763
|
+
return {
|
|
764
|
+
entries: dedupeDaily(entries),
|
|
765
|
+
sessions: dedupeSessions(sessions),
|
|
766
|
+
blocks: dedupeBlocks(blocks),
|
|
767
|
+
toolsFound
|
|
768
|
+
};
|
|
706
769
|
}
|
|
707
770
|
|
|
708
771
|
// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/external.js
|
|
@@ -5036,6 +5099,25 @@ async function publishLocal(payload, deps) {
|
|
|
5036
5099
|
// src/index.ts
|
|
5037
5100
|
var require2 = createRequire4(import.meta.url);
|
|
5038
5101
|
var VERSION = require2("../package.json").version;
|
|
5102
|
+
function startSpinner(label) {
|
|
5103
|
+
if (!process.stdout.isTTY) {
|
|
5104
|
+
console.log(pc2.dim(` ${label}`));
|
|
5105
|
+
return () => {
|
|
5106
|
+
};
|
|
5107
|
+
}
|
|
5108
|
+
const frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
5109
|
+
let i = 0;
|
|
5110
|
+
process.stdout.write("\x1B[?25l");
|
|
5111
|
+
const timer = setInterval(() => {
|
|
5112
|
+
i = (i + 1) % frames.length;
|
|
5113
|
+
process.stdout.write(`\r ${pc2.yellow(frames[i])} ${pc2.dim(label)}`);
|
|
5114
|
+
}, 80);
|
|
5115
|
+
return () => {
|
|
5116
|
+
clearInterval(timer);
|
|
5117
|
+
process.stdout.write("\r\x1B[2K");
|
|
5118
|
+
process.stdout.write("\x1B[?25h");
|
|
5119
|
+
};
|
|
5120
|
+
}
|
|
5039
5121
|
function openBrowser(url) {
|
|
5040
5122
|
const os = platform3();
|
|
5041
5123
|
const [cmd, args] = os === "darwin" ? ["open", [url]] : os === "win32" ? ["cmd", ["/c", "start", "", url]] : ["xdg-open", [url]];
|
|
@@ -5082,9 +5164,16 @@ function showLocalDashboard(entries) {
|
|
|
5082
5164
|
async function run(flags) {
|
|
5083
5165
|
if (!flags.quiet) {
|
|
5084
5166
|
console.log(pc2.dim(`whoburnedmore v${VERSION} \xB7 ${flags.local ? "local mode" : apiBase()}`));
|
|
5085
|
-
console.log(pc2.dim(" Calculating your burn from local usage\u2026"));
|
|
5086
5167
|
}
|
|
5087
|
-
const
|
|
5168
|
+
const stop = flags.quiet ? () => {
|
|
5169
|
+
} : startSpinner("Calculating your burn from local usage\u2026");
|
|
5170
|
+
let collected;
|
|
5171
|
+
try {
|
|
5172
|
+
collected = await collectAll();
|
|
5173
|
+
} finally {
|
|
5174
|
+
stop();
|
|
5175
|
+
}
|
|
5176
|
+
const { entries, sessions, blocks, toolsFound } = collected;
|
|
5088
5177
|
if (entries.length === 0) {
|
|
5089
5178
|
console.log();
|
|
5090
5179
|
console.log(" Nothing to burn yet \u2014 no local usage found from any coding agent.");
|