whoburnedmore 0.9.17 → 0.9.18
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 +91 -39
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -417,9 +417,19 @@ ${envEntries}
|
|
|
417
417
|
interval. Submits are idempotent server-side, so an extra run is safe. -->
|
|
418
418
|
<key>RunAtLoad</key>
|
|
419
419
|
<true/>
|
|
420
|
-
<!--
|
|
420
|
+
<!-- Standard, NOT Background. ProcessType=Background opts the job into
|
|
421
|
+
macOS I/O throttling, which is disastrous for a job whose work is almost
|
|
422
|
+
entirely reading thousands of transcript files: a full collect measured
|
|
423
|
+
~51s unthrottled vs ~197s throttled on the same machine. That blows past
|
|
424
|
+
the collector's own budgets (25s per ccusage child, 45s for the native
|
|
425
|
+
reader), so every source times out at once, entries comes back empty and
|
|
426
|
+
the tick submits nothing \u2014 it logged "Nothing to burn yet" on 206 of 473
|
|
427
|
+
runs (~44%) until this was changed. Nice=0 keeps CPU priority neighbourly
|
|
428
|
+
without throttling the reads. -->
|
|
421
429
|
<key>ProcessType</key>
|
|
422
|
-
<string>
|
|
430
|
+
<string>Standard</string>
|
|
431
|
+
<key>Nice</key>
|
|
432
|
+
<integer>0</integer>
|
|
423
433
|
<key>StandardOutPath</key>
|
|
424
434
|
<string>${xmlEscape(logPath)}</string>
|
|
425
435
|
<key>StandardErrorPath</key>
|
|
@@ -7715,9 +7725,12 @@ function finalizeCodexEntries(acc) {
|
|
|
7715
7725
|
}
|
|
7716
7726
|
return entries;
|
|
7717
7727
|
}
|
|
7718
|
-
function
|
|
7719
|
-
|
|
7720
|
-
|
|
7728
|
+
function resolveCodexHome(env = process.env) {
|
|
7729
|
+
return env.CODEX_HOME && env.CODEX_HOME.trim() ? env.CODEX_HOME.trim() : join9(homedir7(), ".codex");
|
|
7730
|
+
}
|
|
7731
|
+
function resolveCodexSessionsDirs(env = process.env) {
|
|
7732
|
+
const home = resolveCodexHome(env);
|
|
7733
|
+
return [join9(home, "sessions"), join9(home, "archived_sessions")];
|
|
7721
7734
|
}
|
|
7722
7735
|
async function listJsonl3(dir) {
|
|
7723
7736
|
let dirents;
|
|
@@ -7769,8 +7782,8 @@ function fromCachedSession(t) {
|
|
|
7769
7782
|
};
|
|
7770
7783
|
}
|
|
7771
7784
|
async function collectCodexNative(env = process.env, opts = {}) {
|
|
7772
|
-
const
|
|
7773
|
-
const files = await listJsonl3(
|
|
7785
|
+
const dirs = resolveCodexSessionsDirs(env);
|
|
7786
|
+
const files = (await Promise.all(dirs.map(listJsonl3))).flat();
|
|
7774
7787
|
if (files.length === 0) return { entries: [], found: false, filesScanned: 0 };
|
|
7775
7788
|
const now = opts.now ?? Date.now;
|
|
7776
7789
|
const res = await readFilesWithCache({
|
|
@@ -8147,6 +8160,10 @@ function reconcileProvenance(entries, agent, complete, store) {
|
|
|
8147
8160
|
|
|
8148
8161
|
// src/collect.ts
|
|
8149
8162
|
var execFileAsync = promisify(execFile);
|
|
8163
|
+
var NATIVE_COVERED_SOURCES = /* @__PURE__ */ new Set(["claude", "codex"]);
|
|
8164
|
+
var CCUSAGE_TIMEOUT_MS = 25e3;
|
|
8165
|
+
var CCUSAGE_FALLBACK_TIMEOUT_MS = NATIVE_READ_BUDGET_MS;
|
|
8166
|
+
var CCUSAGE_AGGREGATE_TIMEOUT_MS = 18e4;
|
|
8150
8167
|
var SOURCES = [
|
|
8151
8168
|
"claude",
|
|
8152
8169
|
"codex",
|
|
@@ -8342,25 +8359,39 @@ function dedupeBlocks(blocks) {
|
|
|
8342
8359
|
return [...byStart.values()];
|
|
8343
8360
|
}
|
|
8344
8361
|
function selectSourceEntries(source, ccusageEntries, native) {
|
|
8345
|
-
if (source === "claude" && native.claude
|
|
8362
|
+
if (source === "claude" && nativeReaderWon(native.claude))
|
|
8346
8363
|
return native.claude.entries;
|
|
8347
|
-
if (source === "codex" && native.codex
|
|
8364
|
+
if (source === "codex" && nativeReaderWon(native.codex))
|
|
8348
8365
|
return native.codex.entries;
|
|
8349
8366
|
return ccusageEntries;
|
|
8350
8367
|
}
|
|
8368
|
+
function nativeReaderWon(result) {
|
|
8369
|
+
return result.found && result.entries.length > 0;
|
|
8370
|
+
}
|
|
8371
|
+
function ccusageFallbackSources(native) {
|
|
8372
|
+
return SOURCES.filter(
|
|
8373
|
+
(s) => NATIVE_COVERED_SOURCES.has(s) && !nativeReaderWon(s === "claude" ? native.claude : native.codex)
|
|
8374
|
+
);
|
|
8375
|
+
}
|
|
8351
8376
|
function ccusageClaudeEnv(env = process.env) {
|
|
8352
8377
|
if (env.CLAUDE_CONFIG_DIR && env.CLAUDE_CONFIG_DIR.trim()) return env;
|
|
8353
8378
|
return { ...env, CLAUDE_CONFIG_DIR: resolveClaudeConfigRoots(env).join(",") };
|
|
8354
8379
|
}
|
|
8355
|
-
|
|
8380
|
+
function isRetryableCcusageFailure(err) {
|
|
8381
|
+
const e = err;
|
|
8382
|
+
if (e.killed === true) return false;
|
|
8383
|
+
return e.signal != null || typeof e.code === "string";
|
|
8384
|
+
}
|
|
8385
|
+
async function runCcusageOnce(cmd, args, env, timeoutMs = CCUSAGE_TIMEOUT_MS) {
|
|
8356
8386
|
try {
|
|
8357
8387
|
const { stdout } = await execFileAsync(cmd, args, {
|
|
8358
8388
|
encoding: "utf8",
|
|
8359
8389
|
maxBuffer: 64 * 1024 * 1024,
|
|
8360
|
-
// A single source shouldn't be able to hang the whole run
|
|
8361
|
-
//
|
|
8362
|
-
//
|
|
8363
|
-
|
|
8390
|
+
// A single source shouldn't be able to hang the whole run: a hung source
|
|
8391
|
+
// gets killed and (if transient) retried once below rather than stalling
|
|
8392
|
+
// everything for minutes. The claude/codex fallback passes a longer cap —
|
|
8393
|
+
// see CCUSAGE_FALLBACK_TIMEOUT_MS.
|
|
8394
|
+
timeout: timeoutMs,
|
|
8364
8395
|
...env ? { env } : {}
|
|
8365
8396
|
});
|
|
8366
8397
|
if (!stdout) return { json: null, transient: false };
|
|
@@ -8370,15 +8401,13 @@ async function runCcusageOnce(cmd, args, env) {
|
|
|
8370
8401
|
return { json: null, transient: false };
|
|
8371
8402
|
}
|
|
8372
8403
|
} catch (err) {
|
|
8373
|
-
|
|
8374
|
-
const transient = e.killed === true || e.signal != null || typeof e.code === "string";
|
|
8375
|
-
return { json: null, transient };
|
|
8404
|
+
return { json: null, transient: isRetryableCcusageFailure(err) };
|
|
8376
8405
|
}
|
|
8377
8406
|
}
|
|
8378
|
-
async function runCcusage(cmd, args, env) {
|
|
8379
|
-
const first = await runCcusageOnce(cmd, args, env);
|
|
8407
|
+
async function runCcusage(cmd, args, env, timeoutMs = CCUSAGE_TIMEOUT_MS) {
|
|
8408
|
+
const first = await runCcusageOnce(cmd, args, env, timeoutMs);
|
|
8380
8409
|
if (first.json !== null || !first.transient) return first.json;
|
|
8381
|
-
return (await runCcusageOnce(cmd, args, env)).json;
|
|
8410
|
+
return (await runCcusageOnce(cmd, args, env, timeoutMs)).json;
|
|
8382
8411
|
}
|
|
8383
8412
|
var COLLECT_STAGES = SOURCES.length + 4 + VSCODE_AGENTS.length + 1;
|
|
8384
8413
|
function isAuthoritativeScan(attributionComplete, ...fingerprintReaders) {
|
|
@@ -8397,27 +8426,39 @@ async function collectAll(onProgress) {
|
|
|
8397
8426
|
() => ({ entries: [], found: false, filesScanned: 0, timedOut: true })
|
|
8398
8427
|
);
|
|
8399
8428
|
const sourceTasks = SOURCES.map(async (source) => {
|
|
8400
|
-
|
|
8401
|
-
|
|
8402
|
-
|
|
8403
|
-
|
|
8404
|
-
|
|
8405
|
-
|
|
8429
|
+
if (NATIVE_COVERED_SOURCES.has(source)) {
|
|
8430
|
+
await (source === "claude" ? nativeClaudeTask : nativeCodexTask);
|
|
8431
|
+
tick();
|
|
8432
|
+
return { source, mapped: [] };
|
|
8433
|
+
}
|
|
8434
|
+
const json = await runCcusage(cmd, [
|
|
8435
|
+
...prefixArgs,
|
|
8436
|
+
source,
|
|
8437
|
+
"daily",
|
|
8438
|
+
"--json",
|
|
8439
|
+
"--offline"
|
|
8440
|
+
]);
|
|
8406
8441
|
tick();
|
|
8407
8442
|
return { source, mapped: json ? mapCcusageDaily(source, json) : [] };
|
|
8408
8443
|
});
|
|
8409
|
-
const sessionTask = runCcusage(
|
|
8410
|
-
|
|
8411
|
-
|
|
8412
|
-
|
|
8413
|
-
|
|
8414
|
-
)
|
|
8415
|
-
|
|
8416
|
-
(json)
|
|
8417
|
-
|
|
8418
|
-
|
|
8419
|
-
|
|
8420
|
-
|
|
8444
|
+
const sessionTask = runCcusage(
|
|
8445
|
+
cmd,
|
|
8446
|
+
[...prefixArgs, "session", "--json", "--offline"],
|
|
8447
|
+
void 0,
|
|
8448
|
+
CCUSAGE_AGGREGATE_TIMEOUT_MS
|
|
8449
|
+
).then((json) => {
|
|
8450
|
+
tick();
|
|
8451
|
+
return json ? mapCcusageSessions(json) : [];
|
|
8452
|
+
});
|
|
8453
|
+
const blockTask = runCcusage(
|
|
8454
|
+
cmd,
|
|
8455
|
+
[...prefixArgs, "blocks", "--json", "--offline"],
|
|
8456
|
+
void 0,
|
|
8457
|
+
CCUSAGE_AGGREGATE_TIMEOUT_MS
|
|
8458
|
+
).then((json) => {
|
|
8459
|
+
tick();
|
|
8460
|
+
return json ? mapCcusageBlocks(json) : [];
|
|
8461
|
+
});
|
|
8421
8462
|
const cursorTask = collectCursor().then((c) => {
|
|
8422
8463
|
tick();
|
|
8423
8464
|
return c;
|
|
@@ -8458,10 +8499,21 @@ async function collectAll(onProgress) {
|
|
|
8458
8499
|
continueTask
|
|
8459
8500
|
]);
|
|
8460
8501
|
const native = { claude: nativeClaude, codex: nativeCodex };
|
|
8502
|
+
const fallbacks = /* @__PURE__ */ new Map();
|
|
8503
|
+
for (const source of ccusageFallbackSources(native)) {
|
|
8504
|
+
const json = await runCcusage(
|
|
8505
|
+
cmd,
|
|
8506
|
+
[...prefixArgs, source, "daily", "--json", "--offline"],
|
|
8507
|
+
// For Claude, force ccusage to scan both config roots (dual-dir hardening).
|
|
8508
|
+
source === "claude" ? ccusageClaudeEnv() : void 0,
|
|
8509
|
+
CCUSAGE_FALLBACK_TIMEOUT_MS
|
|
8510
|
+
);
|
|
8511
|
+
fallbacks.set(source, json ? mapCcusageDaily(source, json) : []);
|
|
8512
|
+
}
|
|
8461
8513
|
const entries = [];
|
|
8462
8514
|
const toolsFound = [];
|
|
8463
8515
|
for (const { source, mapped } of sourceResults) {
|
|
8464
|
-
const chosen = selectSourceEntries(source, mapped, native);
|
|
8516
|
+
const chosen = selectSourceEntries(source, fallbacks.get(source) ?? mapped, native);
|
|
8465
8517
|
if (chosen.length > 0) {
|
|
8466
8518
|
entries.push(...chosen);
|
|
8467
8519
|
toolsFound.push(source);
|
package/package.json
CHANGED