llm-usage-metrics 0.4.1 → 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 +124 -21
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2580,7 +2580,7 @@ function renderCommitBarLabels(monthlyRows, chartLeft, stepX, maxCommits, chartT
|
|
|
2580
2580
|
return monthlyRows.map((row, i) => {
|
|
2581
2581
|
const x = chartLeft + i * stepX;
|
|
2582
2582
|
const yTop = scaleY(row.commitCount, maxCommits, chartTop, chartBottom);
|
|
2583
|
-
return `<text x="${x.toFixed(2)}" y="${(yTop - 8).toFixed(0)}" text-anchor="middle" font-size="12" font-weight="600" fill="${shareTheme.textSecondary}" font-family="${shareTheme.font}">${formatInteger(row.commitCount)}</text>`;
|
|
2583
|
+
return `<text x="${x.toFixed(2)}" y="${(yTop - 8).toFixed(0)}" text-anchor="middle" font-size="12" font-weight="600" fill="${shareTheme.textSecondary}" font-family="${shareTheme.font}">${escapeSvg(formatInteger(row.commitCount))}</text>`;
|
|
2584
2584
|
}).join("\n");
|
|
2585
2585
|
}
|
|
2586
2586
|
function renderUsdDataLabels(monthlyRows, usdPoints) {
|
|
@@ -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
|
}
|
|
@@ -7333,16 +7425,10 @@ function buildStackedValues(series) {
|
|
|
7333
7425
|
return stacked;
|
|
7334
7426
|
}
|
|
7335
7427
|
function renderAccentBar() {
|
|
7336
|
-
return
|
|
7337
|
-
`<defs><linearGradient id="accent-grad" x1="0" y1="0" x2="1" y2="0">`,
|
|
7338
|
-
` <stop offset="0%" stop-color="#10b981"/>`,
|
|
7339
|
-
` <stop offset="100%" stop-color="#06b6d4"/>`,
|
|
7340
|
-
`</linearGradient></defs>`,
|
|
7341
|
-
`<rect width="${W3}" height="${ACCENT_H3}" fill="url(#accent-grad)"/>`
|
|
7342
|
-
].join("\n");
|
|
7428
|
+
return `<rect width="${W3}" height="${ACCENT_H3}" fill="url(#accent-grad)"/>`;
|
|
7343
7429
|
}
|
|
7344
7430
|
function renderStatColumn(totalTokens, costUsd, sourceCount) {
|
|
7345
|
-
const x =
|
|
7431
|
+
const x = STAT_X;
|
|
7346
7432
|
const baseY = ACCENT_H3 + 48;
|
|
7347
7433
|
let svg = "";
|
|
7348
7434
|
svg += `<text x="${x}" y="${baseY}" fill="${shareTheme.textPrimary}" font-family="${shareTheme.font}" font-size="52" font-weight="800">${escapeSvg(formatCompact(totalTokens))}</text>
|
|
@@ -7357,9 +7443,9 @@ function renderStatColumn(totalTokens, costUsd, sourceCount) {
|
|
|
7357
7443
|
`;
|
|
7358
7444
|
return svg;
|
|
7359
7445
|
}
|
|
7360
|
-
function renderSourcePills(series) {
|
|
7446
|
+
function renderSourcePills(series, startX) {
|
|
7361
7447
|
let svg = "";
|
|
7362
|
-
let cx =
|
|
7448
|
+
let cx = Math.max(SOURCE_PILLS_MIN_X, startX);
|
|
7363
7449
|
const pillY = ACCENT_H3 + 30;
|
|
7364
7450
|
for (const s of series) {
|
|
7365
7451
|
const label = `${s.source} ${formatCompact(s.total)}`;
|
|
@@ -7376,6 +7462,10 @@ function renderSourcePills(series) {
|
|
|
7376
7462
|
}
|
|
7377
7463
|
return svg;
|
|
7378
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
|
+
}
|
|
7379
7469
|
function renderCommandBadge(command) {
|
|
7380
7470
|
const textW = command.length * 9;
|
|
7381
7471
|
const badgeW = textW + 28;
|
|
@@ -7500,6 +7590,7 @@ function renderUsageShareSvg(usageData, granularity) {
|
|
|
7500
7590
|
const toX = (p) => chartLeft + (periodCount <= 1 ? chartW / 2 : p / (periodCount - 1) * chartW);
|
|
7501
7591
|
const toChartY = (val) => scaleY(val, maxY, chartTop, chartBottom);
|
|
7502
7592
|
const commandText = `llm-usage ${granularity} --share`;
|
|
7593
|
+
const sourcePillsStartX = estimateStatValueRightEdge(totalTokens) + SOURCE_PILLS_STAT_GAP;
|
|
7503
7594
|
let chartContent;
|
|
7504
7595
|
if (periodCount === 0) {
|
|
7505
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>`;
|
|
@@ -7524,6 +7615,10 @@ function renderUsageShareSvg(usageData, granularity) {
|
|
|
7524
7615
|
}
|
|
7525
7616
|
return `<svg xmlns="http://www.w3.org/2000/svg" width="${W3}" height="${H3}" viewBox="0 0 ${W3} ${H3}">
|
|
7526
7617
|
<defs>
|
|
7618
|
+
<linearGradient id="accent-grad" x1="0" y1="0" x2="1" y2="0">
|
|
7619
|
+
<stop offset="0%" stop-color="#10b981"/>
|
|
7620
|
+
<stop offset="100%" stop-color="#06b6d4"/>
|
|
7621
|
+
</linearGradient>
|
|
7527
7622
|
<clipPath id="chart-clip">
|
|
7528
7623
|
<rect x="${chartLeft}" y="${chartTop - 4}" width="${chartW}" height="${chartH + 8}"/>
|
|
7529
7624
|
</clipPath>
|
|
@@ -7532,7 +7627,7 @@ function renderUsageShareSvg(usageData, granularity) {
|
|
|
7532
7627
|
<rect width="${W3}" height="${H3}" fill="${shareTheme.bg}"/>
|
|
7533
7628
|
${renderAccentBar()}
|
|
7534
7629
|
${renderStatColumn(totalTokens, totalCost, activeSeries.length)}
|
|
7535
|
-
${renderSourcePills(activeSeries)}
|
|
7630
|
+
${renderSourcePills(activeSeries, sourcePillsStartX)}
|
|
7536
7631
|
${renderCommandBadge(commandText)}
|
|
7537
7632
|
${renderGridLines(chartLeft, chartRight, chartTop, chartH, maxY)}
|
|
7538
7633
|
${chartContent}
|
|
@@ -7586,11 +7681,18 @@ async function runUsageReport(granularity, options) {
|
|
|
7586
7681
|
});
|
|
7587
7682
|
}
|
|
7588
7683
|
if (preparedReport.shareSvg) {
|
|
7589
|
-
const
|
|
7684
|
+
const shareResult = await writeAndOpenShareSvgFile(
|
|
7590
7685
|
resolveShareFileName(granularity),
|
|
7591
7686
|
preparedReport.shareSvg
|
|
7592
7687
|
);
|
|
7593
|
-
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
|
+
}
|
|
7594
7696
|
}
|
|
7595
7697
|
console.log(preparedReport.output);
|
|
7596
7698
|
}
|
|
@@ -7761,7 +7863,7 @@ function loadPackageMetadataFromRuntime() {
|
|
|
7761
7863
|
var { packageName, packageVersion } = loadPackageMetadataFromRuntime();
|
|
7762
7864
|
var updateRuntimeConfig = getUpdateNotifierRuntimeConfig();
|
|
7763
7865
|
var cli = createCli({ version: packageVersion });
|
|
7764
|
-
|
|
7866
|
+
async function main() {
|
|
7765
7867
|
const updateResult = await checkForUpdatesAndMaybeRestart({
|
|
7766
7868
|
packageName,
|
|
7767
7869
|
currentVersion: packageVersion,
|
|
@@ -7773,9 +7875,10 @@ try {
|
|
|
7773
7875
|
} else {
|
|
7774
7876
|
await cli.parseAsync(process.argv);
|
|
7775
7877
|
}
|
|
7776
|
-
}
|
|
7878
|
+
}
|
|
7879
|
+
main().catch((error) => {
|
|
7777
7880
|
const message = error instanceof Error ? error.message : String(error);
|
|
7778
7881
|
console.error(message);
|
|
7779
7882
|
process.exitCode = 1;
|
|
7780
|
-
}
|
|
7883
|
+
});
|
|
7781
7884
|
//# sourceMappingURL=index.js.map
|