llm-usage-metrics 0.4.2 → 0.4.3
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 +118 -13
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5337,6 +5337,7 @@ function emitEnvVarOverrides(activeEnvOverrides, diagnosticsLogger) {
|
|
|
5337
5337
|
}
|
|
5338
5338
|
|
|
5339
5339
|
// src/cli/share-artifact.ts
|
|
5340
|
+
import { spawn as spawn3 } from "child_process";
|
|
5340
5341
|
import { writeFile as writeFile4 } from "fs/promises";
|
|
5341
5342
|
import path13 from "path";
|
|
5342
5343
|
async function writeShareSvgFile(fileName, svgContent) {
|
|
@@ -5344,6 +5345,78 @@ async function writeShareSvgFile(fileName, svgContent) {
|
|
|
5344
5345
|
await writeFile4(outputPath, svgContent, "utf8");
|
|
5345
5346
|
return outputPath;
|
|
5346
5347
|
}
|
|
5348
|
+
function stringifyError(error) {
|
|
5349
|
+
if (error instanceof Error) {
|
|
5350
|
+
return error.message;
|
|
5351
|
+
}
|
|
5352
|
+
return String(error);
|
|
5353
|
+
}
|
|
5354
|
+
function resolveOpenCommand(filePath, platform) {
|
|
5355
|
+
if (platform === "win32") {
|
|
5356
|
+
return {
|
|
5357
|
+
command: "cmd",
|
|
5358
|
+
args: ["/c", "start", "", filePath]
|
|
5359
|
+
};
|
|
5360
|
+
}
|
|
5361
|
+
if (platform === "darwin") {
|
|
5362
|
+
return {
|
|
5363
|
+
command: "open",
|
|
5364
|
+
args: [filePath]
|
|
5365
|
+
};
|
|
5366
|
+
}
|
|
5367
|
+
return {
|
|
5368
|
+
command: "xdg-open",
|
|
5369
|
+
args: [filePath]
|
|
5370
|
+
};
|
|
5371
|
+
}
|
|
5372
|
+
async function spawnDetached(command, args) {
|
|
5373
|
+
await new Promise((resolve, reject) => {
|
|
5374
|
+
const child = spawn3(command, args, {
|
|
5375
|
+
detached: true,
|
|
5376
|
+
stdio: "ignore",
|
|
5377
|
+
windowsHide: true
|
|
5378
|
+
});
|
|
5379
|
+
const cleanup = () => {
|
|
5380
|
+
child.removeListener("error", onError);
|
|
5381
|
+
child.removeListener("spawn", onSpawn);
|
|
5382
|
+
};
|
|
5383
|
+
const onError = (error) => {
|
|
5384
|
+
cleanup();
|
|
5385
|
+
reject(error);
|
|
5386
|
+
};
|
|
5387
|
+
const onSpawn = () => {
|
|
5388
|
+
cleanup();
|
|
5389
|
+
child.unref();
|
|
5390
|
+
resolve();
|
|
5391
|
+
};
|
|
5392
|
+
child.once("error", onError);
|
|
5393
|
+
child.once("spawn", onSpawn);
|
|
5394
|
+
});
|
|
5395
|
+
}
|
|
5396
|
+
async function openShareSvgFile(filePath, deps = {}) {
|
|
5397
|
+
const platform = deps.platform ?? process.platform;
|
|
5398
|
+
const runDetached = deps.spawnDetached ?? spawnDetached;
|
|
5399
|
+
const { command, args } = resolveOpenCommand(filePath, platform);
|
|
5400
|
+
await runDetached(command, args);
|
|
5401
|
+
}
|
|
5402
|
+
async function writeAndOpenShareSvgFile(fileName, svgContent, deps = {}) {
|
|
5403
|
+
const writeShareSvg = deps.writeShareSvgFileFn ?? writeShareSvgFile;
|
|
5404
|
+
const openShareSvg = deps.openShareSvgFileFn ?? openShareSvgFile;
|
|
5405
|
+
const outputPath = await writeShareSvg(fileName, svgContent);
|
|
5406
|
+
try {
|
|
5407
|
+
await openShareSvg(outputPath);
|
|
5408
|
+
return {
|
|
5409
|
+
outputPath,
|
|
5410
|
+
opened: true
|
|
5411
|
+
};
|
|
5412
|
+
} catch (error) {
|
|
5413
|
+
return {
|
|
5414
|
+
outputPath,
|
|
5415
|
+
opened: false,
|
|
5416
|
+
openErrorMessage: stringifyError(error)
|
|
5417
|
+
};
|
|
5418
|
+
}
|
|
5419
|
+
}
|
|
5347
5420
|
|
|
5348
5421
|
// src/render/table-text-layout.ts
|
|
5349
5422
|
var ansiEscapePattern = new RegExp(String.raw`\u001B\[[0-9;]*m`, "gu");
|
|
@@ -6454,11 +6527,18 @@ async function runEfficiencyReport(granularity, options) {
|
|
|
6454
6527
|
});
|
|
6455
6528
|
}
|
|
6456
6529
|
if (preparedReport.shareSvg) {
|
|
6457
|
-
const
|
|
6530
|
+
const shareResult = await writeAndOpenShareSvgFile(
|
|
6458
6531
|
"efficiency-monthly-share.svg",
|
|
6459
6532
|
preparedReport.shareSvg
|
|
6460
6533
|
);
|
|
6461
|
-
logger.info(`Wrote efficiency share SVG: ${outputPath}`);
|
|
6534
|
+
logger.info(`Wrote efficiency share SVG: ${shareResult.outputPath}`);
|
|
6535
|
+
if (shareResult.opened) {
|
|
6536
|
+
logger.info(`Opened efficiency share SVG: ${shareResult.outputPath}`);
|
|
6537
|
+
} else {
|
|
6538
|
+
logger.warn(
|
|
6539
|
+
`Could not open efficiency share SVG: ${shareResult.outputPath} (${shareResult.openErrorMessage})`
|
|
6540
|
+
);
|
|
6541
|
+
}
|
|
6462
6542
|
}
|
|
6463
6543
|
console.log(preparedReport.output);
|
|
6464
6544
|
}
|
|
@@ -7227,11 +7307,18 @@ async function runOptimizeReport(granularity, options) {
|
|
|
7227
7307
|
});
|
|
7228
7308
|
}
|
|
7229
7309
|
if (preparedReport.shareSvg) {
|
|
7230
|
-
const
|
|
7310
|
+
const shareResult = await writeAndOpenShareSvgFile(
|
|
7231
7311
|
"optimize-monthly-share.svg",
|
|
7232
7312
|
preparedReport.shareSvg
|
|
7233
7313
|
);
|
|
7234
|
-
logger.info(`Wrote optimize share SVG: ${outputPath}`);
|
|
7314
|
+
logger.info(`Wrote optimize share SVG: ${shareResult.outputPath}`);
|
|
7315
|
+
if (shareResult.opened) {
|
|
7316
|
+
logger.info(`Opened optimize share SVG: ${shareResult.outputPath}`);
|
|
7317
|
+
} else {
|
|
7318
|
+
logger.warn(
|
|
7319
|
+
`Could not open optimize share SVG: ${shareResult.outputPath} (${shareResult.openErrorMessage})`
|
|
7320
|
+
);
|
|
7321
|
+
}
|
|
7235
7322
|
}
|
|
7236
7323
|
console.log(preparedReport.output);
|
|
7237
7324
|
}
|
|
@@ -7296,6 +7383,11 @@ var H3 = 560;
|
|
|
7296
7383
|
var ACCENT_H3 = 4;
|
|
7297
7384
|
var FOOTER_H3 = 36;
|
|
7298
7385
|
var pad3 = { top: 140, right: 80, bottom: 60 + FOOTER_H3, left: 200 };
|
|
7386
|
+
var STAT_X = 60;
|
|
7387
|
+
var STAT_VALUE_FONT_SIZE = 52;
|
|
7388
|
+
var STAT_VALUE_WIDTH_FACTOR = 0.6;
|
|
7389
|
+
var SOURCE_PILLS_MIN_X = pad3.left + 10;
|
|
7390
|
+
var SOURCE_PILLS_STAT_GAP = 24;
|
|
7299
7391
|
function extractPeriodSourceRows(rows) {
|
|
7300
7392
|
return rows.filter((r) => r.rowType === "period_source");
|
|
7301
7393
|
}
|
|
@@ -7336,7 +7428,7 @@ function renderAccentBar() {
|
|
|
7336
7428
|
return `<rect width="${W3}" height="${ACCENT_H3}" fill="url(#accent-grad)"/>`;
|
|
7337
7429
|
}
|
|
7338
7430
|
function renderStatColumn(totalTokens, costUsd, sourceCount) {
|
|
7339
|
-
const x =
|
|
7431
|
+
const x = STAT_X;
|
|
7340
7432
|
const baseY = ACCENT_H3 + 48;
|
|
7341
7433
|
let svg = "";
|
|
7342
7434
|
svg += `<text x="${x}" y="${baseY}" fill="${shareTheme.textPrimary}" font-family="${shareTheme.font}" font-size="52" font-weight="800">${escapeSvg(formatCompact(totalTokens))}</text>
|
|
@@ -7351,9 +7443,9 @@ function renderStatColumn(totalTokens, costUsd, sourceCount) {
|
|
|
7351
7443
|
`;
|
|
7352
7444
|
return svg;
|
|
7353
7445
|
}
|
|
7354
|
-
function renderSourcePills(series) {
|
|
7446
|
+
function renderSourcePills(series, startX) {
|
|
7355
7447
|
let svg = "";
|
|
7356
|
-
let cx =
|
|
7448
|
+
let cx = Math.max(SOURCE_PILLS_MIN_X, startX);
|
|
7357
7449
|
const pillY = ACCENT_H3 + 30;
|
|
7358
7450
|
for (const s of series) {
|
|
7359
7451
|
const label = `${s.source} ${formatCompact(s.total)}`;
|
|
@@ -7370,6 +7462,10 @@ function renderSourcePills(series) {
|
|
|
7370
7462
|
}
|
|
7371
7463
|
return svg;
|
|
7372
7464
|
}
|
|
7465
|
+
function estimateStatValueRightEdge(totalTokens) {
|
|
7466
|
+
const value = formatCompact(totalTokens);
|
|
7467
|
+
return STAT_X + value.length * STAT_VALUE_FONT_SIZE * STAT_VALUE_WIDTH_FACTOR;
|
|
7468
|
+
}
|
|
7373
7469
|
function renderCommandBadge(command) {
|
|
7374
7470
|
const textW = command.length * 9;
|
|
7375
7471
|
const badgeW = textW + 28;
|
|
@@ -7494,6 +7590,7 @@ function renderUsageShareSvg(usageData, granularity) {
|
|
|
7494
7590
|
const toX = (p) => chartLeft + (periodCount <= 1 ? chartW / 2 : p / (periodCount - 1) * chartW);
|
|
7495
7591
|
const toChartY = (val) => scaleY(val, maxY, chartTop, chartBottom);
|
|
7496
7592
|
const commandText = `llm-usage ${granularity} --share`;
|
|
7593
|
+
const sourcePillsStartX = estimateStatValueRightEdge(totalTokens) + SOURCE_PILLS_STAT_GAP;
|
|
7497
7594
|
let chartContent;
|
|
7498
7595
|
if (periodCount === 0) {
|
|
7499
7596
|
chartContent = `<text x="${(W3 / 2).toFixed(0)}" y="${(H3 / 2).toFixed(0)}" text-anchor="middle" font-size="20" fill="${shareTheme.textSecondary}" font-family="${shareTheme.font}">No usage data available</text>`;
|
|
@@ -7530,7 +7627,7 @@ function renderUsageShareSvg(usageData, granularity) {
|
|
|
7530
7627
|
<rect width="${W3}" height="${H3}" fill="${shareTheme.bg}"/>
|
|
7531
7628
|
${renderAccentBar()}
|
|
7532
7629
|
${renderStatColumn(totalTokens, totalCost, activeSeries.length)}
|
|
7533
|
-
${renderSourcePills(activeSeries)}
|
|
7630
|
+
${renderSourcePills(activeSeries, sourcePillsStartX)}
|
|
7534
7631
|
${renderCommandBadge(commandText)}
|
|
7535
7632
|
${renderGridLines(chartLeft, chartRight, chartTop, chartH, maxY)}
|
|
7536
7633
|
${chartContent}
|
|
@@ -7584,11 +7681,18 @@ async function runUsageReport(granularity, options) {
|
|
|
7584
7681
|
});
|
|
7585
7682
|
}
|
|
7586
7683
|
if (preparedReport.shareSvg) {
|
|
7587
|
-
const
|
|
7684
|
+
const shareResult = await writeAndOpenShareSvgFile(
|
|
7588
7685
|
resolveShareFileName(granularity),
|
|
7589
7686
|
preparedReport.shareSvg
|
|
7590
7687
|
);
|
|
7591
|
-
logger.info(`Wrote usage share SVG: ${outputPath}`);
|
|
7688
|
+
logger.info(`Wrote usage share SVG: ${shareResult.outputPath}`);
|
|
7689
|
+
if (shareResult.opened) {
|
|
7690
|
+
logger.info(`Opened usage share SVG: ${shareResult.outputPath}`);
|
|
7691
|
+
} else {
|
|
7692
|
+
logger.warn(
|
|
7693
|
+
`Could not open usage share SVG: ${shareResult.outputPath} (${shareResult.openErrorMessage})`
|
|
7694
|
+
);
|
|
7695
|
+
}
|
|
7592
7696
|
}
|
|
7593
7697
|
console.log(preparedReport.output);
|
|
7594
7698
|
}
|
|
@@ -7759,7 +7863,7 @@ function loadPackageMetadataFromRuntime() {
|
|
|
7759
7863
|
var { packageName, packageVersion } = loadPackageMetadataFromRuntime();
|
|
7760
7864
|
var updateRuntimeConfig = getUpdateNotifierRuntimeConfig();
|
|
7761
7865
|
var cli = createCli({ version: packageVersion });
|
|
7762
|
-
|
|
7866
|
+
async function main() {
|
|
7763
7867
|
const updateResult = await checkForUpdatesAndMaybeRestart({
|
|
7764
7868
|
packageName,
|
|
7765
7869
|
currentVersion: packageVersion,
|
|
@@ -7771,9 +7875,10 @@ try {
|
|
|
7771
7875
|
} else {
|
|
7772
7876
|
await cli.parseAsync(process.argv);
|
|
7773
7877
|
}
|
|
7774
|
-
}
|
|
7878
|
+
}
|
|
7879
|
+
main().catch((error) => {
|
|
7775
7880
|
const message = error instanceof Error ? error.message : String(error);
|
|
7776
7881
|
console.error(message);
|
|
7777
7882
|
process.exitCode = 1;
|
|
7778
|
-
}
|
|
7883
|
+
});
|
|
7779
7884
|
//# sourceMappingURL=index.js.map
|