ccstatusline-usage 2.3.3 → 2.3.5

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/README.md CHANGED
@@ -18,7 +18,7 @@
18
18
 
19
19
  [![npm version](https://img.shields.io/npm/v/ccstatusline-usage.svg)](https://www.npmjs.com/package/ccstatusline-usage)
20
20
  [![npm downloads](https://img.shields.io/npm/dm/ccstatusline-usage.svg)](https://www.npmjs.com/package/ccstatusline-usage)
21
- [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/sirmalloc/ccstatusline/blob/main/LICENSE)
21
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/pcvelz/ccstatusline-usage/blob/main/LICENSE)
22
22
  [![Node.js Version](https://img.shields.io/node/v/ccstatusline-usage.svg)](https://nodejs.org)
23
23
  [![install size](https://packagephobia.com/badge?p=ccstatusline-usage)](https://packagephobia.com/result?p=ccstatusline-usage)
24
24
  [![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://github.com/pcvelz/ccstatusline-usage/graphs/commit-activity)
@@ -34,7 +34,7 @@ This fork adds API-based usage widgets beyond the upstream:
34
34
  - **Weekly Pace** - Pendulum bar showing if you're ahead or behind expected usage pace
35
35
  - **Reset Timer** - Time until 5-hour session window resets
36
36
  - **Context Window Display** - Visual bar showing context usage
37
- - **Off Peak** - Shows peak/off-peak 2x status during Anthropic usage promotions
37
+ - **Off Peak** - Shows peak/off-peak status with countdown timer (peak hours drain sessions faster)
38
38
  - **Two-line Layout** - Session info on line 1, context on line 2
39
39
 
40
40
  ### Enhanced Status Line Preview
@@ -66,6 +66,17 @@ Session: [████░░░░░░░░░░░] 27.0% | Weekly: [██
66
66
 
67
67
  ## 🆕 Recent Updates
68
68
 
69
+ ### [v2.3.5](https://github.com/pcvelz/ccstatusline-usage/releases/tag/v2.3.5) - Upstream sync + permanent peak/off-peak widget
70
+
71
+ - [sirmalloc/ccstatusline](https://github.com/sirmalloc/ccstatusline): **Major upstream sync** — 180 commits merged, including Weekly Reset Timer widget, new test infrastructure, Windows support, and various improvements
72
+ - [pcvelz/ccstatusline-usage](https://github.com/pcvelz/ccstatusline-usage): **Permanent Off-Peak widget** — Widget no longer disappears after the March 28 promo ends; shows peak/off-peak status permanently with countdown timer (Anthropic confirmed peak hours continue to drain sessions faster)
73
+ - [pcvelz/ccstatusline-usage](https://github.com/pcvelz/ccstatusline-usage): **README fork branding fix** — Fixed upstream package name references in Windows install commands, WSL section, and dev setup
74
+
75
+ ### [v2.3.4](https://github.com/pcvelz/ccstatusline-usage/releases/tag/v2.3.4) - Upstream sync + extra usage fix
76
+
77
+ - [sirmalloc/ccstatusline](https://github.com/sirmalloc/ccstatusline): **Native rate_limits support** — Upstream now uses Claude Code 2.1.80's native `rate_limits` field for usage data
78
+ - [pcvelz/ccstatusline-usage](https://github.com/pcvelz/ccstatusline-usage): **Extra usage regression fix** — Reset timer widget now supplements native `rate_limits` data with API fetch for extra usage fields that upstream's pipeline omits
79
+
69
80
  ### [v2.3.3](https://github.com/pcvelz/ccstatusline-usage/releases/tag/v2.3.3) - CI pipeline fix
70
81
 
71
82
  - [pcvelz/ccstatusline-usage](https://github.com/pcvelz/ccstatusline-usage): **CI pipeline fix** — Fixed TypeScript errors (model union type narrowing, missing `extraUsageBalance` setting), disabled broken `import/order` ESLint rule (incompatible with ESLint 10), resolved all remaining lint errors in fork-specific files
@@ -332,19 +343,19 @@ ccstatusline works seamlessly on Windows with full feature compatibility across
332
343
  irm bun.sh/install.ps1 | iex
333
344
 
334
345
  # Run ccstatusline
335
- bunx -y ccstatusline@latest
346
+ bunx -y ccstatusline-usage@latest
336
347
  ```
337
348
 
338
349
  #### Option 2: Using Node.js
339
350
  ```powershell
340
351
  # Using npm
341
- npx -y ccstatusline@latest
352
+ npx -y ccstatusline-usage@latest
342
353
 
343
354
  # Or with Yarn
344
- yarn dlx ccstatusline@latest
355
+ yarn dlx ccstatusline-usage@latest
345
356
 
346
357
  # Or with pnpm
347
- pnpm dlx ccstatusline@latest
358
+ pnpm dlx ccstatusline-usage@latest
348
359
  ```
349
360
 
350
361
  ### Windows-Specific Features
@@ -399,7 +410,7 @@ winget install Git.Git
399
410
  **Issue**: Permission errors during installation
400
411
  ```powershell
401
412
  # Use non-global installation (recommended)
402
- npx -y ccstatusline@latest
413
+ npx -y ccstatusline-usage@latest
403
414
 
404
415
  # Or run PowerShell as Administrator for global install
405
416
  ```
@@ -427,7 +438,7 @@ ccstatusline works perfectly in WSL environments:
427
438
  # Install in WSL Ubuntu/Debian
428
439
  curl -fsSL https://bun.sh/install | bash
429
440
  source ~/.bashrc
430
- bunx -y ccstatusline@latest
441
+ bunx -y ccstatusline-usage@latest
431
442
  ```
432
443
 
433
444
  **WSL Benefits**:
@@ -466,7 +477,7 @@ Configure ccstatusline in your Claude Code settings:
466
477
  {
467
478
  "statusLine": {
468
479
  "type": "command",
469
- "command": "bunx -y ccstatusline@latest",
480
+ "command": "bunx -y ccstatusline-usage@latest",
470
481
  "padding": 0
471
482
  }
472
483
  }
@@ -477,7 +488,7 @@ Configure ccstatusline in your Claude Code settings:
477
488
  {
478
489
  "statusLine": {
479
490
  "type": "command",
480
- "command": "npx -y ccstatusline@latest",
491
+ "command": "npx -y ccstatusline-usage@latest",
481
492
  "padding": 0
482
493
  }
483
494
  }
@@ -562,7 +573,7 @@ bun run example
562
573
  - **Skills** - Shows skill activity as last used, total count, or unique list (with optional list limit and hide-when-empty toggle)
563
574
  - **Thinking Effort** - Shows the current Claude Code thinking effort level
564
575
  - **Vim Mode** - Displays current vim editor mode
565
- - **Off Peak** *(ccstatusline-usage)* - Shows `Off peak: Off-peak 2x` or `Off peak: Peak` during Anthropic usage promotions (auto-hides when promotion ends)
576
+ - **Off Peak** *(ccstatusline-usage)* - Shows `Off-peak (X:XX hr)` or `Peak (X:XX hr)` with countdown to next status change. Peak hours (5-11 AM PT weekdays) drain sessions faster per Anthropic's permanent capacity policy
566
577
  - **Separator** - Visual divider between widgets (available when Powerline mode is off and no default separator is configured)
567
578
  - **Flex Separator** - Expands to fill available space (available when Powerline mode is off)
568
579
 
@@ -757,7 +768,7 @@ The documentation will be generated in the `docs/` directory and can be viewed b
757
768
 
758
769
  ```bash
759
770
  # Clone the repository
760
- git clone https://github.com/sirmalloc/ccstatusline.git
771
+ git clone https://github.com/pcvelz/ccstatusline-usage.git
761
772
  cd ccstatusline
762
773
 
763
774
  # Install dependencies
@@ -917,7 +928,7 @@ Give a ⭐ if this project helped you!
917
928
 
918
929
  [![npm version](https://img.shields.io/npm/v/ccstatusline-usage.svg)](https://www.npmjs.com/package/ccstatusline-usage)
919
930
  [![npm downloads](https://img.shields.io/npm/dm/ccstatusline-usage.svg)](https://www.npmjs.com/package/ccstatusline-usage)
920
- [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/sirmalloc/ccstatusline/blob/main/LICENSE)
931
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/pcvelz/ccstatusline-usage/blob/main/LICENSE)
921
932
  [![Made with Bun](https://img.shields.io/badge/Made%20with-Bun-000000.svg?logo=bun)](https://bun.sh)
922
933
 
923
934
  [![Issues](https://img.shields.io/github/issues/sirmalloc/ccstatusline)](https://github.com/sirmalloc/ccstatusline/issues)
@@ -54072,7 +54072,7 @@ function getTerminalWidth() {
54072
54072
  function canDetectTerminalWidth() {
54073
54073
  return probeTerminalWidth() !== null;
54074
54074
  }
54075
- var __dirname = "/Users/peter/Documents/Code/ccstatusline-usage/src/utils", PACKAGE_VERSION = "2.3.3";
54075
+ var __dirname = "/Users/peter/Documents/Code/ccstatusline-usage/src/utils", PACKAGE_VERSION = "2.3.5";
54076
54076
  var init_terminal = () => {};
54077
54077
 
54078
54078
  // src/utils/renderer.ts
@@ -61846,6 +61846,128 @@ var init_ApiUsage = __esm(() => {
61846
61846
  CRED_FILE = path7.join(os7.homedir(), ".claude", ".credentials.json");
61847
61847
  });
61848
61848
 
61849
+ // src/widgets/WeeklyResetTimer.ts
61850
+ function makeTimerProgressBar2(percent, width) {
61851
+ const clampedPercent = Math.max(0, Math.min(100, percent));
61852
+ const filledWidth = Math.floor(clampedPercent / 100 * width);
61853
+ const emptyWidth = width - filledWidth;
61854
+ return "█".repeat(filledWidth) + "░".repeat(emptyWidth);
61855
+ }
61856
+ function isWeeklyResetHoursOnly(item) {
61857
+ return isMetadataFlagEnabled(item, "hours");
61858
+ }
61859
+ function toggleWeeklyResetHoursOnly(item) {
61860
+ return toggleMetadataFlag(item, "hours");
61861
+ }
61862
+ function getWeeklyResetModifierText(item) {
61863
+ const displayMode = getUsageDisplayMode(item);
61864
+ const modifiers = [];
61865
+ if (displayMode === "progress") {
61866
+ modifiers.push("progress bar");
61867
+ } else if (displayMode === "progress-short") {
61868
+ modifiers.push("short bar");
61869
+ }
61870
+ if (isUsageInverted(item)) {
61871
+ modifiers.push("inverted");
61872
+ }
61873
+ if (!isUsageProgressMode(displayMode)) {
61874
+ if (isUsageCompact(item)) {
61875
+ modifiers.push("compact");
61876
+ }
61877
+ if (isWeeklyResetHoursOnly(item)) {
61878
+ modifiers.push("hours only");
61879
+ }
61880
+ }
61881
+ return makeModifierText(modifiers);
61882
+ }
61883
+
61884
+ class WeeklyResetTimerWidget {
61885
+ getDefaultColor() {
61886
+ return "brightBlue";
61887
+ }
61888
+ getDescription() {
61889
+ return "Shows time remaining until weekly usage reset";
61890
+ }
61891
+ getDisplayName() {
61892
+ return "Weekly Reset Timer";
61893
+ }
61894
+ getCategory() {
61895
+ return "Usage";
61896
+ }
61897
+ getEditorDisplay(item) {
61898
+ return {
61899
+ displayText: this.getDisplayName(),
61900
+ modifierText: getWeeklyResetModifierText(item)
61901
+ };
61902
+ }
61903
+ handleEditorAction(action, item) {
61904
+ if (action === "toggle-progress") {
61905
+ return cycleUsageDisplayMode(item, ["compact", "hours"]);
61906
+ }
61907
+ if (action === "toggle-invert") {
61908
+ return toggleUsageInverted(item);
61909
+ }
61910
+ if (action === "toggle-compact") {
61911
+ return toggleUsageCompact(item);
61912
+ }
61913
+ if (action === "toggle-hours") {
61914
+ return toggleWeeklyResetHoursOnly(item);
61915
+ }
61916
+ return null;
61917
+ }
61918
+ render(item, context, settings) {
61919
+ const displayMode = getUsageDisplayMode(item);
61920
+ const inverted = isUsageInverted(item);
61921
+ const compact2 = isUsageCompact(item);
61922
+ const useDays = !isWeeklyResetHoursOnly(item);
61923
+ if (context.isPreview) {
61924
+ const previewPercent = inverted ? 90 : 10;
61925
+ if (isUsageProgressMode(displayMode)) {
61926
+ const barWidth = getUsageProgressBarWidth(displayMode);
61927
+ const progressBar = makeTimerProgressBar2(previewPercent, barWidth);
61928
+ return formatRawOrLabeledValue(item, "Weekly Reset ", `[${progressBar}] ${previewPercent.toFixed(1)}%`);
61929
+ }
61930
+ return formatRawOrLabeledValue(item, "Weekly Reset: ", formatUsageDuration(WEEKLY_PREVIEW_DURATION_MS, compact2, useDays));
61931
+ }
61932
+ const usageData = context.usageData ?? {};
61933
+ const window2 = resolveWeeklyUsageWindow(usageData);
61934
+ if (!window2) {
61935
+ if (usageData.error) {
61936
+ return getUsageErrorMessage(usageData.error);
61937
+ }
61938
+ return null;
61939
+ }
61940
+ if (isUsageProgressMode(displayMode)) {
61941
+ const barWidth = getUsageProgressBarWidth(displayMode);
61942
+ const percent = inverted ? window2.remainingPercent : window2.elapsedPercent;
61943
+ const progressBar = makeTimerProgressBar2(percent, barWidth);
61944
+ const percentage = percent.toFixed(1);
61945
+ return formatRawOrLabeledValue(item, "Weekly Reset ", `[${progressBar}] ${percentage}%`);
61946
+ }
61947
+ const remainingTime = formatUsageDuration(window2.remainingMs, compact2, useDays);
61948
+ return formatRawOrLabeledValue(item, "Weekly Reset: ", remainingTime);
61949
+ }
61950
+ getCustomKeybinds(item) {
61951
+ const keybinds = getUsageTimerCustomKeybinds(item);
61952
+ if (!item || !isUsageProgressMode(getUsageDisplayMode(item))) {
61953
+ keybinds.push({ key: "h", label: "(h)ours only", action: "toggle-hours" });
61954
+ }
61955
+ return keybinds;
61956
+ }
61957
+ supportsRawValue() {
61958
+ return true;
61959
+ }
61960
+ supportsColors(item) {
61961
+ return true;
61962
+ }
61963
+ }
61964
+ var WEEKLY_PREVIEW_DURATION_MS;
61965
+ var init_WeeklyResetTimer = __esm(() => {
61966
+ init_usage();
61967
+ init_usage_display();
61968
+ WEEKLY_PREVIEW_DURATION_MS = 36.5 * 60 * 60 * 1000;
61969
+ });
61970
+
61849
61971
  // src/widgets/Link.tsx
61850
61972
  function isValidHttpUrl(url2) {
61851
61973
  try {
@@ -62602,34 +62724,45 @@ var init_WeeklyPace = __esm(() => {
62602
62724
  });
62603
62725
 
62604
62726
  // src/widgets/OffPeak.ts
62605
- function isOffPeak(now2) {
62606
- const ms = now2.getTime();
62607
- if (ms < PROMO_START_MS || ms >= PROMO_END_MS) {
62608
- return null;
62609
- }
62727
+ function isWeekend(now2) {
62610
62728
  const dayOfWeek = now2.getUTCDay();
62611
- const isWeekend = dayOfWeek === 0 || dayOfWeek === 6;
62612
- if (isWeekend)
62613
- return true;
62729
+ return dayOfWeek === 0 || dayOfWeek === 6;
62730
+ }
62731
+ function isPeakHour(now2) {
62614
62732
  const utcHour = now2.getUTCHours();
62615
- const isPeak = utcHour >= PEAK_START_UTC_HOUR && utcHour < PEAK_END_UTC_HOUR;
62616
- return !isPeak;
62733
+ return utcHour >= PEAK_START_UTC_HOUR && utcHour < PEAK_END_UTC_HOUR;
62734
+ }
62735
+ function isPromoActive(now2) {
62736
+ const ms = now2.getTime();
62737
+ return ms >= PROMO_START_MS && ms < PROMO_END_MS;
62738
+ }
62739
+ function isOffPeak(now2) {
62740
+ if (isWeekend(now2))
62741
+ return true;
62742
+ return !isPeakHour(now2);
62617
62743
  }
62618
62744
  function minutesUntilFlip(now2) {
62619
- const dayOfWeek = now2.getUTCDay();
62620
- const isWeekend = dayOfWeek === 0 || dayOfWeek === 6;
62621
- if (isWeekend)
62622
- return null;
62745
+ if (isWeekend(now2)) {
62746
+ return minutesUntilMondayPeak(now2);
62747
+ }
62623
62748
  const utcHour = now2.getUTCHours();
62624
- const isPeak = utcHour >= PEAK_START_UTC_HOUR && utcHour < PEAK_END_UTC_HOUR;
62625
- const flipHour = isPeak ? PEAK_END_UTC_HOUR : PEAK_START_UTC_HOUR;
62749
+ const peak = isPeakHour(now2);
62750
+ const flipHour = peak ? PEAK_END_UTC_HOUR : PEAK_START_UTC_HOUR;
62626
62751
  const target = new Date(now2);
62627
- if (!isPeak && utcHour >= PEAK_END_UTC_HOUR) {
62752
+ if (!peak && utcHour >= PEAK_END_UTC_HOUR) {
62628
62753
  target.setUTCDate(now2.getUTCDate() + 1);
62629
62754
  }
62630
62755
  target.setUTCHours(flipHour, 0, 0, 0);
62631
62756
  return Math.max(0, Math.round((target.getTime() - now2.getTime()) / 60000));
62632
62757
  }
62758
+ function minutesUntilMondayPeak(now2) {
62759
+ const dayOfWeek = now2.getUTCDay();
62760
+ const daysUntilMonday = dayOfWeek === 0 ? 1 : 8 - dayOfWeek;
62761
+ const target = new Date(now2);
62762
+ target.setUTCDate(now2.getUTCDate() + daysUntilMonday);
62763
+ target.setUTCHours(PEAK_START_UTC_HOUR, 0, 0, 0);
62764
+ return Math.max(0, Math.round((target.getTime() - now2.getTime()) / 60000));
62765
+ }
62633
62766
  function formatCountdown(minutes) {
62634
62767
  const h = Math.floor(minutes / 60);
62635
62768
  const m = minutes % 60;
@@ -62641,7 +62774,7 @@ class OffPeakWidget {
62641
62774
  return "green";
62642
62775
  }
62643
62776
  getDescription() {
62644
- return "Shows peak / off-peak 2x status during the March 2026 Anthropic usage promotion";
62777
+ return "Shows peak / off-peak status with countdown timer";
62645
62778
  }
62646
62779
  getDisplayName() {
62647
62780
  return "Off Peak";
@@ -62654,17 +62787,21 @@ class OffPeakWidget {
62654
62787
  }
62655
62788
  render(item, context, _settings) {
62656
62789
  if (context.isPreview) {
62657
- return item.rawValue ? "Off-peak 2x (3:42)" : "Off-peak 2x (3:42)";
62790
+ return item.rawValue ? "Off-peak (3:42 hr)" : "Off-peak (3:42 hr)";
62658
62791
  }
62659
62792
  const now2 = new Date;
62660
62793
  const offPeak = isOffPeak(now2);
62661
- if (offPeak === null)
62662
- return null;
62663
62794
  const mins = minutesUntilFlip(now2);
62664
- const countdown = mins !== null ? ` (${formatCountdown(mins)} hr)` : "";
62795
+ const countdown = ` (${formatCountdown(mins)} hr)`;
62665
62796
  const mobile = (context.terminalWidth ?? 0) > 0 && (context.terminalWidth ?? 0) < 80;
62797
+ if (isPromoActive(now2)) {
62798
+ if (offPeak) {
62799
+ return mobile ? `2x${countdown}` : `Off-peak 2x${countdown}`;
62800
+ }
62801
+ return `Peak${countdown}`;
62802
+ }
62666
62803
  if (offPeak) {
62667
- return mobile ? `2x${countdown}` : `Off-peak 2x${countdown}`;
62804
+ return mobile ? `OffPk${countdown}` : `Off-peak${countdown}`;
62668
62805
  }
62669
62806
  return `Peak${countdown}`;
62670
62807
  }
@@ -62696,6 +62833,7 @@ var init_widgets = __esm(async () => {
62696
62833
  init_FreeMemory();
62697
62834
  init_SessionName();
62698
62835
  init_ApiUsage();
62836
+ init_WeeklyResetTimer();
62699
62837
  init_ThinkingEffort();
62700
62838
  init_Battery();
62701
62839
  init_VimMode();
@@ -62756,6 +62894,7 @@ var init_widget_manifest = __esm(async () => {
62756
62894
  { type: "session-usage", create: () => new SessionUsageWidget },
62757
62895
  { type: "weekly-usage", create: () => new WeeklyUsageWidget },
62758
62896
  { type: "reset-timer", create: () => new ResetTimerWidget },
62897
+ { type: "weekly-reset-timer", create: () => new WeeklyResetTimerWidget },
62759
62898
  { type: "context-bar", create: () => new ContextBarWidget },
62760
62899
  { type: "skills", create: () => new SkillsWidget },
62761
62900
  { type: "thinking-effort", create: () => new ThinkingEffortWidget },
@@ -68997,6 +69136,10 @@ var CoercedNumberSchema = exports_external.preprocess((value) => {
68997
69136
  const parsed = Number(trimmed);
68998
69137
  return Number.isFinite(parsed) ? parsed : value;
68999
69138
  }, exports_external.number());
69139
+ var RateLimitPeriodSchema = exports_external.object({
69140
+ used_percentage: CoercedNumberSchema.nullable().optional(),
69141
+ resets_at: CoercedNumberSchema.nullable().optional()
69142
+ });
69000
69143
  var StatusJSONSchema = exports_external.looseObject({
69001
69144
  hook_event_name: exports_external.string().optional(),
69002
69145
  session_id: exports_external.string().optional(),
@@ -69039,7 +69182,11 @@ var StatusJSONSchema = exports_external.looseObject({
69039
69182
  used_percentage: CoercedNumberSchema.nullable().optional(),
69040
69183
  remaining_percentage: CoercedNumberSchema.nullable().optional()
69041
69184
  }).nullable().optional(),
69042
- vim: exports_external.object({ mode: exports_external.string().optional() }).nullable().optional()
69185
+ vim: exports_external.object({ mode: exports_external.string().optional() }).nullable().optional(),
69186
+ rate_limits: exports_external.object({
69187
+ five_hour: RateLimitPeriodSchema.optional(),
69188
+ seven_day: RateLimitPeriodSchema.optional()
69189
+ }).nullable().optional()
69043
69190
  });
69044
69191
 
69045
69192
  // src/ccstatusline.ts
@@ -69172,11 +69319,46 @@ var USAGE_WIDGET_TYPES = new Set([
69172
69319
  function hasUsageDependentWidgets(lines) {
69173
69320
  return lines.some((line) => line.some((item) => USAGE_WIDGET_TYPES.has(item.type)));
69174
69321
  }
69175
- async function prefetchUsageDataIfNeeded(lines) {
69322
+ function epochSecondsToIsoString(epochSeconds) {
69323
+ if (epochSeconds === null || epochSeconds === undefined || !Number.isFinite(epochSeconds)) {
69324
+ return;
69325
+ }
69326
+ return new Date(epochSeconds * 1000).toISOString();
69327
+ }
69328
+ function extractUsageDataFromRateLimits(rateLimits) {
69329
+ if (!rateLimits) {
69330
+ return null;
69331
+ }
69332
+ const sessionUsage = rateLimits.five_hour?.used_percentage ?? undefined;
69333
+ const sessionResetAt = epochSecondsToIsoString(rateLimits.five_hour?.resets_at);
69334
+ const weeklyUsage = rateLimits.seven_day?.used_percentage ?? undefined;
69335
+ const weeklyResetAt = epochSecondsToIsoString(rateLimits.seven_day?.resets_at);
69336
+ if (sessionUsage === undefined && weeklyUsage === undefined) {
69337
+ return null;
69338
+ }
69339
+ return { sessionUsage, sessionResetAt, weeklyUsage, weeklyResetAt };
69340
+ }
69341
+ function hasCompleteRateLimitsUsageData(usageData) {
69342
+ return usageData?.sessionUsage !== undefined && usageData.sessionResetAt !== undefined && usageData.weeklyUsage !== undefined && usageData.weeklyResetAt !== undefined;
69343
+ }
69344
+ function hasExtraUsageDependentWidgets(lines) {
69345
+ return lines.some((line) => line.some((item) => item.type === "reset-timer"));
69346
+ }
69347
+ async function prefetchUsageDataIfNeeded(lines, data) {
69176
69348
  if (!hasUsageDependentWidgets(lines)) {
69177
69349
  return null;
69178
69350
  }
69179
- return await fetchUsageData();
69351
+ const rateLimitsData = extractUsageDataFromRateLimits(data?.rate_limits);
69352
+ if (hasCompleteRateLimitsUsageData(rateLimitsData)) {
69353
+ if (hasExtraUsageDependentWidgets(lines)) {
69354
+ const apiData = await fetchUsageData();
69355
+ if (apiData.error === undefined) {
69356
+ return { ...rateLimitsData, extraUsageEnabled: apiData.extraUsageEnabled, extraUsageLimit: apiData.extraUsageLimit, extraUsageUsed: apiData.extraUsageUsed, extraUsageUtilization: apiData.extraUsageUtilization };
69357
+ }
69358
+ }
69359
+ return rateLimitsData;
69360
+ }
69361
+ return fetchUsageData();
69180
69362
  }
69181
69363
 
69182
69364
  // src/ccstatusline.ts
@@ -69248,7 +69430,7 @@ async function renderMultipleLines(data) {
69248
69430
  if (hasSessionClock && !hasSessionDurationInStatusJson(data) && data.transcript_path) {
69249
69431
  sessionDuration = await getSessionDuration(data.transcript_path);
69250
69432
  }
69251
- const usageData = await prefetchUsageDataIfNeeded(lines);
69433
+ const usageData = await prefetchUsageDataIfNeeded(lines, data);
69252
69434
  let speedMetrics = null;
69253
69435
  let windowedSpeedMetrics = null;
69254
69436
  if (hasSpeedItems && data.transcript_path) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccstatusline-usage",
3
- "version": "2.3.3",
3
+ "version": "2.3.5",
4
4
  "description": "A customizable status line formatter for Claude Code CLI",
5
5
  "module": "src/ccstatusline.ts",
6
6
  "type": "module",