ccusage 15.5.0 → 15.5.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.
@@ -1,7 +1,7 @@
1
- import { CLAUDE_CONFIG_DIR_ENV, CLAUDE_PROJECTS_DIR_NAME, DEFAULT_CLAUDE_CODE_PATH, DEFAULT_CLAUDE_CONFIG_PATH, DEFAULT_RECENT_DAYS, PricingFetcher, USAGE_DATA_GLOB_PATTERN, USER_HOME_DIR, __commonJSMin, __require, __toESM, isFailure, isPromise, require_usingCtx } from "./pricing-fetcher-B2yEbqCO.js";
1
+ import { CLAUDE_CONFIG_DIR_ENV, CLAUDE_PROJECTS_DIR_NAME, DEFAULT_CLAUDE_CODE_PATH, DEFAULT_CLAUDE_CONFIG_PATH, DEFAULT_RECENT_DAYS, PricingFetcher, USAGE_DATA_GLOB_PATTERN, USER_HOME_DIR, __commonJSMin, __require, __toESM, isFailure, isPromise, require_usingCtx } from "./pricing-fetcher-B5b61mDE.js";
2
2
  import { getTotalTokens } from "./_token-utils-WjkbrjKv.js";
3
3
  import { activityDateSchema, arrayType, booleanType, createDailyDate, createMonthlyDate, createProjectPath, createSessionId, dailyDateSchema, isoTimestampSchema, messageIdSchema, modelNameSchema, monthlyDateSchema, numberType, objectType, projectPathSchema, requestIdSchema, sessionIdSchema, stringType, versionSchema } from "./_types-BHFM59hI.js";
4
- import { logger } from "./logger-CZzaUNvP.js";
4
+ import { logger } from "./logger-D0z-I-_d.js";
5
5
  import a, { readFile } from "node:fs/promises";
6
6
  import path, { posix } from "node:path";
7
7
  import process$1 from "node:process";
@@ -3543,26 +3543,16 @@ function extractUniqueModels(entries, getModel) {
3543
3543
  return uniq(entries.map(getModel).filter((m$1) => m$1 != null && m$1 !== "<synthetic>"));
3544
3544
  }
3545
3545
  /**
3546
- * Shared method for formatting dates with proper timezone handling
3547
- * @param dateStr - Input date string
3548
- * @param twoLine - Whether to format as two lines (true) or single line (false)
3549
- * @returns Formatted date string
3550
- */
3551
- function formatDateInternal(dateStr, twoLine) {
3552
- const date = new Date(dateStr);
3553
- const hasTimezone = /Z|[+-]\d{2}:\d{2}/.test(dateStr);
3554
- const year = hasTimezone ? date.getUTCFullYear() : date.getFullYear();
3555
- const month = String(hasTimezone ? date.getUTCMonth() + 1 : date.getMonth() + 1).padStart(2, "0");
3556
- const day = String(hasTimezone ? date.getUTCDate() : date.getDate()).padStart(2, "0");
3557
- return twoLine ? `${year}\n${month}-${day}` : `${year}-${month}-${day}`;
3558
- }
3559
- /**
3560
3546
  * Formats a date string to YYYY-MM-DD format
3561
3547
  * @param dateStr - Input date string
3562
3548
  * @returns Formatted date string in YYYY-MM-DD format
3563
3549
  */
3564
3550
  function formatDate(dateStr) {
3565
- return formatDateInternal(dateStr, false);
3551
+ const date = new Date(dateStr);
3552
+ const year = date.getFullYear();
3553
+ const month = String(date.getMonth() + 1).padStart(2, "0");
3554
+ const day = String(date.getDate()).padStart(2, "0");
3555
+ return `${year}-${month}-${day}`;
3566
3556
  }
3567
3557
  /**
3568
3558
  * Formats a date string to compact format with year on first line and month-day on second
@@ -3570,7 +3560,11 @@ function formatDate(dateStr) {
3570
3560
  * @returns Formatted date string with newline separator (YYYY\nMM-DD)
3571
3561
  */
3572
3562
  function formatDateCompact(dateStr) {
3573
- return formatDateInternal(dateStr, true);
3563
+ const date = new Date(dateStr);
3564
+ const year = date.getFullYear();
3565
+ const month = String(date.getMonth() + 1).padStart(2, "0");
3566
+ const day = String(date.getDate()).padStart(2, "0");
3567
+ return `${year}\n${month}-${day}`;
3574
3568
  }
3575
3569
  /**
3576
3570
  * Generic function to sort items by date based on sort order
@@ -1,6 +1,6 @@
1
- import "./pricing-fetcher-B2yEbqCO.js";
1
+ import "./pricing-fetcher-B5b61mDE.js";
2
2
  import "./_token-utils-WjkbrjKv.js";
3
3
  import "./_types-BHFM59hI.js";
4
- import { calculateCostForEntry, createUniqueHash, dailyUsageSchema, extractProjectFromPath, formatDate, formatDateCompact, getClaudePaths, getEarliestTimestamp, getUsageLimitResetTime, globUsageFiles, loadDailyUsageData, loadMonthlyUsageData, loadSessionBlockData, loadSessionData, modelBreakdownSchema, monthlyUsageSchema, sessionUsageSchema, sortFilesByTimestamp, usageDataSchema } from "./data-loader-BVwVxx4T.js";
5
- import "./logger-CZzaUNvP.js";
4
+ import { calculateCostForEntry, createUniqueHash, dailyUsageSchema, extractProjectFromPath, formatDate, formatDateCompact, getClaudePaths, getEarliestTimestamp, getUsageLimitResetTime, globUsageFiles, loadDailyUsageData, loadMonthlyUsageData, loadSessionBlockData, loadSessionData, modelBreakdownSchema, monthlyUsageSchema, sessionUsageSchema, sortFilesByTimestamp, usageDataSchema } from "./data-loader-CmW1xurn.js";
5
+ import "./logger-D0z-I-_d.js";
6
6
  export { calculateCostForEntry, createUniqueHash, dailyUsageSchema, extractProjectFromPath, formatDate, formatDateCompact, getClaudePaths, getEarliestTimestamp, getUsageLimitResetTime, globUsageFiles, loadDailyUsageData, loadMonthlyUsageData, loadSessionBlockData, loadSessionData, modelBreakdownSchema, monthlyUsageSchema, sessionUsageSchema, sortFilesByTimestamp, usageDataSchema };
@@ -1,6 +1,6 @@
1
- import { CLAUDE_PROJECTS_DIR_NAME, DEBUG_MATCH_THRESHOLD_PERCENT, PricingFetcher, USAGE_DATA_GLOB_PATTERN, __toESM, isFailure, require_usingCtx, try_ } from "./pricing-fetcher-B2yEbqCO.js";
2
- import { getClaudePaths, glob, unwrap, usageDataSchema } from "./data-loader-BVwVxx4T.js";
3
- import { logger } from "./logger-CZzaUNvP.js";
1
+ import { CLAUDE_PROJECTS_DIR_NAME, DEBUG_MATCH_THRESHOLD_PERCENT, PricingFetcher, USAGE_DATA_GLOB_PATTERN, __toESM, isFailure, require_usingCtx, try_ } from "./pricing-fetcher-B5b61mDE.js";
2
+ import { getClaudePaths, glob, unwrap, usageDataSchema } from "./data-loader-CmW1xurn.js";
3
+ import { logger } from "./logger-D0z-I-_d.js";
4
4
  import { readFile } from "node:fs/promises";
5
5
  import path from "node:path";
6
6
  var import_usingCtx = __toESM(require_usingCtx(), 1);
package/dist/debug.js CHANGED
@@ -1,7 +1,7 @@
1
- import "./pricing-fetcher-B2yEbqCO.js";
1
+ import "./pricing-fetcher-B5b61mDE.js";
2
2
  import "./_token-utils-WjkbrjKv.js";
3
3
  import "./_types-BHFM59hI.js";
4
- import "./data-loader-BVwVxx4T.js";
5
- import "./logger-CZzaUNvP.js";
6
- import { detectMismatches, printMismatchReport } from "./debug-DtmspKbf.js";
4
+ import "./data-loader-CmW1xurn.js";
5
+ import "./logger-D0z-I-_d.js";
6
+ import { detectMismatches, printMismatchReport } from "./debug-kkVHYWpk.js";
7
7
  export { detectMismatches, printMismatchReport };
package/dist/index.js CHANGED
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env node
2
- import { BLOCKS_COMPACT_WIDTH_THRESHOLD, BLOCKS_DEFAULT_TERMINAL_WIDTH, BLOCKS_WARNING_THRESHOLD, BURN_RATE_THRESHOLDS, DEFAULT_RECENT_DAYS, DEFAULT_REFRESH_INTERVAL_SECONDS, MAX_REFRESH_INTERVAL_SECONDS, MCP_DEFAULT_PORT, MIN_REFRESH_INTERVAL_SECONDS, MIN_RENDER_INTERVAL_MS, PROJECT_ALIASES_ENV, PricingFetcher, __commonJSMin, __require, __toESM, isFailure, require_usingCtx, try_ } from "./pricing-fetcher-B2yEbqCO.js";
2
+ import { BLOCKS_COMPACT_WIDTH_THRESHOLD, BLOCKS_DEFAULT_TERMINAL_WIDTH, BLOCKS_WARNING_THRESHOLD, BURN_RATE_THRESHOLDS, DEFAULT_RECENT_DAYS, DEFAULT_REFRESH_INTERVAL_SECONDS, MAX_REFRESH_INTERVAL_SECONDS, MCP_DEFAULT_PORT, MIN_REFRESH_INTERVAL_SECONDS, MIN_RENDER_INTERVAL_MS, PROJECT_ALIASES_ENV, PricingFetcher, __commonJSMin, __require, __toESM, isFailure, require_usingCtx, try_ } from "./pricing-fetcher-B5b61mDE.js";
3
3
  import { getTotalTokens } from "./_token-utils-WjkbrjKv.js";
4
4
  import { CostModes, SortOrders, filterDateSchema } from "./_types-BHFM59hI.js";
5
5
  import { calculateTotals, createTotalsObject } from "./calculate-cost-BDqO4yWA.js";
6
- import { DEFAULT_SESSION_DURATION_HOURS, calculateBurnRate, calculateCostForEntry, createUniqueHash, filterRecentBlocks, formatDateCompact, getClaudePaths, getEarliestTimestamp, getUsageLimitResetTime, globUsageFiles, identifySessionBlocks, loadDailyUsageData, loadMonthlyUsageData, loadSessionBlockData, loadSessionData, projectBlockUsage, sortFilesByTimestamp, uniq, usageDataSchema } from "./data-loader-BVwVxx4T.js";
7
- import { description, log, logger, name, version } from "./logger-CZzaUNvP.js";
8
- import { detectMismatches, printMismatchReport } from "./debug-DtmspKbf.js";
9
- import { createMcpHttpApp, createMcpServer, startMcpServerStdio } from "./mcp-DRNUcHZe.js";
6
+ import { DEFAULT_SESSION_DURATION_HOURS, calculateBurnRate, calculateCostForEntry, createUniqueHash, filterRecentBlocks, formatDateCompact, getClaudePaths, getEarliestTimestamp, getUsageLimitResetTime, globUsageFiles, identifySessionBlocks, loadDailyUsageData, loadMonthlyUsageData, loadSessionBlockData, loadSessionData, projectBlockUsage, sortFilesByTimestamp, uniq, usageDataSchema } from "./data-loader-CmW1xurn.js";
7
+ import { description, log, logger, name, version } from "./logger-D0z-I-_d.js";
8
+ import { detectMismatches, printMismatchReport } from "./debug-kkVHYWpk.js";
9
+ import { createMcpHttpApp, createMcpServer, startMcpServerStdio } from "./mcp-DbViDMcM.js";
10
10
  import { readFile } from "node:fs/promises";
11
11
  import process$1 from "node:process";
12
12
  import { createServer } from "node:http";
@@ -3729,13 +3729,6 @@ function formatTokensShort(num) {
3729
3729
  return num.toString();
3730
3730
  }
3731
3731
  /**
3732
- * Column layout constants for detail rows
3733
- */
3734
- const DETAIL_COLUMN_WIDTHS = {
3735
- col1: 46,
3736
- col2: 37
3737
- };
3738
- /**
3739
3732
  * Renders the live display for an active session block
3740
3733
  */
3741
3734
  function renderLiveDisplay(terminal, block, config) {
@@ -3744,6 +3737,9 @@ function renderLiveDisplay(terminal, block, config) {
3744
3737
  const totalTokens = getTotalTokens(block.tokenCounts);
3745
3738
  const elapsed = (now.getTime() - block.startTime.getTime()) / (1e3 * 60);
3746
3739
  const remaining = (block.endTime.getTime() - now.getTime()) / (1e3 * 60);
3740
+ const formatTokenDisplay = (tokens, useShort) => {
3741
+ return useShort ? formatTokensShort(tokens) : formatNumber(tokens);
3742
+ };
3747
3743
  if (width < 60) {
3748
3744
  renderCompactLiveDisplay(terminal, block, config, totalTokens, elapsed, remaining);
3749
3745
  return;
@@ -3751,12 +3747,19 @@ function renderLiveDisplay(terminal, block, config) {
3751
3747
  const boxWidth = Math.min(120, width - 2);
3752
3748
  const boxMargin = Math.floor((width - boxWidth) / 2);
3753
3749
  const marginStr = " ".repeat(boxMargin);
3754
- const labelWidth = 14;
3755
- const percentWidth = 7;
3756
- const shortLabelWidth = 20;
3757
- const barWidth = boxWidth - labelWidth - percentWidth - shortLabelWidth - 4;
3758
3750
  const sessionDuration = elapsed + remaining;
3759
3751
  const sessionPercent = elapsed / sessionDuration * 100;
3752
+ const sessionRightText = `${sessionPercent.toFixed(1).padStart(6)}%`;
3753
+ const tokenPercent = config.tokenLimit != null && config.tokenLimit > 0 ? totalTokens / config.tokenLimit * 100 : 0;
3754
+ const usageRightText = config.tokenLimit != null && config.tokenLimit > 0 ? `${tokenPercent.toFixed(1).padStart(6)}% (${formatTokensShort(totalTokens)}/${formatTokensShort(config.tokenLimit)})` : `(${formatTokensShort(totalTokens)} tokens)`;
3755
+ const projection = projectBlockUsage(block);
3756
+ const projectedPercent = projection != null && config.tokenLimit != null && config.tokenLimit > 0 ? projection.totalTokens / config.tokenLimit * 100 : 0;
3757
+ const projectionRightText = projection != null ? config.tokenLimit != null && config.tokenLimit > 0 ? `${projectedPercent.toFixed(1).padStart(6)}% (${formatTokensShort(projection.totalTokens)}/${formatTokensShort(config.tokenLimit)})` : `(${formatTokensShort(projection.totalTokens)} tokens)` : "";
3758
+ const maxRightTextWidth = Math.max(stringWidth(sessionRightText), stringWidth(usageRightText), projection != null ? stringWidth(projectionRightText) : 0);
3759
+ const labelWidth = 14;
3760
+ const spacing = 4;
3761
+ const boxPadding = 4;
3762
+ const barWidth = boxWidth - labelWidth - maxRightTextWidth - spacing - boxPadding;
3760
3763
  const sessionProgressBar = createProgressBar(elapsed, sessionDuration, barWidth, {
3761
3764
  showPercentage: false,
3762
3765
  fillChar: import_picocolors$5.default.cyan("█"),
@@ -3776,23 +3779,24 @@ function renderLiveDisplay(terminal, block, config) {
3776
3779
  second: "2-digit",
3777
3780
  hour12: true
3778
3781
  });
3782
+ const detailsIndent = 3;
3783
+ const detailsSpacing = 2;
3784
+ const detailsAvailableWidth = boxWidth - 3 - detailsIndent;
3779
3785
  terminal.write(`${marginStr}┌${"─".repeat(boxWidth - 2)}┐\n`);
3780
3786
  terminal.write(`${marginStr}│${import_picocolors$5.default.bold(centerText("CLAUDE CODE - LIVE TOKEN USAGE MONITOR", boxWidth - 2))}│\n`);
3781
3787
  terminal.write(`${marginStr}├${"─".repeat(boxWidth - 2)}┤\n`);
3782
3788
  terminal.write(`${marginStr}│${" ".repeat(boxWidth - 2)}│\n`);
3783
3789
  const sessionLabel = import_picocolors$5.default.bold("⏱️ SESSION");
3784
3790
  const sessionLabelWidth = stringWidth(sessionLabel);
3785
- const sessionBarStr = `${sessionLabel}${"".padEnd(Math.max(0, labelWidth - sessionLabelWidth))} ${sessionProgressBar} ${sessionPercent.toFixed(1).padStart(6)}%`;
3791
+ const sessionBarStr = `${sessionLabel}${"".padEnd(Math.max(0, labelWidth - sessionLabelWidth))} ${sessionProgressBar} ${sessionRightText}`;
3786
3792
  const sessionBarPadded = sessionBarStr + " ".repeat(Math.max(0, boxWidth - 3 - stringWidth(sessionBarStr)));
3787
3793
  terminal.write(`${marginStr}│ ${sessionBarPadded}│\n`);
3788
- const col1 = `${import_picocolors$5.default.gray("Started:")} ${startTime}`;
3789
- const col2 = `${import_picocolors$5.default.gray("Elapsed:")} ${prettyMilliseconds(elapsed * 60 * 1e3, { compact: true })}`;
3790
- const col3 = `${import_picocolors$5.default.gray("Remaining:")} ${prettyMilliseconds(remaining * 60 * 1e3, { compact: true })} (${endTime})`;
3791
- const col1Visible = stringWidth(col1);
3792
- const col2Visible = stringWidth(col2);
3793
- const pad1 = " ".repeat(Math.max(0, DETAIL_COLUMN_WIDTHS.col1 - col1Visible));
3794
- const pad2 = " ".repeat(Math.max(0, DETAIL_COLUMN_WIDTHS.col2 - col2Visible));
3795
- const sessionDetails = ` ${col1}${pad1}${pad2}${col3}`;
3794
+ const sessionCol1 = `${import_picocolors$5.default.gray("Started:")} ${startTime}`;
3795
+ const sessionCol2 = `${import_picocolors$5.default.gray("Elapsed:")} ${prettyMilliseconds(elapsed * 60 * 1e3, { compact: true })}`;
3796
+ const sessionCol3 = `${import_picocolors$5.default.gray("Remaining:")} ${prettyMilliseconds(remaining * 60 * 1e3, { compact: true })} (${endTime})`;
3797
+ let sessionDetails = `${" ".repeat(detailsIndent)}${sessionCol1}${" ".repeat(detailsSpacing)}${sessionCol2}${" ".repeat(detailsSpacing)}${sessionCol3}`;
3798
+ const sessionDetailsWidth = stringWidth(sessionCol1) + stringWidth(sessionCol2) + stringWidth(sessionCol3) + detailsSpacing * 2;
3799
+ if (sessionDetailsWidth > detailsAvailableWidth) sessionDetails = `${" ".repeat(detailsIndent)}${sessionCol1}${" ".repeat(detailsSpacing)}${sessionCol3}`;
3796
3800
  const sessionDetailsPadded = sessionDetails + " ".repeat(Math.max(0, boxWidth - 3 - stringWidth(sessionDetails)));
3797
3801
  let usageLimitResetTimePadded = null;
3798
3802
  if (block.usageLimitResetTime !== void 0 && now < block.usageLimitResetTime) {
@@ -3809,7 +3813,6 @@ function renderLiveDisplay(terminal, block, config) {
3809
3813
  terminal.write(`${marginStr}│${" ".repeat(boxWidth - 2)}│\n`);
3810
3814
  terminal.write(`${marginStr}├${"─".repeat(boxWidth - 2)}┤\n`);
3811
3815
  terminal.write(`${marginStr}│${" ".repeat(boxWidth - 2)}│\n`);
3812
- const tokenPercent = config.tokenLimit != null && config.tokenLimit > 0 ? totalTokens / config.tokenLimit * 100 : 0;
3813
3816
  let barColor = import_picocolors$5.default.green;
3814
3817
  if (tokenPercent > 100) barColor = import_picocolors$5.default.red;
3815
3818
  else if (tokenPercent > 80) barColor = import_picocolors$5.default.yellow;
@@ -3822,35 +3825,51 @@ function renderLiveDisplay(terminal, block, config) {
3822
3825
  }) : `[${import_picocolors$5.default.green("█".repeat(Math.floor(barWidth * .1)))}${import_picocolors$5.default.gray("░".repeat(barWidth - Math.floor(barWidth * .1)))}]`;
3823
3826
  const burnRate = calculateBurnRate(block);
3824
3827
  const rateIndicator = getRateIndicator(burnRate);
3825
- const rateDisplay = burnRate != null ? `${import_picocolors$5.default.bold("Burn Rate:")} ${Math.round(burnRate.tokensPerMinute)} token/min ${rateIndicator}` : `${import_picocolors$5.default.bold("Burn Rate:")} N/A`;
3828
+ const buildRateDisplay = (useShort) => {
3829
+ if (burnRate == null) return `${import_picocolors$5.default.bold("Burn Rate:")} N/A`;
3830
+ const rateValue = Math.round(burnRate.tokensPerMinute);
3831
+ const formattedRate = useShort ? formatTokensShort(rateValue) : formatNumber(rateValue);
3832
+ return `${import_picocolors$5.default.bold("Burn Rate:")} ${formattedRate} token/min ${rateIndicator}`;
3833
+ };
3826
3834
  const usageLabel = import_picocolors$5.default.bold("🔥 USAGE");
3827
3835
  const usageLabelWidth = stringWidth(usageLabel);
3828
- const { usageBarStr, usageCol1, usageCol2, usageCol3 } = config.tokenLimit != null && config.tokenLimit > 0 ? {
3829
- usageBarStr: `${usageLabel}${"".padEnd(Math.max(0, labelWidth - usageLabelWidth))} ${usageBar} ${tokenPercent.toFixed(1).padStart(6)}% (${formatTokensShort(totalTokens)}/${formatTokensShort(config.tokenLimit)})`,
3830
- usageCol1: `${import_picocolors$5.default.gray("Tokens:")} ${formatNumber(totalTokens)} (${rateDisplay})`,
3831
- usageCol2: `${import_picocolors$5.default.gray("Limit:")} ${formatNumber(config.tokenLimit)} tokens`,
3832
- usageCol3: `${import_picocolors$5.default.gray("Cost:")} ${formatCurrency(block.costUSD)}`
3833
- } : {
3834
- usageBarStr: `${usageLabel}${"".padEnd(Math.max(0, labelWidth - usageLabelWidth))} ${usageBar} (${formatTokensShort(totalTokens)} tokens)`,
3835
- usageCol1: `${import_picocolors$5.default.gray("Tokens:")} ${formatNumber(totalTokens)} (${rateDisplay})`,
3836
- usageCol2: "",
3837
- usageCol3: `${import_picocolors$5.default.gray("Cost:")} ${formatCurrency(block.costUSD)}`
3838
- };
3836
+ const usageBarStr = `${usageLabel}${"".padEnd(Math.max(0, labelWidth - usageLabelWidth))} ${usageBar} ${usageRightText}`;
3837
+ let rateDisplay = buildRateDisplay(false);
3838
+ let usageCol1 = `${import_picocolors$5.default.gray("Tokens:")} ${formatTokenDisplay(totalTokens, false)} (${rateDisplay})`;
3839
+ let usageCol2 = config.tokenLimit != null && config.tokenLimit > 0 ? `${import_picocolors$5.default.gray("Limit:")} ${formatTokenDisplay(config.tokenLimit, false)} tokens` : "";
3840
+ const usageCol3 = `${import_picocolors$5.default.gray("Cost:")} ${formatCurrency(block.costUSD)}`;
3841
+ let totalWidth = stringWidth(usageCol1);
3842
+ if (usageCol2.length > 0) totalWidth += detailsSpacing + stringWidth(usageCol2);
3843
+ totalWidth += detailsSpacing + stringWidth(usageCol3);
3844
+ let useTwoLineLayout = false;
3845
+ if (totalWidth > detailsAvailableWidth) {
3846
+ useTwoLineLayout = true;
3847
+ rateDisplay = buildRateDisplay(true);
3848
+ usageCol1 = `${import_picocolors$5.default.gray("Tokens:")} ${formatTokenDisplay(totalTokens, true)} (${rateDisplay})`;
3849
+ if (usageCol2.length > 0) usageCol2 = `${import_picocolors$5.default.gray("Limit:")} ${formatTokenDisplay(config.tokenLimit, true)} tokens`;
3850
+ }
3839
3851
  const usageBarPadded = usageBarStr + " ".repeat(Math.max(0, boxWidth - 3 - stringWidth(usageBarStr)));
3840
3852
  terminal.write(`${marginStr}│ ${usageBarPadded}│\n`);
3841
- const usageCol1Visible = stringWidth(usageCol1);
3842
- const usageCol2Visible = stringWidth(usageCol2);
3843
- const usagePad1 = " ".repeat(Math.max(0, DETAIL_COLUMN_WIDTHS.col1 - usageCol1Visible));
3844
- const usagePad2 = usageCol2.length > 0 ? " ".repeat(Math.max(0, DETAIL_COLUMN_WIDTHS.col2 - usageCol2Visible)) : " ".repeat(DETAIL_COLUMN_WIDTHS.col2);
3845
- const usageDetails = ` ${usageCol1}${usagePad1}${usageCol2}${usagePad2}${usageCol3}`;
3846
- const usageDetailsPadded = usageDetails + " ".repeat(Math.max(0, boxWidth - 3 - stringWidth(usageDetails)));
3847
- terminal.write(`${marginStr}${usageDetailsPadded}│\n`);
3853
+ if (useTwoLineLayout) {
3854
+ const usageDetailsLine1 = `${" ".repeat(detailsIndent)}${usageCol1}`;
3855
+ const usageDetailsLine1Padded = usageDetailsLine1 + " ".repeat(Math.max(0, boxWidth - 3 - stringWidth(usageDetailsLine1)));
3856
+ terminal.write(`${marginStr}│ ${usageDetailsLine1Padded}│\n`);
3857
+ let usageDetailsLine2;
3858
+ if (usageCol2.length > 0) usageDetailsLine2 = `${" ".repeat(detailsIndent)}${usageCol2}${" ".repeat(detailsSpacing)}${usageCol3}`;
3859
+ else usageDetailsLine2 = `${" ".repeat(detailsIndent)}${usageCol3}`;
3860
+ const usageDetailsLine2Padded = usageDetailsLine2 + " ".repeat(Math.max(0, boxWidth - 3 - stringWidth(usageDetailsLine2)));
3861
+ terminal.write(`${marginStr}│ ${usageDetailsLine2Padded}│\n`);
3862
+ } else {
3863
+ let usageDetails;
3864
+ if (usageCol2.length > 0) usageDetails = `${" ".repeat(detailsIndent)}${usageCol1}${" ".repeat(detailsSpacing)}${usageCol2}${" ".repeat(detailsSpacing)}${usageCol3}`;
3865
+ else usageDetails = `${" ".repeat(detailsIndent)}${usageCol1}${" ".repeat(detailsSpacing)}${usageCol3}`;
3866
+ const usageDetailsPadded = usageDetails + " ".repeat(Math.max(0, boxWidth - 3 - stringWidth(usageDetails)));
3867
+ terminal.write(`${marginStr}│ ${usageDetailsPadded}│\n`);
3868
+ }
3848
3869
  terminal.write(`${marginStr}│${" ".repeat(boxWidth - 2)}│\n`);
3849
3870
  terminal.write(`${marginStr}├${"─".repeat(boxWidth - 2)}┤\n`);
3850
3871
  terminal.write(`${marginStr}│${" ".repeat(boxWidth - 2)}│\n`);
3851
- const projection = projectBlockUsage(block);
3852
3872
  if (projection != null) {
3853
- const projectedPercent = config.tokenLimit != null && config.tokenLimit > 0 ? projection.totalTokens / config.tokenLimit * 100 : 0;
3854
3873
  let projBarColor = import_picocolors$5.default.green;
3855
3874
  if (projectedPercent > 100) projBarColor = import_picocolors$5.default.red;
3856
3875
  else if (projectedPercent > 80) projBarColor = import_picocolors$5.default.yellow;
@@ -3864,32 +3883,27 @@ function renderLiveDisplay(terminal, block, config) {
3864
3883
  const limitStatus = config.tokenLimit != null && config.tokenLimit > 0 ? projectedPercent > 100 ? import_picocolors$5.default.red("❌ WILL EXCEED LIMIT") : projectedPercent > 80 ? import_picocolors$5.default.yellow("⚠️ APPROACHING LIMIT") : import_picocolors$5.default.green("✓ WITHIN LIMIT") : import_picocolors$5.default.green("✓ ON TRACK");
3865
3884
  const projLabel = import_picocolors$5.default.bold("📈 PROJECTION");
3866
3885
  const projLabelWidth = stringWidth(projLabel);
3867
- if (config.tokenLimit != null && config.tokenLimit > 0) {
3868
- const projBarStr = `${projLabel}${"".padEnd(Math.max(0, labelWidth - projLabelWidth))} ${projectionBar} ${projectedPercent.toFixed(1).padStart(6)}% (${formatTokensShort(projection.totalTokens)}/${formatTokensShort(config.tokenLimit)})`;
3869
- const projBarPadded = projBarStr + " ".repeat(Math.max(0, boxWidth - 3 - stringWidth(projBarStr)));
3870
- terminal.write(`${marginStr} ${projBarPadded}│\n`);
3871
- const col1$1 = `${import_picocolors$5.default.gray("Status:")} ${limitStatus}`;
3872
- const col2$1 = `${import_picocolors$5.default.gray("Tokens:")} ${formatNumber(projection.totalTokens)}`;
3873
- const col3$1 = `${import_picocolors$5.default.gray("Cost:")} ${formatCurrency(projection.totalCost)}`;
3874
- const col1Visible$1 = stringWidth(col1$1);
3875
- const col2Visible$1 = stringWidth(col2$1);
3876
- const pad1$1 = " ".repeat(Math.max(0, DETAIL_COLUMN_WIDTHS.col1 - col1Visible$1));
3877
- const pad2$1 = " ".repeat(Math.max(0, DETAIL_COLUMN_WIDTHS.col2 - col2Visible$1));
3878
- const projDetails = ` ${col1$1}${pad1$1}${col2$1}${pad2$1}${col3$1}`;
3879
- const projDetailsPadded = projDetails + " ".repeat(Math.max(0, boxWidth - 3 - stringWidth(projDetails)));
3880
- terminal.write(`${marginStr}${projDetailsPadded}│\n`);
3886
+ const projBarStr = `${projLabel}${"".padEnd(Math.max(0, labelWidth - projLabelWidth))} ${projectionBar} ${projectionRightText}`;
3887
+ const projBarPadded = projBarStr + " ".repeat(Math.max(0, boxWidth - 3 - stringWidth(projBarStr)));
3888
+ terminal.write(`${marginStr}│ ${projBarPadded}│\n`);
3889
+ const projCol1 = `${import_picocolors$5.default.gray("Status:")} ${limitStatus}`;
3890
+ let projCol2 = `${import_picocolors$5.default.gray("Tokens:")} ${formatTokenDisplay(projection.totalTokens, false)}`;
3891
+ const projCol3 = `${import_picocolors$5.default.gray("Cost:")} ${formatCurrency(projection.totalCost)}`;
3892
+ const projTotalWidth = stringWidth(projCol1) + stringWidth(projCol2) + stringWidth(projCol3) + detailsSpacing * 2;
3893
+ let projUseTwoLineLayout = false;
3894
+ if (projTotalWidth > detailsAvailableWidth) {
3895
+ projUseTwoLineLayout = true;
3896
+ projCol2 = `${import_picocolors$5.default.gray("Tokens:")} ${formatTokenDisplay(projection.totalTokens, true)}`;
3897
+ }
3898
+ if (projUseTwoLineLayout) {
3899
+ const projDetailsLine1 = `${" ".repeat(detailsIndent)}${projCol1}`;
3900
+ const projDetailsLine1Padded = projDetailsLine1 + " ".repeat(Math.max(0, boxWidth - 3 - stringWidth(projDetailsLine1)));
3901
+ terminal.write(`${marginStr}│ ${projDetailsLine1Padded}│\n`);
3902
+ const projDetailsLine2 = `${" ".repeat(detailsIndent)}${projCol2}${" ".repeat(detailsSpacing)}${projCol3}`;
3903
+ const projDetailsLine2Padded = projDetailsLine2 + " ".repeat(Math.max(0, boxWidth - 3 - stringWidth(projDetailsLine2)));
3904
+ terminal.write(`${marginStr}│ ${projDetailsLine2Padded}│\n`);
3881
3905
  } else {
3882
- const projBarStr = `${projLabel}${"".padEnd(Math.max(0, labelWidth - projLabelWidth))} ${projectionBar} (${formatTokensShort(projection.totalTokens)} tokens)`;
3883
- const projBarPadded = projBarStr + " ".repeat(Math.max(0, boxWidth - 3 - stringWidth(projBarStr)));
3884
- terminal.write(`${marginStr}│ ${projBarPadded}│\n`);
3885
- const col1$1 = `${import_picocolors$5.default.gray("Status:")} ${limitStatus}`;
3886
- const col2$1 = `${import_picocolors$5.default.gray("Tokens:")} ${formatNumber(projection.totalTokens)}`;
3887
- const col3$1 = `${import_picocolors$5.default.gray("Cost:")} ${formatCurrency(projection.totalCost)}`;
3888
- const col1Visible$1 = stringWidth(col1$1);
3889
- const col2Visible$1 = stringWidth(col2$1);
3890
- const pad1$1 = " ".repeat(Math.max(0, DETAIL_COLUMN_WIDTHS.col1 - col1Visible$1));
3891
- const pad2$1 = " ".repeat(Math.max(0, DETAIL_COLUMN_WIDTHS.col2 - col2Visible$1));
3892
- const projDetails = ` ${col1$1}${pad1$1}${col2$1}${pad2$1}${col3$1}`;
3906
+ const projDetails = `${" ".repeat(detailsIndent)}${projCol1}${" ".repeat(detailsSpacing)}${projCol2}${" ".repeat(detailsSpacing)}${projCol3}`;
3893
3907
  const projDetailsPadded = projDetails + " ".repeat(Math.max(0, boxWidth - 3 - stringWidth(projDetails)));
3894
3908
  terminal.write(`${marginStr}│ ${projDetailsPadded}│\n`);
3895
3909
  }
@@ -3970,7 +3984,15 @@ async function startLiveMonitoring(config) {
3970
3984
  }
3971
3985
  renderActiveBlock(terminal, activeBlock, config);
3972
3986
  lastRenderTime = Date.now();
3973
- await delayWithAbort(config.refreshInterval, abortController.signal);
3987
+ let resizeEventHandler;
3988
+ try {
3989
+ await Promise.race([delayWithAbort(config.refreshInterval, abortController.signal), new Promise((resolve) => {
3990
+ resizeEventHandler = resolve;
3991
+ process$1.stdout.once("resize", resolve);
3992
+ })]);
3993
+ } finally {
3994
+ if (resizeEventHandler != null) process$1.stdout.removeListener("resize", resizeEventHandler);
3995
+ }
3974
3996
  }
3975
3997
  },
3976
3998
  catch: (error) => error
@@ -4864,32 +4886,27 @@ Object.setPrototypeOf(Response2, GlobalResponse);
4864
4886
  Object.setPrototypeOf(Response2.prototype, GlobalResponse.prototype);
4865
4887
  function writeFromReadableStream(stream, writable) {
4866
4888
  if (stream.locked) throw new TypeError("ReadableStream is locked.");
4867
- else if (writable.destroyed) {
4868
- stream.cancel();
4869
- return;
4870
- }
4889
+ else if (writable.destroyed) return;
4871
4890
  const reader = stream.getReader();
4872
- writable.on("close", cancel);
4873
- writable.on("error", cancel);
4874
- reader.read().then(flow, cancel);
4891
+ const handleError = () => {};
4892
+ writable.on("error", handleError);
4893
+ reader.read().then(flow, handleStreamError);
4875
4894
  return reader.closed.finally(() => {
4876
- writable.off("close", cancel);
4877
- writable.off("error", cancel);
4895
+ writable.off("error", handleError);
4878
4896
  });
4879
- function cancel(error) {
4880
- reader.cancel(error).catch(() => {});
4897
+ function handleStreamError(error) {
4881
4898
  if (error) writable.destroy(error);
4882
4899
  }
4883
4900
  function onDrain() {
4884
- reader.read().then(flow, cancel);
4901
+ reader.read().then(flow, handleStreamError);
4885
4902
  }
4886
4903
  function flow({ done, value }) {
4887
4904
  try {
4888
4905
  if (done) writable.end();
4889
4906
  else if (!writable.write(value)) writable.once("drain", onDrain);
4890
- else return reader.read().then(flow, cancel);
4907
+ else return reader.read().then(flow, handleStreamError);
4891
4908
  } catch (e) {
4892
- cancel(e);
4909
+ handleStreamError(e);
4893
4910
  }
4894
4911
  }
4895
4912
  }
@@ -951,7 +951,7 @@ function _getDefaultLogLevel() {
951
951
  }
952
952
  const consola = createConsola$1();
953
953
  var name = "ccusage";
954
- var version = "15.5.0";
954
+ var version = "15.5.2";
955
955
  var description = "Usage analysis tool for Claude Code";
956
956
  /**
957
957
  * Application logger instance with package name tag
package/dist/logger.js CHANGED
@@ -1,2 +1,2 @@
1
- import { log, logger } from "./logger-CZzaUNvP.js";
1
+ import { log, logger } from "./logger-D0z-I-_d.js";
2
2
  export { log, logger };
@@ -1,9 +1,9 @@
1
- import { __commonJSMin, __toESM, require_usingCtx } from "./pricing-fetcher-B2yEbqCO.js";
1
+ import { __commonJSMin, __toESM, require_usingCtx } from "./pricing-fetcher-B5b61mDE.js";
2
2
  import { getTotalTokens } from "./_token-utils-WjkbrjKv.js";
3
3
  import { ZodFirstPartyTypeKind, ZodOptional, ZodType, arrayType, booleanType, discriminatedUnionType, enumType, filterDateSchema, literalType, numberType, objectType, optionalType, recordType, stringType, unionType, unknownType } from "./_types-BHFM59hI.js";
4
4
  import { calculateTotals, createTotalsObject } from "./calculate-cost-BDqO4yWA.js";
5
- import { getClaudePaths, loadDailyUsageData, loadMonthlyUsageData, loadSessionBlockData, loadSessionData } from "./data-loader-BVwVxx4T.js";
6
- import { name, version } from "./logger-CZzaUNvP.js";
5
+ import { getClaudePaths, loadDailyUsageData, loadMonthlyUsageData, loadSessionBlockData, loadSessionData } from "./data-loader-CmW1xurn.js";
6
+ import { name, version } from "./logger-D0z-I-_d.js";
7
7
  import process from "node:process";
8
8
  const LATEST_PROTOCOL_VERSION = "2025-06-18";
9
9
  const SUPPORTED_PROTOCOL_VERSIONS = [
@@ -1605,6 +1605,7 @@ var Protocol = class {
1605
1605
  this._responseHandlers = /* @__PURE__ */ new Map();
1606
1606
  this._progressHandlers = /* @__PURE__ */ new Map();
1607
1607
  this._timeoutInfo = /* @__PURE__ */ new Map();
1608
+ this._pendingDebouncedNotifications = /* @__PURE__ */ new Set();
1608
1609
  this.setNotificationHandler(CancelledNotificationSchema, (notification) => {
1609
1610
  const controller = this._requestHandlerAbortControllers.get(notification.params.requestId);
1610
1611
  controller === null || controller === void 0 || controller.abort(notification.params.reason);
@@ -1679,6 +1680,7 @@ var Protocol = class {
1679
1680
  const responseHandlers = this._responseHandlers;
1680
1681
  this._responseHandlers = /* @__PURE__ */ new Map();
1681
1682
  this._progressHandlers.clear();
1683
+ this._pendingDebouncedNotifications.clear();
1682
1684
  this._transport = void 0;
1683
1685
  (_a = this.onclose) === null || _a === void 0 || _a.call(this);
1684
1686
  const error = new McpError(ErrorCode.ConnectionClosed, "Connection closed");
@@ -1872,8 +1874,26 @@ var Protocol = class {
1872
1874
  * Emits a notification, which is a one-way message that does not expect a response.
1873
1875
  */
1874
1876
  async notification(notification, options) {
1877
+ var _a, _b;
1875
1878
  if (!this._transport) throw new Error("Not connected");
1876
1879
  this.assertNotificationCapability(notification.method);
1880
+ const debouncedMethods = (_b = (_a = this._options) === null || _a === void 0 ? void 0 : _a.debouncedNotificationMethods) !== null && _b !== void 0 ? _b : [];
1881
+ const canDebounce = debouncedMethods.includes(notification.method) && !notification.params && !(options === null || options === void 0 ? void 0 : options.relatedRequestId);
1882
+ if (canDebounce) {
1883
+ if (this._pendingDebouncedNotifications.has(notification.method)) return;
1884
+ this._pendingDebouncedNotifications.add(notification.method);
1885
+ Promise.resolve().then(() => {
1886
+ var _a$1;
1887
+ this._pendingDebouncedNotifications.delete(notification.method);
1888
+ if (!this._transport) return;
1889
+ const jsonrpcNotification$1 = {
1890
+ ...notification,
1891
+ jsonrpc: "2.0"
1892
+ };
1893
+ (_a$1 = this._transport) === null || _a$1 === void 0 || _a$1.send(jsonrpcNotification$1, options).catch((error) => this._onerror(error));
1894
+ });
1895
+ return;
1896
+ }
1877
1897
  const jsonrpcNotification = {
1878
1898
  ...notification,
1879
1899
  jsonrpc: "2.0"
package/dist/mcp.js CHANGED
@@ -1,8 +1,8 @@
1
- import "./pricing-fetcher-B2yEbqCO.js";
1
+ import "./pricing-fetcher-B5b61mDE.js";
2
2
  import "./_token-utils-WjkbrjKv.js";
3
3
  import "./_types-BHFM59hI.js";
4
4
  import "./calculate-cost-BDqO4yWA.js";
5
- import "./data-loader-BVwVxx4T.js";
6
- import "./logger-CZzaUNvP.js";
7
- import { createMcpHttpApp, createMcpServer, startMcpServerStdio } from "./mcp-DRNUcHZe.js";
5
+ import "./data-loader-CmW1xurn.js";
6
+ import "./logger-D0z-I-_d.js";
7
+ import { createMcpHttpApp, createMcpServer, startMcpServerStdio } from "./mcp-DbViDMcM.js";
8
8
  export { createMcpHttpApp, createMcpServer, startMcpServerStdio };
@@ -1,5 +1,5 @@
1
1
  import { modelPricingSchema } from "./_types-BHFM59hI.js";
2
- import { logger } from "./logger-CZzaUNvP.js";
2
+ import { logger } from "./logger-D0z-I-_d.js";
3
3
  import { createRequire } from "node:module";
4
4
  import path from "node:path";
5
5
  import F, { homedir } from "node:os";
@@ -346,14 +346,6 @@ var PricingFetcher = class {
346
346
  loadOfflinePricing = try_({
347
347
  try: async () => {
348
348
  const pricing = new Map(Object.entries({
349
- "claude-2": {
350
- "input_cost_per_token": 8e-6,
351
- "output_cost_per_token": 24e-6
352
- },
353
- "claude-2.1": {
354
- "input_cost_per_token": 8e-6,
355
- "output_cost_per_token": 24e-6
356
- },
357
349
  "claude-3-haiku-20240307": {
358
350
  "input_cost_per_token": 25e-8,
359
351
  "output_cost_per_token": 125e-8,
@@ -384,10 +376,6 @@ var PricingFetcher = class {
384
376
  "cache_creation_input_token_cost": 1875e-8,
385
377
  "cache_read_input_token_cost": 15e-7
386
378
  },
387
- "claude-3-sonnet-20240229": {
388
- "input_cost_per_token": 3e-6,
389
- "output_cost_per_token": 15e-6
390
- },
391
379
  "claude-3-5-sonnet-latest": {
392
380
  "input_cost_per_token": 3e-6,
393
381
  "output_cost_per_token": 15e-6,
@@ -1,4 +1,4 @@
1
- import { PricingFetcher } from "./pricing-fetcher-B2yEbqCO.js";
1
+ import { PricingFetcher } from "./pricing-fetcher-B5b61mDE.js";
2
2
  import "./_types-BHFM59hI.js";
3
- import "./logger-CZzaUNvP.js";
3
+ import "./logger-D0z-I-_d.js";
4
4
  export { PricingFetcher };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccusage",
3
- "version": "15.5.0",
3
+ "version": "15.5.2",
4
4
  "description": "Usage analysis tool for Claude Code",
5
5
  "homepage": "https://github.com/ryoppippi/ccusage#readme",
6
6
  "bugs": {