ccstatusline-usage 2.3.4 → 2.3.6

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,16 @@ Session: [████░░░░░░░░░░░] 27.0% | Weekly: [██
66
66
 
67
67
  ## 🆕 Recent Updates
68
68
 
69
+ ### [v2.3.6](https://github.com/pcvelz/ccstatusline-usage/releases/tag/v2.3.6) - Remove expired 2x promo code
70
+
71
+ - [pcvelz/ccstatusline-usage](https://github.com/pcvelz/ccstatusline-usage): **Off-Peak cleanup** — Removed expired March 2026 promo (2x) code path, leaving only the permanent peak/off-peak indicator
72
+
73
+ ### [v2.3.5](https://github.com/pcvelz/ccstatusline-usage/releases/tag/v2.3.5) - Upstream sync + permanent peak/off-peak widget
74
+
75
+ - [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
76
+ - [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)
77
+ - [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
78
+
69
79
  ### [v2.3.4](https://github.com/pcvelz/ccstatusline-usage/releases/tag/v2.3.4) - Upstream sync + extra usage fix
70
80
 
71
81
  - [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 +347,19 @@ ccstatusline works seamlessly on Windows with full feature compatibility across
337
347
  irm bun.sh/install.ps1 | iex
338
348
 
339
349
  # Run ccstatusline
340
- bunx -y ccstatusline@latest
350
+ bunx -y ccstatusline-usage@latest
341
351
  ```
342
352
 
343
353
  #### Option 2: Using Node.js
344
354
  ```powershell
345
355
  # Using npm
346
- npx -y ccstatusline@latest
356
+ npx -y ccstatusline-usage@latest
347
357
 
348
358
  # Or with Yarn
349
- yarn dlx ccstatusline@latest
359
+ yarn dlx ccstatusline-usage@latest
350
360
 
351
361
  # Or with pnpm
352
- pnpm dlx ccstatusline@latest
362
+ pnpm dlx ccstatusline-usage@latest
353
363
  ```
354
364
 
355
365
  ### Windows-Specific Features
@@ -404,7 +414,7 @@ winget install Git.Git
404
414
  **Issue**: Permission errors during installation
405
415
  ```powershell
406
416
  # Use non-global installation (recommended)
407
- npx -y ccstatusline@latest
417
+ npx -y ccstatusline-usage@latest
408
418
 
409
419
  # Or run PowerShell as Administrator for global install
410
420
  ```
@@ -432,7 +442,7 @@ ccstatusline works perfectly in WSL environments:
432
442
  # Install in WSL Ubuntu/Debian
433
443
  curl -fsSL https://bun.sh/install | bash
434
444
  source ~/.bashrc
435
- bunx -y ccstatusline@latest
445
+ bunx -y ccstatusline-usage@latest
436
446
  ```
437
447
 
438
448
  **WSL Benefits**:
@@ -471,7 +481,7 @@ Configure ccstatusline in your Claude Code settings:
471
481
  {
472
482
  "statusLine": {
473
483
  "type": "command",
474
- "command": "bunx -y ccstatusline@latest",
484
+ "command": "bunx -y ccstatusline-usage@latest",
475
485
  "padding": 0
476
486
  }
477
487
  }
@@ -482,7 +492,7 @@ Configure ccstatusline in your Claude Code settings:
482
492
  {
483
493
  "statusLine": {
484
494
  "type": "command",
485
- "command": "npx -y ccstatusline@latest",
495
+ "command": "npx -y ccstatusline-usage@latest",
486
496
  "padding": 0
487
497
  }
488
498
  }
@@ -567,7 +577,7 @@ bun run example
567
577
  - **Skills** - Shows skill activity as last used, total count, or unique list (with optional list limit and hide-when-empty toggle)
568
578
  - **Thinking Effort** - Shows the current Claude Code thinking effort level
569
579
  - **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)
580
+ - **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
581
  - **Separator** - Visual divider between widgets (available when Powerline mode is off and no default separator is configured)
572
582
  - **Flex Separator** - Expands to fill available space (available when Powerline mode is off)
573
583
 
@@ -762,7 +772,7 @@ The documentation will be generated in the `docs/` directory and can be viewed b
762
772
 
763
773
  ```bash
764
774
  # Clone the repository
765
- git clone https://github.com/sirmalloc/ccstatusline.git
775
+ git clone https://github.com/pcvelz/ccstatusline-usage.git
766
776
  cd ccstatusline
767
777
 
768
778
  # Install dependencies
@@ -922,7 +932,7 @@ Give a ⭐ if this project helped you!
922
932
 
923
933
  [![npm version](https://img.shields.io/npm/v/ccstatusline-usage.svg)](https://www.npmjs.com/package/ccstatusline-usage)
924
934
  [![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)
935
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/pcvelz/ccstatusline-usage/blob/main/LICENSE)
926
936
  [![Made with Bun](https://img.shields.io/badge/Made%20with-Bun-000000.svg?logo=bun)](https://bun.sh)
927
937
 
928
938
  [![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.6";
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,41 @@ 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 isOffPeak(now2) {
62736
+ if (isWeekend(now2))
62737
+ return true;
62738
+ return !isPeakHour(now2);
62617
62739
  }
62618
62740
  function minutesUntilFlip(now2) {
62619
- const dayOfWeek = now2.getUTCDay();
62620
- const isWeekend = dayOfWeek === 0 || dayOfWeek === 6;
62621
- if (isWeekend)
62622
- return null;
62741
+ if (isWeekend(now2)) {
62742
+ return minutesUntilMondayPeak(now2);
62743
+ }
62623
62744
  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;
62745
+ const peak = isPeakHour(now2);
62746
+ const flipHour = peak ? PEAK_END_UTC_HOUR : PEAK_START_UTC_HOUR;
62626
62747
  const target = new Date(now2);
62627
- if (!isPeak && utcHour >= PEAK_END_UTC_HOUR) {
62748
+ if (!peak && utcHour >= PEAK_END_UTC_HOUR) {
62628
62749
  target.setUTCDate(now2.getUTCDate() + 1);
62629
62750
  }
62630
62751
  target.setUTCHours(flipHour, 0, 0, 0);
62631
62752
  return Math.max(0, Math.round((target.getTime() - now2.getTime()) / 60000));
62632
62753
  }
62754
+ function minutesUntilMondayPeak(now2) {
62755
+ const dayOfWeek = now2.getUTCDay();
62756
+ const daysUntilMonday = dayOfWeek === 0 ? 1 : 8 - dayOfWeek;
62757
+ const target = new Date(now2);
62758
+ target.setUTCDate(now2.getUTCDate() + daysUntilMonday);
62759
+ target.setUTCHours(PEAK_START_UTC_HOUR, 0, 0, 0);
62760
+ return Math.max(0, Math.round((target.getTime() - now2.getTime()) / 60000));
62761
+ }
62633
62762
  function formatCountdown(minutes) {
62634
62763
  const h = Math.floor(minutes / 60);
62635
62764
  const m = minutes % 60;
@@ -62641,7 +62770,7 @@ class OffPeakWidget {
62641
62770
  return "green";
62642
62771
  }
62643
62772
  getDescription() {
62644
- return "Shows peak / off-peak 2x status during the March 2026 Anthropic usage promotion";
62773
+ return "Shows peak / off-peak status with countdown timer";
62645
62774
  }
62646
62775
  getDisplayName() {
62647
62776
  return "Off Peak";
@@ -62654,17 +62783,15 @@ class OffPeakWidget {
62654
62783
  }
62655
62784
  render(item, context, _settings) {
62656
62785
  if (context.isPreview) {
62657
- return item.rawValue ? "Off-peak 2x (3:42)" : "Off-peak 2x (3:42)";
62786
+ return item.rawValue ? "Off-peak (3:42 hr)" : "Off-peak (3:42 hr)";
62658
62787
  }
62659
62788
  const now2 = new Date;
62660
62789
  const offPeak = isOffPeak(now2);
62661
- if (offPeak === null)
62662
- return null;
62663
62790
  const mins = minutesUntilFlip(now2);
62664
- const countdown = mins !== null ? ` (${formatCountdown(mins)} hr)` : "";
62791
+ const countdown = ` (${formatCountdown(mins)} hr)`;
62665
62792
  const mobile = (context.terminalWidth ?? 0) > 0 && (context.terminalWidth ?? 0) < 80;
62666
62793
  if (offPeak) {
62667
- return mobile ? `2x${countdown}` : `Off-peak 2x${countdown}`;
62794
+ return mobile ? `OffPk${countdown}` : `Off-peak${countdown}`;
62668
62795
  }
62669
62796
  return `Peak${countdown}`;
62670
62797
  }
@@ -62675,11 +62802,7 @@ class OffPeakWidget {
62675
62802
  return true;
62676
62803
  }
62677
62804
  }
62678
- var PROMO_START_MS, PROMO_END_MS, PEAK_START_UTC_HOUR = 12, PEAK_END_UTC_HOUR = 18;
62679
- var init_OffPeak = __esm(() => {
62680
- PROMO_START_MS = Date.UTC(2026, 2, 13, 7, 0, 0);
62681
- PROMO_END_MS = Date.UTC(2026, 2, 29, 6, 59, 0);
62682
- });
62805
+ var PEAK_START_UTC_HOUR = 12, PEAK_END_UTC_HOUR = 18;
62683
62806
 
62684
62807
  // src/widgets/index.ts
62685
62808
  var init_widgets = __esm(async () => {
@@ -62696,11 +62819,11 @@ var init_widgets = __esm(async () => {
62696
62819
  init_FreeMemory();
62697
62820
  init_SessionName();
62698
62821
  init_ApiUsage();
62822
+ init_WeeklyResetTimer();
62699
62823
  init_ThinkingEffort();
62700
62824
  init_Battery();
62701
62825
  init_VimMode();
62702
62826
  init_WeeklyPace();
62703
- init_OffPeak();
62704
62827
  await __promiseAll([
62705
62828
  init_TokensInput(),
62706
62829
  init_TokensOutput(),
@@ -62756,6 +62879,7 @@ var init_widget_manifest = __esm(async () => {
62756
62879
  { type: "session-usage", create: () => new SessionUsageWidget },
62757
62880
  { type: "weekly-usage", create: () => new WeeklyUsageWidget },
62758
62881
  { type: "reset-timer", create: () => new ResetTimerWidget },
62882
+ { type: "weekly-reset-timer", create: () => new WeeklyResetTimerWidget },
62759
62883
  { type: "context-bar", create: () => new ContextBarWidget },
62760
62884
  { type: "skills", create: () => new SkillsWidget },
62761
62885
  { 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.6",
4
4
  "description": "A customizable status line formatter for Claude Code CLI",
5
5
  "module": "src/ccstatusline.ts",
6
6
  "type": "module",