ccusage 15.5.0 → 15.5.1

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-eNV76BjF.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-COLgmk2z.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";
@@ -1,6 +1,6 @@
1
- import "./pricing-fetcher-B2yEbqCO.js";
1
+ import "./pricing-fetcher-eNV76BjF.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-BAp4u-7e.js";
5
+ import "./logger-COLgmk2z.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-eNV76BjF.js";
2
+ import { getClaudePaths, glob, unwrap, usageDataSchema } from "./data-loader-BAp4u-7e.js";
3
+ import { logger } from "./logger-COLgmk2z.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-eNV76BjF.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-BAp4u-7e.js";
5
+ import "./logger-COLgmk2z.js";
6
+ import { detectMismatches, printMismatchReport } from "./debug-IQBgd8CJ.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-eNV76BjF.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-BAp4u-7e.js";
7
+ import { description, log, logger, name, version } from "./logger-COLgmk2z.js";
8
+ import { detectMismatches, printMismatchReport } from "./debug-IQBgd8CJ.js";
9
+ import { createMcpHttpApp, createMcpServer, startMcpServerStdio } from "./mcp-Ta2UK9sc.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
@@ -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.1";
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-COLgmk2z.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-eNV76BjF.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-BAp4u-7e.js";
6
+ import { name, version } from "./logger-COLgmk2z.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-eNV76BjF.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-BAp4u-7e.js";
6
+ import "./logger-COLgmk2z.js";
7
+ import { createMcpHttpApp, createMcpServer, startMcpServerStdio } from "./mcp-Ta2UK9sc.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-COLgmk2z.js";
3
3
  import { createRequire } from "node:module";
4
4
  import path from "node:path";
5
5
  import F, { homedir } from "node:os";
@@ -1,4 +1,4 @@
1
- import { PricingFetcher } from "./pricing-fetcher-B2yEbqCO.js";
1
+ import { PricingFetcher } from "./pricing-fetcher-eNV76BjF.js";
2
2
  import "./_types-BHFM59hI.js";
3
- import "./logger-CZzaUNvP.js";
3
+ import "./logger-COLgmk2z.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.1",
4
4
  "description": "Usage analysis tool for Claude Code",
5
5
  "homepage": "https://github.com/ryoppippi/ccusage#readme",
6
6
  "bugs": {