tokenleak 0.2.0 → 0.3.0

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/tokenleak.js +17 -6
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tokenleak",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Visualise your AI coding-assistant token usage across providers — heatmaps, dashboards, and shareable cards.",
5
5
  "type": "module",
6
6
  "bin": {
package/tokenleak.js CHANGED
@@ -1651,9 +1651,10 @@ function buildInsights(stats, providers) {
1651
1651
  if (stats.topModels.length > 0) {
1652
1652
  const top = stats.topModels[0];
1653
1653
  if (top) {
1654
+ const pct = top.percentage < 1 ? top.percentage * 100 : top.percentage;
1654
1655
  items.push({
1655
1656
  label: "Top Model",
1656
- value: `${top.model} (${top.percentage.toFixed(1)}%)`
1657
+ value: `${top.model} (${pct.toFixed(1)}%)`
1657
1658
  });
1658
1659
  }
1659
1660
  }
@@ -1748,7 +1749,8 @@ function renderModelChart(topModels2, theme) {
1748
1749
  if (barWidth > 0) {
1749
1750
  children.push(rect(BAR_LABEL_WIDTH, y, barWidth, BAR_HEIGHT, theme.accentSecondary, 3));
1750
1751
  }
1751
- const valueStr = `${formatNumber(entry.tokens)} (${entry.percentage.toFixed(1)}%)`;
1752
+ const pct = entry.percentage < 1 ? entry.percentage * 100 : entry.percentage;
1753
+ const valueStr = `${formatNumber(entry.tokens)} (${pct.toFixed(1)}%)`;
1752
1754
  children.push(text(BAR_LABEL_WIDTH + barAreaWidth + 8, y + BAR_HEIGHT - 4, valueStr, {
1753
1755
  fill: theme.foreground,
1754
1756
  "font-size": FONT_SIZE_SMALL,
@@ -1761,13 +1763,15 @@ function renderModelChart(topModels2, theme) {
1761
1763
  }
1762
1764
 
1763
1765
  // packages/renderers/dist/svg/svg-renderer.js
1766
+ var MIN_SVG_WIDTH = 520;
1767
+
1764
1768
  class SvgRenderer {
1765
1769
  format = "svg";
1766
1770
  async render(output, options) {
1767
1771
  const theme = getTheme(options.theme);
1768
- const contentWidth = options.width - PADDING * 2;
1769
1772
  let y = PADDING;
1770
1773
  const sections = [];
1774
+ const sectionWidths = [];
1771
1775
  sections.push(group([
1772
1776
  text(PADDING, y + FONT_SIZE_TITLE + 4, "Tokenleak", {
1773
1777
  fill: theme.foreground,
@@ -1805,6 +1809,7 @@ class SvgRenderer {
1805
1809
  endDate: output.dateRange.until
1806
1810
  });
1807
1811
  sections.push(group([heatmap.svg], `translate(${PADDING}, ${y})`));
1812
+ sectionWidths.push(heatmap.width);
1808
1813
  y += heatmap.height + SECTION_GAP;
1809
1814
  }
1810
1815
  sections.push(text(PADDING, y, "Statistics", {
@@ -1816,6 +1821,7 @@ class SvgRenderer {
1816
1821
  y += 16;
1817
1822
  const stats = renderStatsPanel(output.aggregated, theme);
1818
1823
  sections.push(group([stats.svg], `translate(${PADDING}, ${y})`));
1824
+ sectionWidths.push(stats.width);
1819
1825
  y += stats.height + SECTION_GAP;
1820
1826
  if (output.aggregated.dayOfWeek.length > 0) {
1821
1827
  sections.push(text(PADDING, y, "Day of Week", {
@@ -1827,6 +1833,7 @@ class SvgRenderer {
1827
1833
  y += 16;
1828
1834
  const dowChart = renderDayOfWeekChart(output.aggregated.dayOfWeek, theme);
1829
1835
  sections.push(group([dowChart.svg], `translate(${PADDING}, ${y})`));
1836
+ sectionWidths.push(dowChart.width);
1830
1837
  y += dowChart.height + SECTION_GAP;
1831
1838
  }
1832
1839
  if (output.aggregated.topModels.length > 0) {
@@ -1839,6 +1846,7 @@ class SvgRenderer {
1839
1846
  y += 16;
1840
1847
  const modelChart = renderModelChart(output.aggregated.topModels, theme);
1841
1848
  sections.push(group([modelChart.svg], `translate(${PADDING}, ${y})`));
1849
+ sectionWidths.push(modelChart.width);
1842
1850
  y += modelChart.height + SECTION_GAP;
1843
1851
  }
1844
1852
  if (options.showInsights) {
@@ -1851,12 +1859,15 @@ class SvgRenderer {
1851
1859
  y += 16;
1852
1860
  const insights = renderInsightsPanel(output.aggregated, output.providers, theme);
1853
1861
  sections.push(group([insights.svg], `translate(${PADDING}, ${y})`));
1862
+ sectionWidths.push(insights.width);
1854
1863
  y += insights.height + SECTION_GAP;
1855
1864
  }
1856
1865
  const totalHeight = y + PADDING;
1866
+ const maxContentWidth = sectionWidths.length > 0 ? Math.max(...sectionWidths) : MIN_SVG_WIDTH - PADDING * 2;
1867
+ const svgWidth = Math.max(maxContentWidth + PADDING * 2, MIN_SVG_WIDTH);
1857
1868
  const svgContent = [
1858
- `<svg xmlns="http://www.w3.org/2000/svg" width="${options.width}" height="${totalHeight}" viewBox="0 0 ${options.width} ${totalHeight}">`,
1859
- rect(0, 0, options.width, totalHeight, theme.background, 8),
1869
+ `<svg xmlns="http://www.w3.org/2000/svg" width="${svgWidth}" height="${totalHeight}" viewBox="0 0 ${svgWidth} ${totalHeight}">`,
1870
+ rect(0, 0, svgWidth, totalHeight, theme.background, 8),
1860
1871
  ...sections,
1861
1872
  "</svg>"
1862
1873
  ].join(`
@@ -2107,7 +2118,7 @@ function renderDayOfWeek(stats, width, noColor2) {
2107
2118
  function renderTopModels(stats, width, noColor2) {
2108
2119
  const lines = [];
2109
2120
  for (const model of stats.topModels.slice(0, 5)) {
2110
- const pct = formatPercent2(model.percentage / 100);
2121
+ const pct = formatPercent2(model.percentage);
2111
2122
  const tokens = formatTokens(model.tokens);
2112
2123
  const line = ` ${colorize(model.model, "yellow", noColor2)} ${tokens} ${pct}`;
2113
2124
  lines.push(line.length > width ? line.slice(0, width) : line);