whoburnedmore 0.9.16 → 0.9.17
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 +80 -74
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -7,7 +7,6 @@ var __export = (target, all) => {
|
|
|
7
7
|
|
|
8
8
|
// src/index.ts
|
|
9
9
|
import { spawn } from "node:child_process";
|
|
10
|
-
import { createHash } from "node:crypto";
|
|
11
10
|
import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync5 } from "node:fs";
|
|
12
11
|
import { createRequire as createRequire4 } from "node:module";
|
|
13
12
|
import { platform as platform4 } from "node:os";
|
|
@@ -6618,6 +6617,31 @@ async function readFilesWithCache(opts) {
|
|
|
6618
6617
|
return { itemsByFile, filesRead, timedOut: false };
|
|
6619
6618
|
}
|
|
6620
6619
|
|
|
6620
|
+
// src/native/usage-date.ts
|
|
6621
|
+
var MIN_USAGE_TIMESTAMP_MS = Date.UTC(2020, 0, 1);
|
|
6622
|
+
var MAX_CLOCK_SKEW_MS = 2 * 864e5;
|
|
6623
|
+
function localUsageDate(ms, now = Date.now()) {
|
|
6624
|
+
if (!Number.isFinite(ms) || ms < MIN_USAGE_TIMESTAMP_MS || ms > now + MAX_CLOCK_SKEW_MS) {
|
|
6625
|
+
return null;
|
|
6626
|
+
}
|
|
6627
|
+
const d = new Date(ms);
|
|
6628
|
+
if (!Number.isFinite(d.getTime())) return null;
|
|
6629
|
+
const y = d.getFullYear();
|
|
6630
|
+
const m = String(d.getMonth() + 1).padStart(2, "0");
|
|
6631
|
+
const day = String(d.getDate()).padStart(2, "0");
|
|
6632
|
+
return `${y}-${m}-${day}`;
|
|
6633
|
+
}
|
|
6634
|
+
function plausibleUsageDate(value, now = Date.now()) {
|
|
6635
|
+
const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(value);
|
|
6636
|
+
if (!match) return false;
|
|
6637
|
+
const year = Number(match[1]);
|
|
6638
|
+
const month = Number(match[2]);
|
|
6639
|
+
const day = Number(match[3]);
|
|
6640
|
+
const ms = Date.UTC(year, month - 1, day);
|
|
6641
|
+
const parsed = new Date(ms);
|
|
6642
|
+
return parsed.getUTCFullYear() === year && parsed.getUTCMonth() === month - 1 && parsed.getUTCDate() === day && ms >= MIN_USAGE_TIMESTAMP_MS && ms <= now + MAX_CLOCK_SKEW_MS;
|
|
6643
|
+
}
|
|
6644
|
+
|
|
6621
6645
|
// src/native/claude.ts
|
|
6622
6646
|
function num(n) {
|
|
6623
6647
|
const v = Math.round(Number(n));
|
|
@@ -6626,15 +6650,6 @@ function num(n) {
|
|
|
6626
6650
|
function reqTokens(r) {
|
|
6627
6651
|
return r.inputTokens + r.outputTokens + r.cacheCreationTokens + r.cacheReadTokens;
|
|
6628
6652
|
}
|
|
6629
|
-
function localDate(iso) {
|
|
6630
|
-
const t = Date.parse(iso);
|
|
6631
|
-
if (!Number.isFinite(t)) return null;
|
|
6632
|
-
const d = new Date(t);
|
|
6633
|
-
const y = d.getFullYear();
|
|
6634
|
-
const m = String(d.getMonth() + 1).padStart(2, "0");
|
|
6635
|
-
const day = String(d.getDate()).padStart(2, "0");
|
|
6636
|
-
return `${y}-${m}-${day}`;
|
|
6637
|
-
}
|
|
6638
6653
|
var syntheticCounter = 0;
|
|
6639
6654
|
function parseClaudeLine(raw) {
|
|
6640
6655
|
const trimmed = raw.trim();
|
|
@@ -6650,10 +6665,10 @@ function parseClaudeLine(raw) {
|
|
|
6650
6665
|
const usage = message.usage;
|
|
6651
6666
|
if (!usage || typeof usage !== "object") return null;
|
|
6652
6667
|
if (message.role !== void 0 && message.role !== "assistant") return null;
|
|
6653
|
-
const date = localDate(String(obj.timestamp ?? ""));
|
|
6654
|
-
if (!date) return null;
|
|
6655
6668
|
const tsParsed = Date.parse(String(obj.timestamp ?? ""));
|
|
6656
|
-
const
|
|
6669
|
+
const date = localUsageDate(tsParsed);
|
|
6670
|
+
if (!date) return null;
|
|
6671
|
+
const ts = tsParsed;
|
|
6657
6672
|
const messageId = typeof message.id === "string" ? message.id : "";
|
|
6658
6673
|
const requestId = typeof obj.requestId === "string" ? obj.requestId : "";
|
|
6659
6674
|
const hasRealId = messageId !== "" || requestId !== "";
|
|
@@ -6747,7 +6762,7 @@ async function listJsonl(dir) {
|
|
|
6747
6762
|
return out;
|
|
6748
6763
|
}
|
|
6749
6764
|
var NATIVE_READ_BUDGET_MS = 45e3;
|
|
6750
|
-
var CLAUDE_CACHE_VERSION =
|
|
6765
|
+
var CLAUDE_CACHE_VERSION = 2;
|
|
6751
6766
|
function toCached(r) {
|
|
6752
6767
|
return [
|
|
6753
6768
|
r.key,
|
|
@@ -7190,13 +7205,6 @@ function toEpochMs(ts) {
|
|
|
7190
7205
|
}
|
|
7191
7206
|
return null;
|
|
7192
7207
|
}
|
|
7193
|
-
function localDate2(ms) {
|
|
7194
|
-
const d = new Date(ms);
|
|
7195
|
-
const y = d.getFullYear();
|
|
7196
|
-
const m = String(d.getMonth() + 1).padStart(2, "0");
|
|
7197
|
-
const day = String(d.getDate()).padStart(2, "0");
|
|
7198
|
-
return `${y}-${m}-${day}`;
|
|
7199
|
-
}
|
|
7200
7208
|
function mapContinueRecords(records) {
|
|
7201
7209
|
const byKey = /* @__PURE__ */ new Map();
|
|
7202
7210
|
for (const raw of records) {
|
|
@@ -7208,10 +7216,11 @@ function mapContinueRecords(records) {
|
|
|
7208
7216
|
if (!model) continue;
|
|
7209
7217
|
const ms = toEpochMs(rec.timestamp ?? rec.eventTimestamp);
|
|
7210
7218
|
if (ms === null) continue;
|
|
7219
|
+
const date = localUsageDate(ms);
|
|
7220
|
+
if (!date) continue;
|
|
7211
7221
|
const inputTokens = num2(rec.promptTokens ?? rec.prompt_tokens);
|
|
7212
7222
|
const outputTokens = num2(rec.generatedTokens ?? rec.generated_tokens);
|
|
7213
7223
|
if (inputTokens + outputTokens === 0) continue;
|
|
7214
|
-
const date = localDate2(ms);
|
|
7215
7224
|
const key = `${date}|${model}`;
|
|
7216
7225
|
let b = byKey.get(key);
|
|
7217
7226
|
if (!b) {
|
|
@@ -7269,11 +7278,11 @@ async function listJsonl2(dir) {
|
|
|
7269
7278
|
for (const d of dirents) {
|
|
7270
7279
|
const full = join6(dir, d.name);
|
|
7271
7280
|
if (d.isDirectory()) out.push(...await listJsonl2(full));
|
|
7272
|
-
else if (d.isFile() && d.name
|
|
7281
|
+
else if (d.isFile() && d.name === "tokensGenerated.jsonl") out.push(full);
|
|
7273
7282
|
}
|
|
7274
7283
|
return out;
|
|
7275
7284
|
}
|
|
7276
|
-
var CONTINUE_CACHE_VERSION =
|
|
7285
|
+
var CONTINUE_CACHE_VERSION = 2;
|
|
7277
7286
|
async function collectContinue(opts = {}) {
|
|
7278
7287
|
const env = opts.env ?? process.env;
|
|
7279
7288
|
const home = opts.continueDir ?? join6(env.HOME || homedir5(), ".continue");
|
|
@@ -7493,7 +7502,8 @@ function mapCursorEvents(events) {
|
|
|
7493
7502
|
const ms = Number(e.timestamp);
|
|
7494
7503
|
if (!tu || !Number.isFinite(ms)) continue;
|
|
7495
7504
|
const d = new Date(ms);
|
|
7496
|
-
const date =
|
|
7505
|
+
const date = localUsageDate(ms);
|
|
7506
|
+
if (!date) continue;
|
|
7497
7507
|
const model = e.model || "cursor";
|
|
7498
7508
|
const input = num4(tu.inputTokens);
|
|
7499
7509
|
const output = num4(tu.outputTokens);
|
|
@@ -7590,15 +7600,6 @@ function num5(n) {
|
|
|
7590
7600
|
const v = Math.round(Number(n));
|
|
7591
7601
|
return Number.isFinite(v) && v > 0 ? v : 0;
|
|
7592
7602
|
}
|
|
7593
|
-
function localDate3(iso) {
|
|
7594
|
-
const t = Date.parse(iso);
|
|
7595
|
-
if (!Number.isFinite(t)) return null;
|
|
7596
|
-
const d = new Date(t);
|
|
7597
|
-
const y = d.getFullYear();
|
|
7598
|
-
const m = String(d.getMonth() + 1).padStart(2, "0");
|
|
7599
|
-
const day = String(d.getDate()).padStart(2, "0");
|
|
7600
|
-
return `${y}-${m}-${day}`;
|
|
7601
|
-
}
|
|
7602
7603
|
function readTokenFields(payload) {
|
|
7603
7604
|
const info = payload.info;
|
|
7604
7605
|
const src = info?.total_token_usage ?? payload;
|
|
@@ -7608,8 +7609,7 @@ function readTokenFields(payload) {
|
|
|
7608
7609
|
return {
|
|
7609
7610
|
input: num5(input),
|
|
7610
7611
|
cached: num5(src.cached_input_tokens),
|
|
7611
|
-
output: num5(output)
|
|
7612
|
-
reasoning: num5(src.reasoning_output_tokens)
|
|
7612
|
+
output: num5(output)
|
|
7613
7613
|
};
|
|
7614
7614
|
}
|
|
7615
7615
|
function parseCodexRollout(lines) {
|
|
@@ -7634,7 +7634,7 @@ function parseCodexRollout(lines) {
|
|
|
7634
7634
|
if (payload.type === "token_count") {
|
|
7635
7635
|
const fields = readTokenFields(payload);
|
|
7636
7636
|
if (!fields) continue;
|
|
7637
|
-
const parsed =
|
|
7637
|
+
const parsed = localUsageDate(Date.parse(String(obj.timestamp ?? "")));
|
|
7638
7638
|
const day = parsed ?? lastSeenDate;
|
|
7639
7639
|
if (!day) continue;
|
|
7640
7640
|
lastSeenDate = day;
|
|
@@ -7650,17 +7650,16 @@ function parseCodexRollout(lines) {
|
|
|
7650
7650
|
if (perDay.size === 0) return [];
|
|
7651
7651
|
const dates = [...perDay.keys()].sort();
|
|
7652
7652
|
const out = [];
|
|
7653
|
-
let prev = { input: 0, cached: 0, output: 0
|
|
7653
|
+
let prev = { input: 0, cached: 0, output: 0 };
|
|
7654
7654
|
for (const date of dates) {
|
|
7655
7655
|
const { cum, turns } = perDay.get(date);
|
|
7656
7656
|
const dInput = Math.max(0, cum.input - prev.input);
|
|
7657
7657
|
const dCached = Math.max(0, cum.cached - prev.cached);
|
|
7658
7658
|
const dOutput = Math.max(0, cum.output - prev.output);
|
|
7659
|
-
const dReasoning = Math.max(0, cum.reasoning - prev.reasoning);
|
|
7660
7659
|
prev = cum;
|
|
7661
7660
|
const cacheReadTokens = dCached;
|
|
7662
7661
|
const inputTokens = Math.max(0, dInput - dCached);
|
|
7663
|
-
const outputTokens = dOutput
|
|
7662
|
+
const outputTokens = dOutput;
|
|
7664
7663
|
if (inputTokens + outputTokens + cacheReadTokens === 0) continue;
|
|
7665
7664
|
out.push({
|
|
7666
7665
|
date,
|
|
@@ -7746,7 +7745,7 @@ function* splitLines3(content) {
|
|
|
7746
7745
|
if (start < content.length) yield content.slice(start);
|
|
7747
7746
|
}
|
|
7748
7747
|
var NATIVE_READ_BUDGET_MS2 = 45e3;
|
|
7749
|
-
var CODEX_CACHE_VERSION =
|
|
7748
|
+
var CODEX_CACHE_VERSION = 2;
|
|
7750
7749
|
function toCachedSession(s) {
|
|
7751
7750
|
return [
|
|
7752
7751
|
s.date,
|
|
@@ -7813,17 +7812,9 @@ function num6(n) {
|
|
|
7813
7812
|
const v = Math.round(Number(n));
|
|
7814
7813
|
return Number.isFinite(v) && v > 0 ? v : 0;
|
|
7815
7814
|
}
|
|
7816
|
-
function localDate4(ms) {
|
|
7817
|
-
if (!Number.isFinite(ms) || ms <= 0) return null;
|
|
7818
|
-
const d = new Date(ms);
|
|
7819
|
-
const y = d.getFullYear();
|
|
7820
|
-
const m = String(d.getMonth() + 1).padStart(2, "0");
|
|
7821
|
-
const day = String(d.getDate()).padStart(2, "0");
|
|
7822
|
-
return `${y}-${m}-${day}`;
|
|
7823
|
-
}
|
|
7824
7815
|
function parseApiReqMessage(tool, msg) {
|
|
7825
7816
|
if (msg.say !== "api_req_started") return null;
|
|
7826
|
-
const date =
|
|
7817
|
+
const date = localUsageDate(Number(msg.ts));
|
|
7827
7818
|
if (!date) return null;
|
|
7828
7819
|
let payload = null;
|
|
7829
7820
|
const text = msg.text;
|
|
@@ -7947,7 +7938,7 @@ async function listTaskFiles(roots, extIds) {
|
|
|
7947
7938
|
}
|
|
7948
7939
|
return files;
|
|
7949
7940
|
}
|
|
7950
|
-
var VSCODE_CACHE_VERSION =
|
|
7941
|
+
var VSCODE_CACHE_VERSION = 2;
|
|
7951
7942
|
function entryToRow(e) {
|
|
7952
7943
|
return [
|
|
7953
7944
|
e.date,
|
|
@@ -8181,14 +8172,14 @@ function normCost(n) {
|
|
|
8181
8172
|
const v = Number(n);
|
|
8182
8173
|
return Number.isFinite(v) && v > 0 ? v : 0;
|
|
8183
8174
|
}
|
|
8184
|
-
function mapCcusageDaily(tool, json) {
|
|
8175
|
+
function mapCcusageDaily(tool, json, now = Date.now()) {
|
|
8185
8176
|
const daily = json?.daily;
|
|
8186
8177
|
if (!Array.isArray(daily)) return [];
|
|
8187
8178
|
const entries = [];
|
|
8188
8179
|
for (const rawDay of daily) {
|
|
8189
8180
|
const day = rawDay;
|
|
8190
8181
|
const date = day.date ?? day.period;
|
|
8191
|
-
if (typeof date !== "string" ||
|
|
8182
|
+
if (typeof date !== "string" || !plausibleUsageDate(date, now)) continue;
|
|
8192
8183
|
const breakdowns = Array.isArray(day.modelBreakdowns) ? day.modelBreakdowns : [];
|
|
8193
8184
|
const modelsMap = day.models && typeof day.models === "object" && !Array.isArray(day.models) ? day.models : null;
|
|
8194
8185
|
const dayCost = normCost(day.totalCost ?? day.costUSD);
|
|
@@ -8390,8 +8381,8 @@ async function runCcusage(cmd, args, env) {
|
|
|
8390
8381
|
return (await runCcusageOnce(cmd, args, env)).json;
|
|
8391
8382
|
}
|
|
8392
8383
|
var COLLECT_STAGES = SOURCES.length + 4 + VSCODE_AGENTS.length + 1;
|
|
8393
|
-
function isAuthoritativeScan(attributionComplete,
|
|
8394
|
-
return attributionComplete &&
|
|
8384
|
+
function isAuthoritativeScan(attributionComplete, ...fingerprintReaders) {
|
|
8385
|
+
return attributionComplete && fingerprintReaders.every((reader) => reader.timedOut !== true);
|
|
8395
8386
|
}
|
|
8396
8387
|
async function collectAll(onProgress) {
|
|
8397
8388
|
await loadLivePricing().catch(() => {
|
|
@@ -8500,7 +8491,13 @@ async function collectAll(onProgress) {
|
|
|
8500
8491
|
...messageCount ? { messageCount } : {}
|
|
8501
8492
|
};
|
|
8502
8493
|
});
|
|
8503
|
-
const scanComplete = isAuthoritativeScan(
|
|
8494
|
+
const scanComplete = isAuthoritativeScan(
|
|
8495
|
+
complete,
|
|
8496
|
+
nativeClaude,
|
|
8497
|
+
nativeCodex,
|
|
8498
|
+
...vscodeResults.map(({ result }) => result),
|
|
8499
|
+
continueResult
|
|
8500
|
+
);
|
|
8504
8501
|
const storePath = provenanceStorePath();
|
|
8505
8502
|
const reconciled = reconcileProvenance(
|
|
8506
8503
|
dedupeDaily(entries),
|
|
@@ -8545,6 +8542,26 @@ function antigravityNoticeLines() {
|
|
|
8545
8542
|
];
|
|
8546
8543
|
}
|
|
8547
8544
|
|
|
8545
|
+
// src/verify-upload.ts
|
|
8546
|
+
import { createHash } from "node:crypto";
|
|
8547
|
+
function prepareVerifyUpload(requests, scanTimedOut, cap = 5e4) {
|
|
8548
|
+
const sorted = requests.slice().sort((a, b) => b.ts - a.ts);
|
|
8549
|
+
const truncated = scanTimedOut || sorted.length > cap;
|
|
8550
|
+
const capped = sorted.length > cap ? sorted.slice(0, cap) : sorted;
|
|
8551
|
+
const records = capped.map((r) => ({
|
|
8552
|
+
date: r.date,
|
|
8553
|
+
ts: r.ts,
|
|
8554
|
+
tool: "claude",
|
|
8555
|
+
model: r.model.trim().slice(0, 128) || "unknown",
|
|
8556
|
+
inputTokens: r.inputTokens,
|
|
8557
|
+
outputTokens: r.outputTokens,
|
|
8558
|
+
cacheCreationTokens: r.cacheCreationTokens,
|
|
8559
|
+
cacheReadTokens: r.cacheReadTokens,
|
|
8560
|
+
reqHash: createHash("sha256").update(r.key).digest("hex").slice(0, 32)
|
|
8561
|
+
}));
|
|
8562
|
+
return { records, truncated };
|
|
8563
|
+
}
|
|
8564
|
+
|
|
8548
8565
|
// src/status.ts
|
|
8549
8566
|
function ago(ms) {
|
|
8550
8567
|
const mins = Math.round(ms / 6e4);
|
|
@@ -9338,7 +9355,7 @@ async function runVerify() {
|
|
|
9338
9355
|
}
|
|
9339
9356
|
}
|
|
9340
9357
|
console.log(pc2.dim(" Reading your local Claude Code logs\u2026"));
|
|
9341
|
-
const { requests, found } = await collectClaudeRequests();
|
|
9358
|
+
const { requests, found, timedOut } = await collectClaudeRequests();
|
|
9342
9359
|
if (!found || requests.length === 0) {
|
|
9343
9360
|
console.log(
|
|
9344
9361
|
pc2.yellow(" No local Claude Code logs found on this machine to verify.")
|
|
@@ -9350,21 +9367,10 @@ async function runVerify() {
|
|
|
9350
9367
|
);
|
|
9351
9368
|
return;
|
|
9352
9369
|
}
|
|
9353
|
-
const
|
|
9354
|
-
|
|
9355
|
-
|
|
9356
|
-
|
|
9357
|
-
const records = capped.map((r) => ({
|
|
9358
|
-
date: r.date,
|
|
9359
|
-
ts: r.ts,
|
|
9360
|
-
tool: "claude",
|
|
9361
|
-
model: r.model,
|
|
9362
|
-
inputTokens: r.inputTokens,
|
|
9363
|
-
outputTokens: r.outputTokens,
|
|
9364
|
-
cacheCreationTokens: r.cacheCreationTokens,
|
|
9365
|
-
cacheReadTokens: r.cacheReadTokens,
|
|
9366
|
-
reqHash: createHash("sha256").update(r.key).digest("hex").slice(0, 32)
|
|
9367
|
-
}));
|
|
9370
|
+
const { records, truncated } = prepareVerifyUpload(
|
|
9371
|
+
requests,
|
|
9372
|
+
timedOut === true
|
|
9373
|
+
);
|
|
9368
9374
|
console.log(
|
|
9369
9375
|
pc2.dim(
|
|
9370
9376
|
` Sending ${records.length} request records for analysis${truncated ? " (most recent, sampled)" : ""}\u2026`
|
|
@@ -9397,7 +9403,7 @@ async function runVerify() {
|
|
|
9397
9403
|
console.log(result.verdict === "fail" ? pc2.yellow(line) : line);
|
|
9398
9404
|
console.log(
|
|
9399
9405
|
pc2.dim(
|
|
9400
|
-
"
|
|
9406
|
+
" A reviewer can clear the moderation after checking this evidence \u2014 re-run `npx whoburnedmore` anytime to check."
|
|
9401
9407
|
)
|
|
9402
9408
|
);
|
|
9403
9409
|
}
|
|
@@ -9586,7 +9592,7 @@ function printHelp() {
|
|
|
9586
9592
|
npx whoburnedmore private take yourself off the public leaderboard
|
|
9587
9593
|
npx whoburnedmore public put yourself back on it
|
|
9588
9594
|
npx whoburnedmore remove delete your usage data and stop background sync
|
|
9589
|
-
npx whoburnedmore verify
|
|
9595
|
+
npx whoburnedmore verify submit detailed usage evidence for review (never prompts or code)
|
|
9590
9596
|
npx whoburnedmore status check background-sync health (last sync, staleness)
|
|
9591
9597
|
npx whoburnedmore uninstall-sync turn off the background sync
|
|
9592
9598
|
npx whoburnedmore install-sync turn it back on after uninstalling
|
package/package.json
CHANGED