ccstatusline-usage 2.3.4 → 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,12 @@ 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
+
69
75
  ### [v2.3.4](https://github.com/pcvelz/ccstatusline-usage/releases/tag/v2.3.4) - Upstream sync + extra usage fix
70
76
 
71
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
@@ -337,19 +343,19 @@ ccstatusline works seamlessly on Windows with full feature compatibility across
337
343
  irm bun.sh/install.ps1 | iex
338
344
 
339
345
  # Run ccstatusline
340
- bunx -y ccstatusline@latest
346
+ bunx -y ccstatusline-usage@latest
341
347
  ```
342
348
 
343
349
  #### Option 2: Using Node.js
344
350
  ```powershell
345
351
  # Using npm
346
- npx -y ccstatusline@latest
352
+ npx -y ccstatusline-usage@latest
347
353
 
348
354
  # Or with Yarn
349
- yarn dlx ccstatusline@latest
355
+ yarn dlx ccstatusline-usage@latest
350
356
 
351
357
  # Or with pnpm
352
- pnpm dlx ccstatusline@latest
358
+ pnpm dlx ccstatusline-usage@latest
353
359
  ```
354
360
 
355
361
  ### Windows-Specific Features
@@ -404,7 +410,7 @@ winget install Git.Git
404
410
  **Issue**: Permission errors during installation
405
411
  ```powershell
406
412
  # Use non-global installation (recommended)
407
- npx -y ccstatusline@latest
413
+ npx -y ccstatusline-usage@latest
408
414
 
409
415
  # Or run PowerShell as Administrator for global install
410
416
  ```
@@ -432,7 +438,7 @@ ccstatusline works perfectly in WSL environments:
432
438
  # Install in WSL Ubuntu/Debian
433
439
  curl -fsSL https://bun.sh/install | bash
434
440
  source ~/.bashrc
435
- bunx -y ccstatusline@latest
441
+ bunx -y ccstatusline-usage@latest
436
442
  ```
437
443
 
438
444
  **WSL Benefits**:
@@ -471,7 +477,7 @@ Configure ccstatusline in your Claude Code settings:
471
477
  {
472
478
  "statusLine": {
473
479
  "type": "command",
474
- "command": "bunx -y ccstatusline@latest",
480
+ "command": "bunx -y ccstatusline-usage@latest",
475
481
  "padding": 0
476
482
  }
477
483
  }
@@ -482,7 +488,7 @@ Configure ccstatusline in your Claude Code settings:
482
488
  {
483
489
  "statusLine": {
484
490
  "type": "command",
485
- "command": "npx -y ccstatusline@latest",
491
+ "command": "npx -y ccstatusline-usage@latest",
486
492
  "padding": 0
487
493
  }
488
494
  }
@@ -567,7 +573,7 @@ bun run example
567
573
  - **Skills** - Shows skill activity as last used, total count, or unique list (with optional list limit and hide-when-empty toggle)
568
574
  - **Thinking Effort** - Shows the current Claude Code thinking effort level
569
575
  - **Vim Mode** - Displays current vim editor mode
570
- - **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
571
577
  - **Separator** - Visual divider between widgets (available when Powerline mode is off and no default separator is configured)
572
578
  - **Flex Separator** - Expands to fill available space (available when Powerline mode is off)
573
579
 
@@ -762,7 +768,7 @@ The documentation will be generated in the `docs/` directory and can be viewed b
762
768
 
763
769
  ```bash
764
770
  # Clone the repository
765
- git clone https://github.com/sirmalloc/ccstatusline.git
771
+ git clone https://github.com/pcvelz/ccstatusline-usage.git
766
772
  cd ccstatusline
767
773
 
768
774
  # Install dependencies
@@ -922,7 +928,7 @@ Give a ⭐ if this project helped you!
922
928
 
923
929
  [![npm version](https://img.shields.io/npm/v/ccstatusline-usage.svg)](https://www.npmjs.com/package/ccstatusline-usage)
924
930
  [![npm downloads](https://img.shields.io/npm/dm/ccstatusline-usage.svg)](https://www.npmjs.com/package/ccstatusline-usage)
925
- [![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)
926
932
  [![Made with Bun](https://img.shields.io/badge/Made%20with-Bun-000000.svg?logo=bun)](https://bun.sh)
927
933
 
928
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.4";
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 },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccstatusline-usage",
3
- "version": "2.3.4",
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",