llm-usage-metrics 0.7.0 → 0.7.2
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/README.md +12 -7
- package/dist/index.js +411 -102
- package/dist/index.js.map +1 -1
- package/package.json +4 -3
package/dist/index.js
CHANGED
|
@@ -106,9 +106,6 @@ function getParsingRuntimeConfig(env = process.env) {
|
|
|
106
106
|
};
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
-
// src/update/update-notifier.ts
|
|
110
|
-
import { spawn as spawn2 } from "child_process";
|
|
111
|
-
|
|
112
109
|
// src/update/update-cache-repository.ts
|
|
113
110
|
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
114
111
|
import path2 from "path";
|
|
@@ -529,7 +526,6 @@ async function runInteractiveInstallAndRestart(options) {
|
|
|
529
526
|
|
|
530
527
|
// src/update/update-notifier.ts
|
|
531
528
|
var UPDATE_CHECK_SKIP_ENV_VAR = "LLM_USAGE_SKIP_UPDATE_CHECK";
|
|
532
|
-
var UPDATE_CHECK_REFRESH_ENV_VAR = "LLM_USAGE_REFRESH_UPDATE_CHECK";
|
|
533
529
|
function isTruthyEnvFlag(value) {
|
|
534
530
|
if (value === void 0) {
|
|
535
531
|
return false;
|
|
@@ -588,32 +584,6 @@ function toResolveLatestVersionOptions(options, env) {
|
|
|
588
584
|
now: options.now
|
|
589
585
|
};
|
|
590
586
|
}
|
|
591
|
-
function runDetachedCommandWithSpawn(command, args, options = {}) {
|
|
592
|
-
const child = spawn2(command, args, {
|
|
593
|
-
env: options.env,
|
|
594
|
-
stdio: options.stdio ?? "ignore",
|
|
595
|
-
detached: true
|
|
596
|
-
});
|
|
597
|
-
child.on("error", () => void 0);
|
|
598
|
-
child.unref();
|
|
599
|
-
}
|
|
600
|
-
function scheduleBackgroundUpdateRefresh(options, env, argv) {
|
|
601
|
-
const spawnDetachedCommand = options.spawnDetachedCommand ?? runDetachedCommandWithSpawn;
|
|
602
|
-
spawnDetachedCommand(options.execPath ?? process.execPath, argv.slice(1), {
|
|
603
|
-
env: {
|
|
604
|
-
...env,
|
|
605
|
-
[UPDATE_CHECK_REFRESH_ENV_VAR]: "1"
|
|
606
|
-
},
|
|
607
|
-
stdio: "ignore"
|
|
608
|
-
});
|
|
609
|
-
}
|
|
610
|
-
async function refreshUpdateCheckCache(options) {
|
|
611
|
-
try {
|
|
612
|
-
const env = options.env ?? process.env;
|
|
613
|
-
await resolveLatestVersion(toResolveLatestVersionOptions(options, env));
|
|
614
|
-
} catch {
|
|
615
|
-
}
|
|
616
|
-
}
|
|
617
587
|
async function checkForUpdatesAndMaybeRestart(options) {
|
|
618
588
|
const env = options.env ?? process.env;
|
|
619
589
|
const argv = options.argv ?? process.argv;
|
|
@@ -630,19 +600,7 @@ async function checkForUpdatesAndMaybeRestart(options) {
|
|
|
630
600
|
return { continueExecution: true };
|
|
631
601
|
}
|
|
632
602
|
try {
|
|
633
|
-
const
|
|
634
|
-
const cacheFilePath = resolveOptions.cacheFilePath ?? getDefaultUpdateCheckCachePath();
|
|
635
|
-
const cachePayload = await readUpdateCheckCachePayload(cacheFilePath);
|
|
636
|
-
const cacheTtlMs = resolveOptions.cacheTtlMs ?? DEFAULT_UPDATE_CHECK_CACHE_TTL_MS;
|
|
637
|
-
const now = resolveOptions.now ?? Date.now;
|
|
638
|
-
if (!cachePayload || !isCacheFresh(cachePayload, cacheTtlMs, now)) {
|
|
639
|
-
try {
|
|
640
|
-
scheduleBackgroundUpdateRefresh(options, env, argv);
|
|
641
|
-
} catch {
|
|
642
|
-
}
|
|
643
|
-
return { continueExecution: true };
|
|
644
|
-
}
|
|
645
|
-
const latestVersion = cachePayload.latestVersion;
|
|
603
|
+
const latestVersion = await resolveLatestVersion(toResolveLatestVersionOptions(options, env));
|
|
646
604
|
if (!latestVersion || !shouldOfferUpdate(options.currentVersion, latestVersion)) {
|
|
647
605
|
return { continueExecution: true };
|
|
648
606
|
}
|
|
@@ -2659,7 +2617,7 @@ function aggregateEfficiency(options) {
|
|
|
2659
2617
|
}
|
|
2660
2618
|
|
|
2661
2619
|
// src/efficiency/git-outcome-collector.ts
|
|
2662
|
-
import { spawn as
|
|
2620
|
+
import { spawn as spawn2 } from "child_process";
|
|
2663
2621
|
import { createInterface as createInterface2 } from "readline";
|
|
2664
2622
|
import path3 from "path";
|
|
2665
2623
|
import { stat } from "fs/promises";
|
|
@@ -2858,7 +2816,7 @@ function parseGitLogShortstatLines(lines, authorEmail) {
|
|
|
2858
2816
|
}
|
|
2859
2817
|
async function runGitCommand(repoDir, args) {
|
|
2860
2818
|
return await new Promise((resolve, reject) => {
|
|
2861
|
-
const child =
|
|
2819
|
+
const child = spawn2("git", args, {
|
|
2862
2820
|
cwd: repoDir,
|
|
2863
2821
|
env: {
|
|
2864
2822
|
...process.env,
|
|
@@ -3763,13 +3721,16 @@ function parseUsage(usage) {
|
|
|
3763
3721
|
totalTokens
|
|
3764
3722
|
};
|
|
3765
3723
|
}
|
|
3766
|
-
function createDedupKey(filePath, line, message) {
|
|
3724
|
+
function createDedupKey(filePath, line, message, timestamp, model) {
|
|
3767
3725
|
const messageId = asTrimmedText(message.id);
|
|
3768
3726
|
if (messageId) {
|
|
3769
3727
|
return `${filePath}\0${messageId}`;
|
|
3770
3728
|
}
|
|
3771
3729
|
const uuid = asTrimmedText(line.uuid);
|
|
3772
|
-
|
|
3730
|
+
if (uuid) {
|
|
3731
|
+
return `${filePath}\0${uuid}`;
|
|
3732
|
+
}
|
|
3733
|
+
return `${filePath}\0${timestamp}\0${model ?? ""}`;
|
|
3773
3734
|
}
|
|
3774
3735
|
function comparePendingEvents(left, right) {
|
|
3775
3736
|
if (left.timestamp !== right.timestamp) {
|
|
@@ -3842,12 +3803,7 @@ var ClaudeSourceAdapter = class {
|
|
|
3842
3803
|
incrementSkippedReason(skippedRowReasons, "invalid_timestamp");
|
|
3843
3804
|
continue;
|
|
3844
3805
|
}
|
|
3845
|
-
const dedupKey = createDedupKey(filePath, line, message);
|
|
3846
|
-
if (!dedupKey) {
|
|
3847
|
-
skippedRows++;
|
|
3848
|
-
incrementSkippedReason(skippedRowReasons, "missing_message_id");
|
|
3849
|
-
continue;
|
|
3850
|
-
}
|
|
3806
|
+
const dedupKey = createDedupKey(filePath, line, message, timestamp, model);
|
|
3851
3807
|
const sessionId = asTrimmedText(line.sessionId) ?? getFallbackSessionId(filePath);
|
|
3852
3808
|
const repoRoot = asTrimmedText(line.cwd);
|
|
3853
3809
|
const provider = resolveProvider(message, model);
|
|
@@ -5050,17 +5006,257 @@ var OpenCodeSourceAdapter = class {
|
|
|
5050
5006
|
}
|
|
5051
5007
|
};
|
|
5052
5008
|
|
|
5053
|
-
// src/sources/
|
|
5009
|
+
// src/sources/openclaw/openclaw-source-adapter.ts
|
|
5054
5010
|
import os7 from "os";
|
|
5055
5011
|
import path11 from "path";
|
|
5056
|
-
var
|
|
5012
|
+
var defaultAgentsDir = path11.join(os7.homedir(), ".openclaw", "agents");
|
|
5013
|
+
var SESSION_LINE_PATTERN = /"type"\s*:\s*"session"/u;
|
|
5014
|
+
var MESSAGE_LINE_PATTERN = /"type"\s*:\s*"message"/u;
|
|
5015
|
+
var MODEL_CHANGE_LINE_PATTERN = /"type"\s*:\s*"model_change"/u;
|
|
5016
|
+
var USAGE_LINE_PATTERN = /"usage"\s*:/u;
|
|
5017
|
+
var MODEL_LINE_PATTERN = /"model"\s*:/u;
|
|
5018
|
+
var PROVIDER_LINE_PATTERN = /"provider"\s*:/u;
|
|
5019
|
+
function shouldParseOpenClawJsonlLine(lineText) {
|
|
5020
|
+
return SESSION_LINE_PATTERN.test(lineText) || MESSAGE_LINE_PATTERN.test(lineText) || MODEL_CHANGE_LINE_PATTERN.test(lineText) || USAGE_LINE_PATTERN.test(lineText) || MODEL_LINE_PATTERN.test(lineText) || PROVIDER_LINE_PATTERN.test(lineText);
|
|
5021
|
+
}
|
|
5022
|
+
function getFallbackSessionId3(filePath) {
|
|
5023
|
+
return path11.basename(filePath, ".jsonl");
|
|
5024
|
+
}
|
|
5025
|
+
function resolveRepoRootFromRecord(record) {
|
|
5026
|
+
if (!record) {
|
|
5027
|
+
return void 0;
|
|
5028
|
+
}
|
|
5029
|
+
const pathRecord = asRecord(record.path);
|
|
5030
|
+
return asTrimmedText(record.cwd) ?? asTrimmedText(pathRecord?.root) ?? asTrimmedText(pathRecord?.cwd) ?? asTrimmedText(record.repo_root) ?? asTrimmedText(record.repoRoot) ?? asTrimmedText(record.project_root) ?? asTrimmedText(record.projectRoot) ?? asTrimmedText(record.workspace);
|
|
5031
|
+
}
|
|
5032
|
+
function firstText(...values) {
|
|
5033
|
+
for (const value of values) {
|
|
5034
|
+
const normalized = asTrimmedText(value);
|
|
5035
|
+
if (normalized) {
|
|
5036
|
+
return normalized;
|
|
5037
|
+
}
|
|
5038
|
+
}
|
|
5039
|
+
return void 0;
|
|
5040
|
+
}
|
|
5041
|
+
function isAssistantMessage(line, message) {
|
|
5042
|
+
return firstText(line.role, message.role)?.toLowerCase() === "assistant";
|
|
5043
|
+
}
|
|
5044
|
+
function isDeliveryMirror(provider, model, message) {
|
|
5045
|
+
const messageKind = firstText(message.kind, message.source, message.provenance);
|
|
5046
|
+
return provider?.toLowerCase() === "openclaw" || model?.toLowerCase() === "delivery-mirror" || messageKind?.toLowerCase() === "delivery-mirror";
|
|
5047
|
+
}
|
|
5048
|
+
function toFiniteNumber2(value) {
|
|
5049
|
+
if (value === null || value === void 0) {
|
|
5050
|
+
return void 0;
|
|
5051
|
+
}
|
|
5052
|
+
if (typeof value === "string" && value.trim().length === 0) {
|
|
5053
|
+
return void 0;
|
|
5054
|
+
}
|
|
5055
|
+
const parsed = typeof value === "number" ? value : Number(value);
|
|
5056
|
+
return Number.isFinite(parsed) ? parsed : void 0;
|
|
5057
|
+
}
|
|
5058
|
+
function extractCostUsd(usage) {
|
|
5059
|
+
const cost = asRecord(usage.cost);
|
|
5060
|
+
return toNumberLike(usage.costUsd) ?? toNumberLike(usage.cost_usd) ?? toNumberLike(usage.turnUsd) ?? toNumberLike(usage.turn_usd) ?? toNumberLike(usage.usd) ?? toNumberLike(usage.cost) ?? toNumberLike(cost?.total) ?? toNumberLike(cost?.usd) ?? toNumberLike(cost?.turnUsd) ?? toNumberLike(cost?.turn_usd);
|
|
5061
|
+
}
|
|
5062
|
+
function extractUsageFromRecord(usage) {
|
|
5063
|
+
const extracted = {
|
|
5064
|
+
inputTokens: toNumberLike(usage.input) ?? toNumberLike(usage.inputTokens) ?? toNumberLike(usage.input_tokens) ?? toNumberLike(usage.prompt_tokens),
|
|
5065
|
+
outputTokens: toNumberLike(usage.output) ?? toNumberLike(usage.outputTokens) ?? toNumberLike(usage.output_tokens) ?? toNumberLike(usage.completion_tokens),
|
|
5066
|
+
reasoningTokens: toNumberLike(usage.reasoning) ?? toNumberLike(usage.reasoningTokens) ?? toNumberLike(usage.reasoning_tokens) ?? toNumberLike(usage.reasoningOutput) ?? toNumberLike(usage.reasoning_output_tokens),
|
|
5067
|
+
cacheReadTokens: toNumberLike(usage.cacheRead) ?? toNumberLike(usage.cache_read) ?? toNumberLike(usage.cacheReadTokens) ?? toNumberLike(usage.cache_read_tokens) ?? toNumberLike(usage.cached) ?? toNumberLike(usage.cached_input_tokens),
|
|
5068
|
+
cacheWriteTokens: toNumberLike(usage.cacheWrite) ?? toNumberLike(usage.cache_write) ?? toNumberLike(usage.cacheWriteTokens) ?? toNumberLike(usage.cache_write_tokens),
|
|
5069
|
+
totalTokens: toNumberLike(usage.total) ?? toNumberLike(usage.totalTokens) ?? toNumberLike(usage.total_tokens),
|
|
5070
|
+
costUsd: extractCostUsd(usage)
|
|
5071
|
+
};
|
|
5072
|
+
const usageCandidates = [
|
|
5073
|
+
extracted.inputTokens,
|
|
5074
|
+
extracted.outputTokens,
|
|
5075
|
+
extracted.reasoningTokens,
|
|
5076
|
+
extracted.cacheReadTokens,
|
|
5077
|
+
extracted.cacheWriteTokens,
|
|
5078
|
+
extracted.totalTokens
|
|
5079
|
+
];
|
|
5080
|
+
const hasPositiveUsageSignal = usageCandidates.some((value) => {
|
|
5081
|
+
const parsed = toFiniteNumber2(value);
|
|
5082
|
+
return parsed !== void 0 && parsed > 0;
|
|
5083
|
+
});
|
|
5084
|
+
const explicitCost = toFiniteNumber2(extracted.costUsd);
|
|
5085
|
+
const hasPositiveCostSignal = explicitCost !== void 0 && explicitCost > 0;
|
|
5086
|
+
return hasPositiveUsageSignal || hasPositiveCostSignal ? extracted : void 0;
|
|
5087
|
+
}
|
|
5088
|
+
function mergeUsageExtracts(primary, fallback) {
|
|
5089
|
+
if (!primary) {
|
|
5090
|
+
return fallback;
|
|
5091
|
+
}
|
|
5092
|
+
if (!fallback) {
|
|
5093
|
+
return primary;
|
|
5094
|
+
}
|
|
5095
|
+
return {
|
|
5096
|
+
inputTokens: primary.inputTokens ?? fallback.inputTokens,
|
|
5097
|
+
outputTokens: primary.outputTokens ?? fallback.outputTokens,
|
|
5098
|
+
reasoningTokens: primary.reasoningTokens ?? fallback.reasoningTokens,
|
|
5099
|
+
cacheReadTokens: primary.cacheReadTokens ?? fallback.cacheReadTokens,
|
|
5100
|
+
cacheWriteTokens: primary.cacheWriteTokens ?? fallback.cacheWriteTokens,
|
|
5101
|
+
totalTokens: primary.totalTokens ?? fallback.totalTokens,
|
|
5102
|
+
costUsd: primary.costUsd ?? fallback.costUsd
|
|
5103
|
+
};
|
|
5104
|
+
}
|
|
5105
|
+
function extractUsage(line, message) {
|
|
5106
|
+
const lineUsage = asRecord(line.usage);
|
|
5107
|
+
const messageUsage = asRecord(message.usage);
|
|
5108
|
+
const extractedLineUsage = lineUsage ? extractUsageFromRecord(lineUsage) : void 0;
|
|
5109
|
+
const extractedMessageUsage = messageUsage ? extractUsageFromRecord(messageUsage) : void 0;
|
|
5110
|
+
return mergeUsageExtracts(extractedLineUsage, extractedMessageUsage);
|
|
5111
|
+
}
|
|
5112
|
+
function resolveTimestamp2(line, message, state, fallbackTimestamp) {
|
|
5113
|
+
const candidates = [line.timestamp, message.timestamp, fallbackTimestamp, state.sessionTimestamp];
|
|
5114
|
+
for (const candidate of candidates) {
|
|
5115
|
+
const normalizedTimestamp = normalizeTimestampCandidate(candidate);
|
|
5116
|
+
if (normalizedTimestamp) {
|
|
5117
|
+
return normalizedTimestamp;
|
|
5118
|
+
}
|
|
5119
|
+
}
|
|
5120
|
+
return void 0;
|
|
5121
|
+
}
|
|
5122
|
+
function updateRuntimeStateFromRecord(state, record, nested) {
|
|
5123
|
+
state.provider = firstText(
|
|
5124
|
+
record.provider,
|
|
5125
|
+
record.modelProvider,
|
|
5126
|
+
record.model_provider,
|
|
5127
|
+
nested?.provider,
|
|
5128
|
+
nested?.modelProvider,
|
|
5129
|
+
nested?.model_provider
|
|
5130
|
+
) ?? state.provider;
|
|
5131
|
+
state.model = firstText(
|
|
5132
|
+
record.model,
|
|
5133
|
+
record.modelId,
|
|
5134
|
+
record.model_id,
|
|
5135
|
+
nested?.model,
|
|
5136
|
+
nested?.modelId,
|
|
5137
|
+
nested?.model_id
|
|
5138
|
+
) ?? state.model;
|
|
5139
|
+
state.repoRoot = resolveRepoRootFromRecord(record) ?? resolveRepoRootFromRecord(nested) ?? state.repoRoot;
|
|
5140
|
+
}
|
|
5141
|
+
var OpenClawSourceAdapter = class {
|
|
5142
|
+
id = "openclaw";
|
|
5143
|
+
agentsDir;
|
|
5144
|
+
requireAgentsDir;
|
|
5145
|
+
constructor(options = {}) {
|
|
5146
|
+
this.agentsDir = options.agentsDir ?? defaultAgentsDir;
|
|
5147
|
+
this.requireAgentsDir = options.requireAgentsDir ?? false;
|
|
5148
|
+
}
|
|
5149
|
+
async discoverFiles() {
|
|
5150
|
+
if (isBlankText(this.agentsDir)) {
|
|
5151
|
+
throw new Error("OpenClaw agents directory must be a non-empty path");
|
|
5152
|
+
}
|
|
5153
|
+
const normalizedAgentsDir = this.agentsDir.trim();
|
|
5154
|
+
if (this.requireAgentsDir) {
|
|
5155
|
+
const agentsDirStats = await pathStat(normalizedAgentsDir);
|
|
5156
|
+
if (!agentsDirStats) {
|
|
5157
|
+
throw new Error(
|
|
5158
|
+
`OpenClaw agents directory is missing or unreadable: ${normalizedAgentsDir}`
|
|
5159
|
+
);
|
|
5160
|
+
}
|
|
5161
|
+
if (!agentsDirStats.isDirectory()) {
|
|
5162
|
+
throw new Error(`OpenClaw agents directory is not a directory: ${normalizedAgentsDir}`);
|
|
5163
|
+
}
|
|
5164
|
+
}
|
|
5165
|
+
return discoverJsonlFiles(normalizedAgentsDir);
|
|
5166
|
+
}
|
|
5167
|
+
async parseFile(filePath) {
|
|
5168
|
+
return (await this.parseFileWithDiagnostics(filePath)).events;
|
|
5169
|
+
}
|
|
5170
|
+
async parseFileWithDiagnostics(filePath) {
|
|
5171
|
+
const events = [];
|
|
5172
|
+
let skippedRows = 0;
|
|
5173
|
+
const skippedRowReasons = /* @__PURE__ */ new Map();
|
|
5174
|
+
const fileStats = await pathStat(filePath);
|
|
5175
|
+
const fallbackTimestamp = fileStats?.mtime.toISOString();
|
|
5176
|
+
const state = {
|
|
5177
|
+
sessionId: getFallbackSessionId3(filePath)
|
|
5178
|
+
};
|
|
5179
|
+
for await (const line of readJsonlObjects(filePath, {
|
|
5180
|
+
shouldParseLine: shouldParseOpenClawJsonlLine
|
|
5181
|
+
})) {
|
|
5182
|
+
const message = asRecord(line.message) ?? line;
|
|
5183
|
+
if (line.type === "session") {
|
|
5184
|
+
state.sessionId = firstText(line.id, line.sessionId, line.session_id) ?? state.sessionId;
|
|
5185
|
+
state.sessionTimestamp = normalizeTimestampCandidate(line.timestamp) ?? state.sessionTimestamp;
|
|
5186
|
+
updateRuntimeStateFromRecord(state, line, message);
|
|
5187
|
+
continue;
|
|
5188
|
+
}
|
|
5189
|
+
if (line.type === "model_change") {
|
|
5190
|
+
updateRuntimeStateFromRecord(state, line, message);
|
|
5191
|
+
continue;
|
|
5192
|
+
}
|
|
5193
|
+
if (line.type !== "message" || !isAssistantMessage(line, message)) {
|
|
5194
|
+
updateRuntimeStateFromRecord(state, line, message);
|
|
5195
|
+
continue;
|
|
5196
|
+
}
|
|
5197
|
+
const rowProvider = firstText(
|
|
5198
|
+
line.provider,
|
|
5199
|
+
message.provider,
|
|
5200
|
+
line.modelProvider,
|
|
5201
|
+
message.modelProvider,
|
|
5202
|
+
line.model_provider,
|
|
5203
|
+
message.model_provider
|
|
5204
|
+
);
|
|
5205
|
+
const rowModel = firstText(
|
|
5206
|
+
line.model,
|
|
5207
|
+
message.model,
|
|
5208
|
+
line.modelId,
|
|
5209
|
+
message.modelId,
|
|
5210
|
+
line.model_id,
|
|
5211
|
+
message.model_id
|
|
5212
|
+
);
|
|
5213
|
+
if (isDeliveryMirror(rowProvider, rowModel, message)) {
|
|
5214
|
+
continue;
|
|
5215
|
+
}
|
|
5216
|
+
updateRuntimeStateFromRecord(state, line, message);
|
|
5217
|
+
const provider = rowProvider ?? state.provider;
|
|
5218
|
+
const model = rowModel ?? state.model;
|
|
5219
|
+
const usage = extractUsage(line, message);
|
|
5220
|
+
if (!usage) {
|
|
5221
|
+
continue;
|
|
5222
|
+
}
|
|
5223
|
+
const timestamp = resolveTimestamp2(line, message, state, fallbackTimestamp);
|
|
5224
|
+
if (!timestamp) {
|
|
5225
|
+
continue;
|
|
5226
|
+
}
|
|
5227
|
+
try {
|
|
5228
|
+
events.push(
|
|
5229
|
+
createUsageEvent({
|
|
5230
|
+
source: this.id,
|
|
5231
|
+
sessionId: state.sessionId,
|
|
5232
|
+
timestamp,
|
|
5233
|
+
repoRoot: state.repoRoot,
|
|
5234
|
+
provider,
|
|
5235
|
+
model,
|
|
5236
|
+
...usage
|
|
5237
|
+
})
|
|
5238
|
+
);
|
|
5239
|
+
} catch {
|
|
5240
|
+
skippedRows += 1;
|
|
5241
|
+
incrementSkippedReason(skippedRowReasons, "invalid_usage_event");
|
|
5242
|
+
continue;
|
|
5243
|
+
}
|
|
5244
|
+
}
|
|
5245
|
+
return toParseDiagnostics(events, skippedRows, skippedRowReasons);
|
|
5246
|
+
}
|
|
5247
|
+
};
|
|
5248
|
+
|
|
5249
|
+
// src/sources/pi/pi-source-adapter.ts
|
|
5250
|
+
import os8 from "os";
|
|
5251
|
+
import path12 from "path";
|
|
5252
|
+
var defaultSessionsDir3 = path12.join(os8.homedir(), ".pi", "agent", "sessions");
|
|
5057
5253
|
var PI_MESSAGE_LINE_PATTERN = /"type"\s*:\s*"message"/u;
|
|
5058
5254
|
var PI_SESSION_LINE_PATTERN = /"type"\s*:\s*"session"/u;
|
|
5059
5255
|
var PI_MODEL_CHANGE_LINE_PATTERN = /"type"\s*:\s*"model_change"/u;
|
|
5060
5256
|
function shouldParsePiJsonlLine(lineText) {
|
|
5061
5257
|
return PI_MESSAGE_LINE_PATTERN.test(lineText) || PI_SESSION_LINE_PATTERN.test(lineText) || PI_MODEL_CHANGE_LINE_PATTERN.test(lineText);
|
|
5062
5258
|
}
|
|
5063
|
-
function
|
|
5259
|
+
function resolveTimestamp3(line, message, state) {
|
|
5064
5260
|
const candidates = [line.timestamp, message?.timestamp, state.sessionTimestamp];
|
|
5065
5261
|
for (const candidate of candidates) {
|
|
5066
5262
|
const normalizedTimestamp = normalizeTimestampCandidate(candidate);
|
|
@@ -5070,7 +5266,7 @@ function resolveTimestamp2(line, message, state) {
|
|
|
5070
5266
|
}
|
|
5071
5267
|
return void 0;
|
|
5072
5268
|
}
|
|
5073
|
-
function
|
|
5269
|
+
function extractUsageFromRecord2(usage) {
|
|
5074
5270
|
const cost = asRecord(usage.cost);
|
|
5075
5271
|
const extracted = {
|
|
5076
5272
|
inputTokens: toNumberLike(usage.input),
|
|
@@ -5083,7 +5279,7 @@ function extractUsageFromRecord(usage) {
|
|
|
5083
5279
|
totalTokens: toNumberLike(usage.totalTokens),
|
|
5084
5280
|
costUsd: toNumberLike(cost?.total)
|
|
5085
5281
|
};
|
|
5086
|
-
const
|
|
5282
|
+
const toFiniteNumber3 = (value) => {
|
|
5087
5283
|
if (value === null || value === void 0) {
|
|
5088
5284
|
return void 0;
|
|
5089
5285
|
}
|
|
@@ -5105,18 +5301,18 @@ function extractUsageFromRecord(usage) {
|
|
|
5105
5301
|
extracted.totalTokens
|
|
5106
5302
|
];
|
|
5107
5303
|
const hasPositiveUsageSignal = usageCandidates.some((value) => {
|
|
5108
|
-
const parsed =
|
|
5304
|
+
const parsed = toFiniteNumber3(value);
|
|
5109
5305
|
return parsed !== void 0 && parsed > 0;
|
|
5110
5306
|
});
|
|
5111
|
-
const explicitCost =
|
|
5307
|
+
const explicitCost = toFiniteNumber3(extracted.costUsd);
|
|
5112
5308
|
const hasPositiveCostSignal = explicitCost !== void 0 && explicitCost > 0;
|
|
5113
5309
|
return hasPositiveUsageSignal || hasPositiveCostSignal ? extracted : void 0;
|
|
5114
5310
|
}
|
|
5115
|
-
function
|
|
5311
|
+
function extractUsage2(line, message) {
|
|
5116
5312
|
const lineUsage = asRecord(line.usage);
|
|
5117
5313
|
const messageUsage = asRecord(message?.usage);
|
|
5118
5314
|
if (lineUsage) {
|
|
5119
|
-
const extractedLineUsage =
|
|
5315
|
+
const extractedLineUsage = extractUsageFromRecord2(lineUsage);
|
|
5120
5316
|
if (extractedLineUsage) {
|
|
5121
5317
|
return extractedLineUsage;
|
|
5122
5318
|
}
|
|
@@ -5124,12 +5320,12 @@ function extractUsage(line, message) {
|
|
|
5124
5320
|
if (!messageUsage) {
|
|
5125
5321
|
return void 0;
|
|
5126
5322
|
}
|
|
5127
|
-
return
|
|
5323
|
+
return extractUsageFromRecord2(messageUsage);
|
|
5128
5324
|
}
|
|
5129
|
-
function
|
|
5130
|
-
return
|
|
5325
|
+
function getFallbackSessionId4(filePath) {
|
|
5326
|
+
return path12.basename(filePath, ".jsonl");
|
|
5131
5327
|
}
|
|
5132
|
-
function
|
|
5328
|
+
function resolveRepoRootFromRecord2(record) {
|
|
5133
5329
|
if (!record) {
|
|
5134
5330
|
return void 0;
|
|
5135
5331
|
}
|
|
@@ -5159,37 +5355,37 @@ var PiSourceAdapter = class {
|
|
|
5159
5355
|
}
|
|
5160
5356
|
async parseFile(filePath) {
|
|
5161
5357
|
const events = [];
|
|
5162
|
-
const state = { sessionId:
|
|
5358
|
+
const state = { sessionId: getFallbackSessionId4(filePath) };
|
|
5163
5359
|
for await (const line of readJsonlObjects(filePath, {
|
|
5164
5360
|
shouldParseLine: shouldParsePiJsonlLine
|
|
5165
5361
|
})) {
|
|
5166
5362
|
if (line.type === "session") {
|
|
5167
5363
|
state.sessionId = asTrimmedText(line.id) ?? state.sessionId;
|
|
5168
5364
|
state.sessionTimestamp = asTrimmedText(line.timestamp) ?? state.sessionTimestamp;
|
|
5169
|
-
state.repoRoot =
|
|
5365
|
+
state.repoRoot = resolveRepoRootFromRecord2(line) ?? state.repoRoot;
|
|
5170
5366
|
continue;
|
|
5171
5367
|
}
|
|
5172
5368
|
if (line.type === "model_change") {
|
|
5173
5369
|
state.provider = asTrimmedText(line.provider) ?? state.provider;
|
|
5174
5370
|
state.model = asTrimmedText(line.modelId) ?? asTrimmedText(line.model) ?? state.model;
|
|
5175
|
-
state.repoRoot =
|
|
5371
|
+
state.repoRoot = resolveRepoRootFromRecord2(line) ?? state.repoRoot;
|
|
5176
5372
|
continue;
|
|
5177
5373
|
}
|
|
5178
5374
|
if (line.type !== "message") {
|
|
5179
5375
|
continue;
|
|
5180
5376
|
}
|
|
5181
5377
|
const message = asRecord(line.message);
|
|
5182
|
-
const usage =
|
|
5378
|
+
const usage = extractUsage2(line, message);
|
|
5183
5379
|
if (!usage) {
|
|
5184
5380
|
continue;
|
|
5185
5381
|
}
|
|
5186
5382
|
const provider = asTrimmedText(line.provider) ?? asTrimmedText(message?.provider) ?? state.provider;
|
|
5187
|
-
const timestamp =
|
|
5383
|
+
const timestamp = resolveTimestamp3(line, message, state);
|
|
5188
5384
|
if (!timestamp || !state.sessionId) {
|
|
5189
5385
|
continue;
|
|
5190
5386
|
}
|
|
5191
5387
|
const model = asTrimmedText(line.model) ?? asTrimmedText(line.modelId) ?? asTrimmedText(message?.model) ?? state.model;
|
|
5192
|
-
const repoRoot =
|
|
5388
|
+
const repoRoot = resolveRepoRootFromRecord2(line) ?? resolveRepoRootFromRecord2(message) ?? state.repoRoot;
|
|
5193
5389
|
try {
|
|
5194
5390
|
events.push(
|
|
5195
5391
|
createUsageEvent({
|
|
@@ -5299,6 +5495,21 @@ var sourceRegistrations = [
|
|
|
5299
5495
|
dbPath: options.opencodeDb
|
|
5300
5496
|
})
|
|
5301
5497
|
},
|
|
5498
|
+
{
|
|
5499
|
+
id: "openclaw",
|
|
5500
|
+
sourceDirOverride: { kind: "directory" },
|
|
5501
|
+
create: (_options, sourceDirectoryOverrides) => {
|
|
5502
|
+
const directoryConfig = resolveDirectoryConfig(
|
|
5503
|
+
"openclaw",
|
|
5504
|
+
void 0,
|
|
5505
|
+
sourceDirectoryOverrides
|
|
5506
|
+
);
|
|
5507
|
+
return new OpenClawSourceAdapter({
|
|
5508
|
+
agentsDir: directoryConfig.path,
|
|
5509
|
+
requireAgentsDir: directoryConfig.requireExistingPath
|
|
5510
|
+
});
|
|
5511
|
+
}
|
|
5512
|
+
},
|
|
5302
5513
|
{
|
|
5303
5514
|
id: "claude",
|
|
5304
5515
|
sourceDirOverride: { kind: "directory" },
|
|
@@ -5636,7 +5847,7 @@ function normalizeSkippedRowReasons(value) {
|
|
|
5636
5847
|
|
|
5637
5848
|
// src/cli/parse-file-cache.ts
|
|
5638
5849
|
import { mkdir as mkdir2, readFile as readFile4, rename, rm, stat as stat4, writeFile as writeFile2 } from "fs/promises";
|
|
5639
|
-
import
|
|
5850
|
+
import path13 from "path";
|
|
5640
5851
|
var PARSE_FILE_CACHE_VERSION = 5;
|
|
5641
5852
|
var CACHE_KEY_SEPARATOR = "\0";
|
|
5642
5853
|
function createCacheKey(source, filePath) {
|
|
@@ -5863,7 +6074,7 @@ function normalizeCacheEntry(value) {
|
|
|
5863
6074
|
};
|
|
5864
6075
|
}
|
|
5865
6076
|
function getDefaultParseFileCachePath() {
|
|
5866
|
-
return
|
|
6077
|
+
return path13.join(getUserCacheRootDir(), "llm-usage-metrics", "parse-file-cache.json");
|
|
5867
6078
|
}
|
|
5868
6079
|
function normalizeCacheShardSource(source) {
|
|
5869
6080
|
const normalizedSource = normalizeCacheSource(source);
|
|
@@ -5873,12 +6084,12 @@ function normalizeCacheShardSource(source) {
|
|
|
5873
6084
|
return normalizedSource.replace(/[^a-z0-9._-]/gu, "_");
|
|
5874
6085
|
}
|
|
5875
6086
|
function getSourceShardedParseFileCachePath(cacheFilePath, source) {
|
|
5876
|
-
const parsedPath =
|
|
6087
|
+
const parsedPath = path13.parse(cacheFilePath);
|
|
5877
6088
|
const sourceShard = normalizeCacheShardSource(source);
|
|
5878
6089
|
if (parsedPath.ext.length > 0) {
|
|
5879
|
-
return
|
|
6090
|
+
return path13.join(parsedPath.dir, `${parsedPath.name}.${sourceShard}${parsedPath.ext}`);
|
|
5880
6091
|
}
|
|
5881
|
-
return
|
|
6092
|
+
return path13.join(parsedPath.dir, `${parsedPath.base}.${sourceShard}`);
|
|
5882
6093
|
}
|
|
5883
6094
|
var ParseFileCache = class _ParseFileCache {
|
|
5884
6095
|
constructor(cacheFilePath, limits, now) {
|
|
@@ -5975,7 +6186,7 @@ var ParseFileCache = class _ParseFileCache {
|
|
|
5975
6186
|
keptEntries.length = bestCount;
|
|
5976
6187
|
payloadText = bestPayloadText;
|
|
5977
6188
|
}
|
|
5978
|
-
await mkdir2(
|
|
6189
|
+
await mkdir2(path13.dirname(this.cacheFilePath), { recursive: true });
|
|
5979
6190
|
const temporaryPath = `${this.cacheFilePath}.${process.pid}.${this.now()}.tmp`;
|
|
5980
6191
|
try {
|
|
5981
6192
|
await writeFile2(temporaryPath, payloadText, "utf8");
|
|
@@ -6462,9 +6673,92 @@ function applyPricingToEvents(events, pricingSource) {
|
|
|
6462
6673
|
});
|
|
6463
6674
|
}
|
|
6464
6675
|
|
|
6676
|
+
// src/pricing/pricing-override-source.ts
|
|
6677
|
+
import { readFile as readFile5 } from "fs/promises";
|
|
6678
|
+
function toFiniteUsdRate(value) {
|
|
6679
|
+
if (value === null || value === void 0) {
|
|
6680
|
+
return void 0;
|
|
6681
|
+
}
|
|
6682
|
+
if (typeof value === "string" && value.trim() === "") {
|
|
6683
|
+
return void 0;
|
|
6684
|
+
}
|
|
6685
|
+
const parsed = typeof value === "number" ? value : Number(value);
|
|
6686
|
+
return Number.isFinite(parsed) ? parsed : void 0;
|
|
6687
|
+
}
|
|
6688
|
+
function normalizeReasoningBilling(value) {
|
|
6689
|
+
if (value === "included-in-output" || value === "separate") {
|
|
6690
|
+
return value;
|
|
6691
|
+
}
|
|
6692
|
+
return void 0;
|
|
6693
|
+
}
|
|
6694
|
+
function normalizePricingOverride(raw) {
|
|
6695
|
+
const inputPer1MUsd = toFiniteUsdRate(toNumberLike(raw.inputPer1MUsd));
|
|
6696
|
+
const outputPer1MUsd = toFiniteUsdRate(toNumberLike(raw.outputPer1MUsd));
|
|
6697
|
+
if (inputPer1MUsd === void 0 || outputPer1MUsd === void 0) {
|
|
6698
|
+
return void 0;
|
|
6699
|
+
}
|
|
6700
|
+
const cacheReadPer1MUsd = toFiniteUsdRate(toNumberLike(raw.cacheReadPer1MUsd));
|
|
6701
|
+
const cacheWritePer1MUsd = toFiniteUsdRate(toNumberLike(raw.cacheWritePer1MUsd));
|
|
6702
|
+
const reasoningPer1MUsd = toFiniteUsdRate(toNumberLike(raw.reasoningPer1MUsd));
|
|
6703
|
+
const reasoningBilling = normalizeReasoningBilling(raw.reasoningBilling);
|
|
6704
|
+
return {
|
|
6705
|
+
inputPer1MUsd,
|
|
6706
|
+
outputPer1MUsd,
|
|
6707
|
+
...cacheReadPer1MUsd !== void 0 ? { cacheReadPer1MUsd } : {},
|
|
6708
|
+
...cacheWritePer1MUsd !== void 0 ? { cacheWritePer1MUsd } : {},
|
|
6709
|
+
...reasoningPer1MUsd !== void 0 ? { reasoningPer1MUsd } : {},
|
|
6710
|
+
...reasoningBilling !== void 0 ? { reasoningBilling } : {}
|
|
6711
|
+
};
|
|
6712
|
+
}
|
|
6713
|
+
function normalizeOverrideFile(payload) {
|
|
6714
|
+
const root = asRecord(payload);
|
|
6715
|
+
const overrides = /* @__PURE__ */ new Map();
|
|
6716
|
+
const modelsRecord = asRecord(root?.models);
|
|
6717
|
+
if (!modelsRecord) {
|
|
6718
|
+
return overrides;
|
|
6719
|
+
}
|
|
6720
|
+
for (const [modelName, rawPricing] of Object.entries(modelsRecord)) {
|
|
6721
|
+
const normalizedModelName = asTrimmedText(modelName)?.toLowerCase();
|
|
6722
|
+
if (!normalizedModelName) {
|
|
6723
|
+
continue;
|
|
6724
|
+
}
|
|
6725
|
+
const pricing = normalizePricingOverride(asRecord(rawPricing) ?? {});
|
|
6726
|
+
if (pricing) {
|
|
6727
|
+
overrides.set(normalizedModelName, pricing);
|
|
6728
|
+
}
|
|
6729
|
+
}
|
|
6730
|
+
return overrides;
|
|
6731
|
+
}
|
|
6732
|
+
async function loadPricingOverrides(filePath) {
|
|
6733
|
+
const fileContents = await readFile5(filePath, "utf8");
|
|
6734
|
+
const parsed = JSON.parse(fileContents);
|
|
6735
|
+
return normalizeOverrideFile(parsed);
|
|
6736
|
+
}
|
|
6737
|
+
var PricingOverrideSource = class {
|
|
6738
|
+
overrides;
|
|
6739
|
+
delegate;
|
|
6740
|
+
constructor(overrides, delegate) {
|
|
6741
|
+
this.overrides = overrides;
|
|
6742
|
+
this.delegate = delegate;
|
|
6743
|
+
}
|
|
6744
|
+
resolveModelAlias(model) {
|
|
6745
|
+
if (this.overrides.has(model.toLowerCase())) {
|
|
6746
|
+
return model;
|
|
6747
|
+
}
|
|
6748
|
+
return this.delegate.resolveModelAlias(model);
|
|
6749
|
+
}
|
|
6750
|
+
getPricing(model) {
|
|
6751
|
+
const override = this.overrides.get(model.toLowerCase());
|
|
6752
|
+
if (override) {
|
|
6753
|
+
return override;
|
|
6754
|
+
}
|
|
6755
|
+
return this.delegate.getPricing(model);
|
|
6756
|
+
}
|
|
6757
|
+
};
|
|
6758
|
+
|
|
6465
6759
|
// src/pricing/litellm-pricing-fetcher.ts
|
|
6466
|
-
import { mkdir as mkdir3, readFile as
|
|
6467
|
-
import
|
|
6760
|
+
import { mkdir as mkdir3, readFile as readFile6, writeFile as writeFile3 } from "fs/promises";
|
|
6761
|
+
import path14 from "path";
|
|
6468
6762
|
|
|
6469
6763
|
// src/pricing/litellm-model-map.json
|
|
6470
6764
|
var litellm_model_map_default = {
|
|
@@ -6648,7 +6942,7 @@ function normalizeLitellmPricingPayload(payload) {
|
|
|
6648
6942
|
return normalizedPricing;
|
|
6649
6943
|
}
|
|
6650
6944
|
function getDefaultLiteLLMPricingCachePath() {
|
|
6651
|
-
return
|
|
6945
|
+
return path14.join(getUserCacheRootDir(), "llm-usage-metrics", "litellm-pricing-cache.json");
|
|
6652
6946
|
}
|
|
6653
6947
|
function stripProviderPrefix(model) {
|
|
6654
6948
|
const slashIndex = model.lastIndexOf("/");
|
|
@@ -7007,7 +7301,7 @@ var LiteLLMPricingFetcher = class {
|
|
|
7007
7301
|
async readCachePayload() {
|
|
7008
7302
|
let content;
|
|
7009
7303
|
try {
|
|
7010
|
-
content = await
|
|
7304
|
+
content = await readFile6(this.cacheFilePath, "utf8");
|
|
7011
7305
|
} catch {
|
|
7012
7306
|
return void 0;
|
|
7013
7307
|
}
|
|
@@ -7042,7 +7336,7 @@ var LiteLLMPricingFetcher = class {
|
|
|
7042
7336
|
};
|
|
7043
7337
|
}
|
|
7044
7338
|
async writeCache() {
|
|
7045
|
-
const directoryPath =
|
|
7339
|
+
const directoryPath = path14.dirname(this.cacheFilePath);
|
|
7046
7340
|
await mkdir3(directoryPath, { recursive: true });
|
|
7047
7341
|
const payload = {
|
|
7048
7342
|
fetchedAt: this.now(),
|
|
@@ -7054,7 +7348,27 @@ var LiteLLMPricingFetcher = class {
|
|
|
7054
7348
|
};
|
|
7055
7349
|
|
|
7056
7350
|
// src/cli/build-usage-data-pricing.ts
|
|
7351
|
+
function wrapWithPricingOverrides(overrides, delegate) {
|
|
7352
|
+
if (!overrides || overrides.size === 0) {
|
|
7353
|
+
return delegate;
|
|
7354
|
+
}
|
|
7355
|
+
return new PricingOverrideSource(overrides, delegate);
|
|
7356
|
+
}
|
|
7057
7357
|
async function resolvePricingSource(options, runtimeConfig) {
|
|
7358
|
+
let pricingOverrides;
|
|
7359
|
+
if (options.pricingOverrides) {
|
|
7360
|
+
try {
|
|
7361
|
+
pricingOverrides = await loadPricingOverrides(options.pricingOverrides);
|
|
7362
|
+
} catch (error) {
|
|
7363
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
7364
|
+
throw new Error(
|
|
7365
|
+
`Could not load --pricing-overrides from ${options.pricingOverrides}: ${reason}`,
|
|
7366
|
+
{
|
|
7367
|
+
cause: error
|
|
7368
|
+
}
|
|
7369
|
+
);
|
|
7370
|
+
}
|
|
7371
|
+
}
|
|
7058
7372
|
const litellmPricingFetcher = new LiteLLMPricingFetcher({
|
|
7059
7373
|
sourceUrl: options.pricingUrl,
|
|
7060
7374
|
offline: options.pricingOffline,
|
|
@@ -7063,10 +7377,11 @@ async function resolvePricingSource(options, runtimeConfig) {
|
|
|
7063
7377
|
});
|
|
7064
7378
|
try {
|
|
7065
7379
|
const fromCache = await litellmPricingFetcher.load();
|
|
7380
|
+
const source = wrapWithPricingOverrides(pricingOverrides, litellmPricingFetcher);
|
|
7066
7381
|
if (options.pricingOffline) {
|
|
7067
|
-
return { source
|
|
7382
|
+
return { source, origin: "offline-cache" };
|
|
7068
7383
|
}
|
|
7069
|
-
return { source
|
|
7384
|
+
return { source, origin: fromCache ? "cache" : "network" };
|
|
7070
7385
|
} catch (error) {
|
|
7071
7386
|
if (options.pricingOffline) {
|
|
7072
7387
|
throw new Error("Offline pricing mode enabled but cached pricing is unavailable", {
|
|
@@ -7634,12 +7949,12 @@ function emitEnvVarOverrides(activeEnvOverrides, diagnosticsLogger) {
|
|
|
7634
7949
|
}
|
|
7635
7950
|
|
|
7636
7951
|
// src/cli/share-artifact.ts
|
|
7637
|
-
import { spawn as
|
|
7952
|
+
import { spawn as spawn3 } from "child_process";
|
|
7638
7953
|
import { constants as constants3 } from "fs";
|
|
7639
7954
|
import { access as access3, writeFile as writeFile4 } from "fs/promises";
|
|
7640
|
-
import
|
|
7955
|
+
import path15 from "path";
|
|
7641
7956
|
async function writeShareSvgFile(fileName, svgContent) {
|
|
7642
|
-
const outputPath =
|
|
7957
|
+
const outputPath = path15.resolve(process.cwd(), fileName);
|
|
7643
7958
|
await writeFile4(outputPath, svgContent, "utf8");
|
|
7644
7959
|
return outputPath;
|
|
7645
7960
|
}
|
|
@@ -7667,10 +7982,10 @@ async function resolveBinaryPath(primaryPath, fallbackNames) {
|
|
|
7667
7982
|
if (await fileExists(primaryPath)) {
|
|
7668
7983
|
return primaryPath;
|
|
7669
7984
|
}
|
|
7670
|
-
const pathDirs = (process.env.PATH ?? "").split(
|
|
7985
|
+
const pathDirs = (process.env.PATH ?? "").split(path15.delimiter).filter(Boolean);
|
|
7671
7986
|
for (const fallbackName of fallbackNames) {
|
|
7672
7987
|
for (const dir of pathDirs) {
|
|
7673
|
-
const candidate =
|
|
7988
|
+
const candidate = path15.join(dir, fallbackName);
|
|
7674
7989
|
if (await fileExists(candidate)) {
|
|
7675
7990
|
return candidate;
|
|
7676
7991
|
}
|
|
@@ -7716,7 +8031,7 @@ async function resolveOpenCommand(filePath, platform) {
|
|
|
7716
8031
|
}
|
|
7717
8032
|
async function spawnDetached(command, args) {
|
|
7718
8033
|
await new Promise((resolve, reject) => {
|
|
7719
|
-
const child =
|
|
8034
|
+
const child = spawn3(command, args, {
|
|
7720
8035
|
detached: true,
|
|
7721
8036
|
stdio: "ignore",
|
|
7722
8037
|
windowsHide: true
|
|
@@ -9916,7 +10231,10 @@ function registerSharedReportOptions(command, profile) {
|
|
|
9916
10231
|
"--model <name>",
|
|
9917
10232
|
"Filter by model (repeatable/comma-separated; exact when exact match exists after source/provider/date filters, otherwise substring)",
|
|
9918
10233
|
collectRepeatedOption
|
|
9919
|
-
).option("--pricing-url <url>", "Override LiteLLM pricing source URL").option(
|
|
10234
|
+
).option("--pricing-url <url>", "Override LiteLLM pricing source URL").option(
|
|
10235
|
+
"--pricing-overrides <path>",
|
|
10236
|
+
"Path to a JSON file of per-model pricing overrides (takes precedence over LiteLLM)"
|
|
10237
|
+
).option("--pricing-offline", "Use cached LiteLLM pricing only (no network fetch)").option(
|
|
9920
10238
|
"--ignore-pricing-failures",
|
|
9921
10239
|
"Continue without estimated costs when pricing cannot be loaded"
|
|
9922
10240
|
).option("--json", "Render output as JSON");
|
|
@@ -9968,7 +10286,7 @@ function createUsageReportDefinition(granularity) {
|
|
|
9968
10286
|
includeInRootHelp: true
|
|
9969
10287
|
},
|
|
9970
10288
|
{
|
|
9971
|
-
command: "llm-usage daily --source-dir pi=/tmp/pi-sessions --source-dir gemini=/tmp/.gemini --source-dir droid=/tmp/droid-sessions",
|
|
10289
|
+
command: "llm-usage daily --source-dir pi=/tmp/pi-sessions --source-dir gemini=/tmp/.gemini --source-dir droid=/tmp/droid-sessions --source-dir openclaw=/tmp/openclaw-agents",
|
|
9972
10290
|
includeInRootHelp: true,
|
|
9973
10291
|
includeInCliReference: true
|
|
9974
10292
|
},
|
|
@@ -10230,15 +10548,6 @@ var { packageName, packageVersion } = loadPackageMetadataFromRuntime();
|
|
|
10230
10548
|
var updateRuntimeConfig = getUpdateNotifierRuntimeConfig();
|
|
10231
10549
|
var cli = createCli({ version: packageVersion });
|
|
10232
10550
|
async function main() {
|
|
10233
|
-
if (process.env[UPDATE_CHECK_REFRESH_ENV_VAR] === "1") {
|
|
10234
|
-
await refreshUpdateCheckCache({
|
|
10235
|
-
packageName,
|
|
10236
|
-
currentVersion: packageVersion,
|
|
10237
|
-
cacheTtlMs: updateRuntimeConfig.cacheTtlMs,
|
|
10238
|
-
fetchTimeoutMs: updateRuntimeConfig.fetchTimeoutMs
|
|
10239
|
-
});
|
|
10240
|
-
return;
|
|
10241
|
-
}
|
|
10242
10551
|
const updateResult = await checkForUpdatesAndMaybeRestart({
|
|
10243
10552
|
packageName,
|
|
10244
10553
|
currentVersion: packageVersion,
|