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 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 outputPath = await writeShareSvgFile(
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 outputPath = await writeShareSvgFile(
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 = 60;
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 = pad3.left + 10;
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 outputPath = await writeShareSvgFile(
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
- try {
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
- } catch (error) {
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