llm-usage-metrics 0.12.0 → 0.12.1
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 +138 -66
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -73,7 +73,13 @@ function compareByCodePoint(left, right) {
|
|
|
73
73
|
// packages/core/src/domain/provider-normalization.ts
|
|
74
74
|
var billingProviderAliases = /* @__PURE__ */ new Map([
|
|
75
75
|
["openai-codex", "openai"],
|
|
76
|
-
["github-copilot", "github"]
|
|
76
|
+
["github-copilot", "github"],
|
|
77
|
+
// Built-in pi providers that bill through another vendor's API.
|
|
78
|
+
["claude-bridge", "anthropic"],
|
|
79
|
+
["google-gemini-cli", "google"],
|
|
80
|
+
["google-antigravity", "google"],
|
|
81
|
+
["deepseek-official", "deepseek"],
|
|
82
|
+
["kimi-coding", "moonshot"]
|
|
77
83
|
]);
|
|
78
84
|
var billingProviderPrefixAliases = [
|
|
79
85
|
["openai-", "openai"],
|
|
@@ -230,7 +236,7 @@ function normalizeTimestamp(value) {
|
|
|
230
236
|
}
|
|
231
237
|
|
|
232
238
|
// packages/core/src/domain/usage-event.ts
|
|
233
|
-
var USAGE_EVENT_NORMALIZATION_VERSION =
|
|
239
|
+
var USAGE_EVENT_NORMALIZATION_VERSION = 4;
|
|
234
240
|
function normalizeSourceId(value) {
|
|
235
241
|
if (typeof value !== "string") {
|
|
236
242
|
return void 0;
|
|
@@ -1993,6 +1999,29 @@ function computeActiveMs(timestampsMs) {
|
|
|
1993
1999
|
}
|
|
1994
2000
|
return activeMs;
|
|
1995
2001
|
}
|
|
2002
|
+
function computeUnionActiveMs(timestampLists) {
|
|
2003
|
+
const intervals = [];
|
|
2004
|
+
for (const timestamps of timestampLists) {
|
|
2005
|
+
const sorted = [...timestamps].sort((left, right) => left - right);
|
|
2006
|
+
for (let index = 1; index < sorted.length; index += 1) {
|
|
2007
|
+
const start = sorted[index - 1];
|
|
2008
|
+
const end = Math.min(sorted[index], start + IDLE_GAP_CAP_MS);
|
|
2009
|
+
if (end > start) {
|
|
2010
|
+
intervals.push([start, end]);
|
|
2011
|
+
}
|
|
2012
|
+
}
|
|
2013
|
+
}
|
|
2014
|
+
intervals.sort((left, right) => left[0] - right[0]);
|
|
2015
|
+
let activeMs = 0;
|
|
2016
|
+
let coveredUntil = Number.NEGATIVE_INFINITY;
|
|
2017
|
+
for (const [start, end] of intervals) {
|
|
2018
|
+
if (end > coveredUntil) {
|
|
2019
|
+
activeMs += end - Math.max(start, coveredUntil);
|
|
2020
|
+
coveredUntil = end;
|
|
2021
|
+
}
|
|
2022
|
+
}
|
|
2023
|
+
return activeMs;
|
|
2024
|
+
}
|
|
1996
2025
|
|
|
1997
2026
|
// packages/core/src/sources/source-context.ts
|
|
1998
2027
|
import os from "os";
|
|
@@ -3043,7 +3072,11 @@ function readSchemaVersion(database) {
|
|
|
3043
3072
|
return void 0;
|
|
3044
3073
|
}
|
|
3045
3074
|
const schemaVersionRow = database.prepare("SELECT value FROM meta WHERE key = 'schemaVersion'").get();
|
|
3046
|
-
|
|
3075
|
+
const schemaVersion = toText(schemaVersionRow?.value);
|
|
3076
|
+
return schemaVersion === "5" && tableNames.has("events") && !hasEventsFileIdColumn(database) ? "4" : schemaVersion;
|
|
3077
|
+
}
|
|
3078
|
+
function hasEventsFileIdColumn(database) {
|
|
3079
|
+
return database.prepare("SELECT name FROM pragma_table_info(?)").all("events").some((row) => row.name === "file_id");
|
|
3047
3080
|
}
|
|
3048
3081
|
function createFreshSchema(database) {
|
|
3049
3082
|
database.exec(createSchemaSql());
|
|
@@ -3144,6 +3177,8 @@ function migrateSchemaV4ToV5(database) {
|
|
|
3144
3177
|
ALTER TABLE files RENAME TO v4_files;
|
|
3145
3178
|
ALTER TABLE events RENAME TO v4_events;
|
|
3146
3179
|
DROP INDEX IF EXISTS events_content_hash;
|
|
3180
|
+
DROP TABLE IF EXISTS tool_calls;
|
|
3181
|
+
DROP TABLE IF EXISTS messages;
|
|
3147
3182
|
${createFileTablesSql()}
|
|
3148
3183
|
INSERT INTO files (source, file_path, fingerprint, skipped_rows, skipped_row_reasons, ingested_at)
|
|
3149
3184
|
SELECT source, file_path, fingerprint, skipped_rows, skipped_row_reasons, ingested_at
|
|
@@ -3566,8 +3601,7 @@ async function readEventStoreSummary(filePath = getDefaultEventStorePath(), load
|
|
|
3566
3601
|
timeout: EVENT_STORE_OPEN_TIMEOUT_MS
|
|
3567
3602
|
});
|
|
3568
3603
|
try {
|
|
3569
|
-
const
|
|
3570
|
-
const schemaVersion = toText(schemaVersionRow?.value);
|
|
3604
|
+
const schemaVersion = readSchemaVersion(database);
|
|
3571
3605
|
const countRows = (tableName) => toNonNegativeInteger(
|
|
3572
3606
|
database.prepare(`SELECT COUNT(*) AS count FROM ${tableName}`).get()?.count
|
|
3573
3607
|
) ?? 0;
|
|
@@ -3713,11 +3747,12 @@ async function readEventStoreEvents(filePath, window = {}, loadSqliteModule = lo
|
|
|
3713
3747
|
try {
|
|
3714
3748
|
assertSupportedSchemaVersion(database);
|
|
3715
3749
|
const meta = readMetaValues(database);
|
|
3750
|
+
const schemaVersion = readSchemaVersion(database);
|
|
3716
3751
|
const fromTimestamp = window.fromTimestamp ?? "";
|
|
3717
3752
|
const toTimestamp = window.toTimestamp ?? "\uFFFF";
|
|
3718
3753
|
const wideWindow = isWideWindow(database, fromTimestamp, toTimestamp);
|
|
3719
3754
|
const statement = database.prepare(
|
|
3720
|
-
hasSchemaVersion(
|
|
3755
|
+
hasSchemaVersion(schemaVersion, 5) ? selectWindowEventsSql(wideWindow) : selectPreV5WindowEventsSql(schemaVersion, wideWindow)
|
|
3721
3756
|
);
|
|
3722
3757
|
statement.setReturnArrays(true);
|
|
3723
3758
|
const rows = statement.all(fromTimestamp, toTimestamp);
|
|
@@ -3744,7 +3779,7 @@ async function readStoredSessionEvents(filePath, files, kinds, loadSqliteModule
|
|
|
3744
3779
|
timeout: EVENT_STORE_OPEN_TIMEOUT_MS
|
|
3745
3780
|
});
|
|
3746
3781
|
try {
|
|
3747
|
-
const schemaVersion =
|
|
3782
|
+
const schemaVersion = readSchemaVersion(database);
|
|
3748
3783
|
if (!hasSchemaVersion(schemaVersion, 5)) {
|
|
3749
3784
|
throw new EventStoreSchemaVersionError(schemaVersion);
|
|
3750
3785
|
}
|
|
@@ -6183,8 +6218,22 @@ function stripTrailingSeparators(value) {
|
|
|
6183
6218
|
}
|
|
6184
6219
|
return value.slice(0, end);
|
|
6185
6220
|
}
|
|
6221
|
+
function stripDependencyPath(value) {
|
|
6222
|
+
let cut = value.length;
|
|
6223
|
+
for (const separator of ["/", "\\"]) {
|
|
6224
|
+
const needle = `${separator}node_modules`;
|
|
6225
|
+
for (let index = value.indexOf(needle); index >= 0; index = value.indexOf(needle, index + 1)) {
|
|
6226
|
+
const end = index + needle.length;
|
|
6227
|
+
if (end === value.length || isSeparator(value[end])) {
|
|
6228
|
+
cut = Math.min(cut, index);
|
|
6229
|
+
break;
|
|
6230
|
+
}
|
|
6231
|
+
}
|
|
6232
|
+
}
|
|
6233
|
+
return cut < value.length && isBareRoot(value.slice(0, cut + 1)) ? value.slice(0, cut + 1) : value.slice(0, cut);
|
|
6234
|
+
}
|
|
6186
6235
|
function toProjectKey(repoRoot) {
|
|
6187
|
-
return repoRoot === void 0 ? void 0 : stripTrailingSeparators(repoRoot);
|
|
6236
|
+
return repoRoot === void 0 ? void 0 : stripDependencyPath(stripTrailingSeparators(repoRoot));
|
|
6188
6237
|
}
|
|
6189
6238
|
function toProjectLabel(repoRoot, labels) {
|
|
6190
6239
|
return labels.get(toProjectKey(repoRoot)) ?? UNATTRIBUTED_PROJECT_LABEL;
|
|
@@ -42892,13 +42941,15 @@ async function buildUsageEventDataset(options, deps = {}, request = {}) {
|
|
|
42892
42941
|
(failure.stale ? machineWarnings : machineNotes).push(failure.text);
|
|
42893
42942
|
}
|
|
42894
42943
|
}
|
|
42895
|
-
|
|
42896
|
-
|
|
42897
|
-
|
|
42898
|
-
|
|
42899
|
-
|
|
42900
|
-
|
|
42901
|
-
|
|
42944
|
+
if (machineUsage.machines.length > 0) {
|
|
42945
|
+
machineNotes.push(
|
|
42946
|
+
formatMachinesNote(
|
|
42947
|
+
machineUsage.machines,
|
|
42948
|
+
nowMs(),
|
|
42949
|
+
loadPackageMetadataFromRuntime().packageVersion
|
|
42950
|
+
)
|
|
42951
|
+
);
|
|
42952
|
+
}
|
|
42902
42953
|
}
|
|
42903
42954
|
const sessionCopyingSources = getSessionCopyingSourceIds(adaptersToParse);
|
|
42904
42955
|
parseResultsForFiltering = measureRuntimeProfileStageSync(
|
|
@@ -44337,7 +44388,7 @@ function formatBurnRate(active, options) {
|
|
|
44337
44388
|
}
|
|
44338
44389
|
function buildFooterLines(data, options) {
|
|
44339
44390
|
const lines = [
|
|
44340
|
-
`Blocks are estimated: each starts
|
|
44391
|
+
`Blocks are estimated: each starts on the whole UTC hour at or before a source's first event after the previous block and lasts ${String(data.blockHours)} hours, across machines. Times are in ${data.timezone}.`
|
|
44341
44392
|
];
|
|
44342
44393
|
if (data.blocks.some((row) => row.startUncertain)) {
|
|
44343
44394
|
lines.push(
|
|
@@ -46716,7 +46767,7 @@ function formatDeltaUsd(value, options = {}) {
|
|
|
46716
46767
|
}
|
|
46717
46768
|
const sign = options.signed && value !== 0 ? value > 0 ? "+" : "-" : "";
|
|
46718
46769
|
const formatted = formatUsd(Math.abs(value));
|
|
46719
|
-
return `${options.approximate ? "~" : ""}${
|
|
46770
|
+
return `${sign}${options.approximate ? "~" : ""}${formatted}`;
|
|
46720
46771
|
}
|
|
46721
46772
|
function formatPercent(value) {
|
|
46722
46773
|
if (value === void 0) {
|
|
@@ -47901,7 +47952,7 @@ function toPressureCells(row) {
|
|
|
47901
47952
|
];
|
|
47902
47953
|
}
|
|
47903
47954
|
function formatOptionalInteger(value) {
|
|
47904
|
-
return value === void 0 ? "" : formatInteger(value);
|
|
47955
|
+
return value === void 0 ? "-" : formatInteger(value);
|
|
47905
47956
|
}
|
|
47906
47957
|
function buildModelTable(rows) {
|
|
47907
47958
|
return {
|
|
@@ -48835,12 +48886,19 @@ async function isGitRepository(repoDir, runCommand) {
|
|
|
48835
48886
|
throw error;
|
|
48836
48887
|
}
|
|
48837
48888
|
);
|
|
48838
|
-
return gitRepoResult.exitCode === 0;
|
|
48889
|
+
return gitRepoResult.exitCode === 0 && gitRepoResult.lines[0]?.trim() === "true";
|
|
48839
48890
|
}
|
|
48840
48891
|
function notGitRepositoryMessage(repoDir, repoDirOption) {
|
|
48841
48892
|
const hint = repoDirOption === void 0 ? "<path>" : "<path to a git repository>";
|
|
48842
48893
|
return `${repoDir} is not a git repository; pass --repo-dir ${hint}`;
|
|
48843
48894
|
}
|
|
48895
|
+
async function assertGitRepositoryDir(repoDirOption) {
|
|
48896
|
+
const repoDir = resolveRepoDir(repoDirOption);
|
|
48897
|
+
await assertRepoDirReadable(repoDir);
|
|
48898
|
+
if (!await isGitRepository(repoDir, runGitCommand)) {
|
|
48899
|
+
throw new Error(notGitRepositoryMessage(repoDir, repoDirOption));
|
|
48900
|
+
}
|
|
48901
|
+
}
|
|
48844
48902
|
function isNoCommitHistoryFailure(result) {
|
|
48845
48903
|
if (result.exitCode !== 128) {
|
|
48846
48904
|
return false;
|
|
@@ -49111,21 +49169,11 @@ async function collectGitOutcomes(options, deps = {}) {
|
|
|
49111
49169
|
const repoDir = resolveRepoDir(options.repoDir);
|
|
49112
49170
|
const includeMergeCommits = options.includeMergeCommits ?? false;
|
|
49113
49171
|
const runCommand = deps.runGitCommand ?? runGitCommand;
|
|
49114
|
-
if (options.activeUsageDays?.size === 0) {
|
|
49115
|
-
const emptyCollection = createEmptyOutcomeCollection(repoDir, includeMergeCommits);
|
|
49116
|
-
if (!deps.runGitCommand) {
|
|
49117
|
-
await assertRepoDirReadable(repoDir);
|
|
49118
|
-
if (!await isGitRepository(repoDir, runCommand)) {
|
|
49119
|
-
emptyCollection.warning = notGitRepositoryMessage(repoDir, options.repoDir);
|
|
49120
|
-
}
|
|
49121
|
-
}
|
|
49122
|
-
return emptyCollection;
|
|
49123
|
-
}
|
|
49124
49172
|
if (!deps.runGitCommand) {
|
|
49125
|
-
await
|
|
49126
|
-
|
|
49127
|
-
|
|
49128
|
-
|
|
49173
|
+
await assertGitRepositoryDir(options.repoDir);
|
|
49174
|
+
}
|
|
49175
|
+
if (options.activeUsageDays?.size === 0) {
|
|
49176
|
+
return createEmptyOutcomeCollection(repoDir, includeMergeCommits);
|
|
49129
49177
|
}
|
|
49130
49178
|
let authorEmail;
|
|
49131
49179
|
try {
|
|
@@ -49293,6 +49341,9 @@ async function buildEfficiencyData(granularity, options, deps = {}) {
|
|
|
49293
49341
|
if (options.repoDir !== void 0 && !repoDir) {
|
|
49294
49342
|
throw new Error("--repo-dir must be a non-empty path");
|
|
49295
49343
|
}
|
|
49344
|
+
if (!deps.collectGitOutcomes) {
|
|
49345
|
+
await assertGitRepositoryDir(repoDir);
|
|
49346
|
+
}
|
|
49296
49347
|
const dataset = await measureRuntimeProfileStage(
|
|
49297
49348
|
deps.runtimeProfile,
|
|
49298
49349
|
"efficiency.dataset.total",
|
|
@@ -49351,7 +49402,7 @@ async function buildEfficiencyData(granularity, options, deps = {}) {
|
|
|
49351
49402
|
sourceFailures: dataset.sourceFailures,
|
|
49352
49403
|
pricingOrigin,
|
|
49353
49404
|
pricingWarning,
|
|
49354
|
-
warnings:
|
|
49405
|
+
warnings: dataset.warnings,
|
|
49355
49406
|
// The pricing stats are keyed by the priced events, not attribution's copies.
|
|
49356
49407
|
notes: withPricingNotes(
|
|
49357
49408
|
dataset.notes,
|
|
@@ -49438,7 +49489,7 @@ function emitEfficiencyReportDiagnostics(diagnostics) {
|
|
|
49438
49489
|
`Git outcomes (${mergeModeLabel}): ${pluralize(diagnostics.gitCommitCount, "commit")}, +${diagnostics.gitLinesAdded}/-${diagnostics.gitLinesDeleted} lines (${diagnostics.repoDir})`
|
|
49439
49490
|
);
|
|
49440
49491
|
logger.info(
|
|
49441
|
-
`Repo-attributed usage events: ${diagnostics.repoMatchedUsageEvents} matched, ${diagnostics.repoExcludedUsageEvents} excluded, ${diagnostics.repoUnattributedUsageEvents} unattributed`
|
|
49492
|
+
`Repo-attributed usage events: ${formatInteger(diagnostics.repoMatchedUsageEvents)} matched, ${formatInteger(diagnostics.repoExcludedUsageEvents)} excluded, ${formatInteger(diagnostics.repoUnattributedUsageEvents)} unattributed`
|
|
49442
49493
|
);
|
|
49443
49494
|
if (diagnostics.scopeNote) {
|
|
49444
49495
|
logger.warn(diagnostics.scopeNote);
|
|
@@ -51371,6 +51422,15 @@ function toCounts(accumulator) {
|
|
|
51371
51422
|
sessions: accumulator.sessions.size
|
|
51372
51423
|
};
|
|
51373
51424
|
}
|
|
51425
|
+
function findDisplayName(callsByName) {
|
|
51426
|
+
let top;
|
|
51427
|
+
for (const entry of callsByName) {
|
|
51428
|
+
if (top === void 0 || entry[1] > top[1] || entry[1] === top[1] && compareByCodePoint(entry[0], top[0]) < 0) {
|
|
51429
|
+
top = entry;
|
|
51430
|
+
}
|
|
51431
|
+
}
|
|
51432
|
+
return top?.[0] ?? "";
|
|
51433
|
+
}
|
|
51374
51434
|
function findTopRepoRoot(callsByRepoRoot) {
|
|
51375
51435
|
let top;
|
|
51376
51436
|
for (const entry of callsByRepoRoot) {
|
|
@@ -51398,12 +51458,13 @@ function aggregateTools(calls, options) {
|
|
|
51398
51458
|
const repoRoot = toProjectKey(options.sessionRepoRoots.get(sessionKey)) ?? null;
|
|
51399
51459
|
const source = options.bySource ? call.source : void 0;
|
|
51400
51460
|
const rowRepoRoot = options.byRepo ? repoRoot : void 0;
|
|
51401
|
-
const
|
|
51461
|
+
const foldedName = call.name.toLowerCase();
|
|
51462
|
+
const key = [foldedName, source ?? "", rowRepoRoot ?? ""].join("\0");
|
|
51402
51463
|
let row = rows.get(key);
|
|
51403
51464
|
if (!row) {
|
|
51404
51465
|
row = {
|
|
51405
51466
|
...createCountAccumulator(),
|
|
51406
|
-
|
|
51467
|
+
callsByName: /* @__PURE__ */ new Map(),
|
|
51407
51468
|
...source === void 0 ? {} : { source },
|
|
51408
51469
|
...rowRepoRoot === void 0 ? {} : { repoRoot: rowRepoRoot },
|
|
51409
51470
|
callsByRepoRoot: /* @__PURE__ */ new Map()
|
|
@@ -51411,12 +51472,13 @@ function aggregateTools(calls, options) {
|
|
|
51411
51472
|
rows.set(key, row);
|
|
51412
51473
|
}
|
|
51413
51474
|
addCall(row, call, sessionKey);
|
|
51475
|
+
row.callsByName.set(call.name, (row.callsByName.get(call.name) ?? 0) + 1);
|
|
51414
51476
|
row.callsByRepoRoot.set(repoRoot, (row.callsByRepoRoot.get(repoRoot) ?? 0) + 1);
|
|
51415
51477
|
addCall(totals, call, sessionKey);
|
|
51416
|
-
names.add(
|
|
51478
|
+
names.add(foldedName);
|
|
51417
51479
|
}
|
|
51418
51480
|
const toolRows = [...rows.values()].map((row) => ({
|
|
51419
|
-
name: row.
|
|
51481
|
+
name: findDisplayName(row.callsByName),
|
|
51420
51482
|
...row.source === void 0 ? {} : { source: row.source },
|
|
51421
51483
|
...row.repoRoot === void 0 ? {} : { repoRoot: row.repoRoot },
|
|
51422
51484
|
...toCounts(row),
|
|
@@ -53310,38 +53372,49 @@ function sumActiveMsByDay(events, timezone, groupOf) {
|
|
|
53310
53372
|
sessionsByDate.set(dateKey, sessions);
|
|
53311
53373
|
}
|
|
53312
53374
|
const rows = [];
|
|
53375
|
+
const combinedByDay = /* @__PURE__ */ new Map();
|
|
53313
53376
|
for (const [periodKey, sessions] of sessionsByDate) {
|
|
53314
|
-
const
|
|
53377
|
+
const runsByGroup = /* @__PURE__ */ new Map();
|
|
53378
|
+
const sessionTimestamps = [];
|
|
53315
53379
|
for (const sessionEvents of sessions.values()) {
|
|
53316
53380
|
sessionEvents.sort((left, right) => left.timestampMs - right.timestampMs);
|
|
53381
|
+
sessionTimestamps.push(sessionEvents.map((entry) => entry.timestampMs));
|
|
53317
53382
|
let runStart = 0;
|
|
53318
53383
|
for (let index = 1; index <= sessionEvents.length; index += 1) {
|
|
53319
53384
|
const group = sessionEvents[runStart].group;
|
|
53320
53385
|
if (index < sessionEvents.length && sessionEvents[index].group === group) {
|
|
53321
53386
|
continue;
|
|
53322
53387
|
}
|
|
53323
|
-
const
|
|
53324
|
-
|
|
53325
|
-
);
|
|
53326
|
-
activeMsByGroup.set(group, (activeMsByGroup.get(group) ?? 0) + runMs);
|
|
53388
|
+
const runs = runsByGroup.get(group) ?? [];
|
|
53389
|
+
runs.push(sessionEvents.slice(runStart, index).map((entry) => entry.timestampMs));
|
|
53390
|
+
runsByGroup.set(group, runs);
|
|
53327
53391
|
runStart = index;
|
|
53328
53392
|
}
|
|
53329
53393
|
}
|
|
53330
|
-
for (const [group,
|
|
53331
|
-
rows.push({ periodKey, group, value });
|
|
53394
|
+
for (const [group, runs] of runsByGroup) {
|
|
53395
|
+
rows.push({ periodKey, group, value: computeUnionActiveMs(runs) });
|
|
53332
53396
|
}
|
|
53397
|
+
combinedByDay.set(periodKey, computeUnionActiveMs(sessionTimestamps));
|
|
53333
53398
|
}
|
|
53334
|
-
return rows;
|
|
53399
|
+
return { rows, combinedByDay };
|
|
53335
53400
|
}
|
|
53336
53401
|
function toActiveTimeValueRows(events, timezone) {
|
|
53337
|
-
|
|
53402
|
+
const { rows, combinedByDay } = sumActiveMsByDay(events, timezone, (event) => event.source);
|
|
53403
|
+
const sourceRows = rows.map((row) => ({
|
|
53338
53404
|
periodKey: row.periodKey,
|
|
53339
53405
|
source: row.group,
|
|
53340
53406
|
value: row.value
|
|
53341
53407
|
}));
|
|
53408
|
+
const combinedRows = [...combinedByDay].map(([periodKey, value]) => ({
|
|
53409
|
+
periodKey,
|
|
53410
|
+
source: "combined",
|
|
53411
|
+
value
|
|
53412
|
+
}));
|
|
53413
|
+
return [...sourceRows, ...combinedRows];
|
|
53342
53414
|
}
|
|
53343
53415
|
function toActiveTimeProjectValueRows(events, timezone, projectLabels) {
|
|
53344
|
-
|
|
53416
|
+
const { rows } = sumActiveMsByDay(events, timezone, (event) => toProjectKey(event.repoRoot));
|
|
53417
|
+
return rows.map((row) => {
|
|
53345
53418
|
const project = projectLabels.get(row.group);
|
|
53346
53419
|
if (project === void 0) {
|
|
53347
53420
|
throw new Error(`No project label for ${row.group ?? "unattributed usage"}`);
|
|
@@ -55118,9 +55191,10 @@ function toCsvLine(event) {
|
|
|
55118
55191
|
event.cacheWrite1hTokens
|
|
55119
55192
|
].map(toCsvField).join(",");
|
|
55120
55193
|
}
|
|
55121
|
-
async function runEventsReport(
|
|
55122
|
-
const format = resolveEventsFormat(
|
|
55123
|
-
const pushTarget = resolveOtlpPushTarget(
|
|
55194
|
+
async function runEventsReport(commandOptions, commandDeps = {}) {
|
|
55195
|
+
const format = resolveEventsFormat(commandOptions);
|
|
55196
|
+
const pushTarget = resolveOtlpPushTarget(commandOptions);
|
|
55197
|
+
const { options, deps } = commandOptions.last === void 0 ? { options: commandOptions, deps: commandDeps } : await resolveUsageDataRequest("daily", commandOptions, commandDeps);
|
|
55124
55198
|
const dataset = await buildUsageEventDataset(options, deps);
|
|
55125
55199
|
const { pricedEvents, pricingOrigin, pricingWarning } = await applyPricingToUsageEventDataset(
|
|
55126
55200
|
dataset,
|
|
@@ -55156,16 +55230,16 @@ async function runEventsReport(options, deps = {}) {
|
|
|
55156
55230
|
timezone: dataset.normalizedInputs.timezone,
|
|
55157
55231
|
nowMs: (deps.now?.() ?? /* @__PURE__ */ new Date()).getTime()
|
|
55158
55232
|
});
|
|
55159
|
-
await writeOtlp({ kind: "metrics", lines }, pushTarget,
|
|
55233
|
+
await writeOtlp({ kind: "metrics", lines }, pushTarget, commandDeps);
|
|
55160
55234
|
return;
|
|
55161
55235
|
}
|
|
55162
55236
|
if (toolCalls) {
|
|
55163
55237
|
const lines = buildOtlpTraces({
|
|
55164
55238
|
usageEvents: sortedEvents,
|
|
55165
55239
|
toolCalls: dedupeToolCalls(toolCalls.events),
|
|
55166
|
-
includePaths:
|
|
55240
|
+
includePaths: commandOptions.otelIncludePaths
|
|
55167
55241
|
});
|
|
55168
|
-
await writeOtlp({ kind: "traces", lines }, pushTarget,
|
|
55242
|
+
await writeOtlp({ kind: "traces", lines }, pushTarget, commandDeps);
|
|
55169
55243
|
return;
|
|
55170
55244
|
}
|
|
55171
55245
|
if (format === "csv") {
|
|
@@ -55609,10 +55683,7 @@ function aggregateWrapped(events, options) {
|
|
|
55609
55683
|
}
|
|
55610
55684
|
}
|
|
55611
55685
|
const sortedDateKeys = [...activeDateKeys].sort(compareByCodePoint);
|
|
55612
|
-
|
|
55613
|
-
for (const timestamps of sessionTimestamps.values()) {
|
|
55614
|
-
activeMs += computeActiveMs(timestamps);
|
|
55615
|
-
}
|
|
55686
|
+
const activeMs = computeUnionActiveMs(sessionTimestamps.values());
|
|
55616
55687
|
let peakHour;
|
|
55617
55688
|
for (let hour = 0; hour < hourTokens.length; hour += 1) {
|
|
55618
55689
|
if (hourTokens[hour] > 0 && (peakHour === void 0 || hourTokens[hour] > peakHour.totalTokens)) {
|
|
@@ -57040,7 +57111,7 @@ var eventsReportDefinition = {
|
|
|
57040
57111
|
).option(
|
|
57041
57112
|
"--otlp-endpoint <url>",
|
|
57042
57113
|
"With an OTLP format: POST to <url>/v1/traces or /v1/metrics (unless <url> already ends with it) instead of printing; headers from OTEL_EXPORTER_OTLP_HEADERS"
|
|
57043
|
-
);
|
|
57114
|
+
).option("--last <n>", "Export the last N days, counting today");
|
|
57044
57115
|
addFullHistoryOption(command);
|
|
57045
57116
|
addRepoFilterOption(command).action(
|
|
57046
57117
|
(options) => runEventsReport(options)
|
|
@@ -58177,6 +58248,7 @@ async function runMachineList(deps = {}) {
|
|
|
58177
58248
|
}
|
|
58178
58249
|
async function runSync(names, options, deps = {}) {
|
|
58179
58250
|
const print = deps.print ?? console.log;
|
|
58251
|
+
const printError = deps.printError ?? console.error;
|
|
58180
58252
|
const machines = await loadConfiguredMachines();
|
|
58181
58253
|
const unknownNames = names.filter((name) => !Object.hasOwn(machines, name));
|
|
58182
58254
|
if (unknownNames.length > 0) {
|
|
@@ -58203,7 +58275,7 @@ async function runSync(names, options, deps = {}) {
|
|
|
58203
58275
|
now: deps.now
|
|
58204
58276
|
});
|
|
58205
58277
|
for (const line of renderSyncOutcome(outcome, (deps.now ?? Date.now)())) {
|
|
58206
|
-
print(line);
|
|
58278
|
+
(outcome.ok ? print : printError)(line);
|
|
58207
58279
|
}
|
|
58208
58280
|
return outcome;
|
|
58209
58281
|
})
|
|
@@ -63125,23 +63197,23 @@ var schemaDocuments = {
|
|
|
63125
63197
|
// src/cli/create-schema-command.ts
|
|
63126
63198
|
var schemaNames = Object.keys(schemaDocuments).sort();
|
|
63127
63199
|
function createSchemaCommand() {
|
|
63128
|
-
return new Command5("schema").description("Print a bundled report JSON Schema").argument("[name]", `Schema name: ${schemaNames.join(", ")}`).option("--list", "List available schema names").addHelpText(
|
|
63200
|
+
return new Command5("schema").description("Print a bundled report JSON Schema").argument("[name]", `Schema name: ${schemaNames.join(", ")}`).option("--list", "List available schema names (the default without a name)").addHelpText(
|
|
63129
63201
|
"after",
|
|
63130
63202
|
formatHelpExamples([
|
|
63131
63203
|
"llm-usage schema --list",
|
|
63132
63204
|
"llm-usage schema summary > summary.schema.json"
|
|
63133
63205
|
])
|
|
63134
63206
|
).action((name, options) => {
|
|
63135
|
-
if (options.list) {
|
|
63207
|
+
if (options.list || name === void 0) {
|
|
63136
63208
|
for (const schemaName of schemaNames) {
|
|
63137
63209
|
console.log(schemaName);
|
|
63138
63210
|
}
|
|
63139
63211
|
return;
|
|
63140
63212
|
}
|
|
63141
|
-
const schema =
|
|
63213
|
+
const schema = schemaDocuments[name];
|
|
63142
63214
|
if (schema === void 0) {
|
|
63143
63215
|
throw new Error(
|
|
63144
|
-
`Unknown schema "${name
|
|
63216
|
+
`Unknown schema "${name}"; valid names: ${schemaNames.join(", ")} (or --list)`
|
|
63145
63217
|
);
|
|
63146
63218
|
}
|
|
63147
63219
|
console.log(JSON.stringify(schema, null, 2));
|
|
@@ -63314,7 +63386,7 @@ var currentWorkerData = workerData;
|
|
|
63314
63386
|
var mainPromise = !isMainThread && isParseWorkerRequest(currentWorkerData) ? runParseWorker() : runCli();
|
|
63315
63387
|
mainPromise.catch((error) => {
|
|
63316
63388
|
const message = error instanceof Error ? error.message : String(error);
|
|
63317
|
-
console.error(message);
|
|
63389
|
+
console.error(`error: ${message}`);
|
|
63318
63390
|
process.exitCode = 1;
|
|
63319
63391
|
});
|
|
63320
63392
|
/*! Bundled license information:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "llm-usage-metrics",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.1",
|
|
4
4
|
"description": "CLI for aggregating local LLM usage metrics from pi, codex, gemini, droid, opencode, openclaw, claude, copilot, goose, amp, qwen, kimi, cline, roocode, kilocode, antigravity, and deepseek harness sessions",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"packageManager": "pnpm@12.9.1",
|