ccstatusline-usage 2.3.1 → 2.3.3
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 +14 -1
- package/dist/ccstatusline.js +100 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -34,13 +34,14 @@ 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
38
|
- **Two-line Layout** - Session info on line 1, context on line 2
|
|
38
39
|
|
|
39
40
|
### Enhanced Status Line Preview
|
|
40
41
|
|
|
41
42
|
```
|
|
42
43
|
Session: [████░░░░░░░░░░░] 27.0% | Weekly: [███████████████] 100.0% | Extra: €2.50/€50.00 | Model: Opus 4.6 | Session ID: 0109b99d...
|
|
43
|
-
Context: [███████░░░░░░░░] 103k/200k (51%) | Pace: [░░░░░░░|██░░░░░] D5/7 +12%
|
|
44
|
+
Context: [███████░░░░░░░░] 103k/200k (51%) | Pace: [░░░░░░░|██░░░░░] D5/7 +12% | Off peak: Off-peak 2x
|
|
44
45
|
```
|
|
45
46
|
|
|
46
47
|

|
|
@@ -65,6 +66,17 @@ Session: [████░░░░░░░░░░░] 27.0% | Weekly: [██
|
|
|
65
66
|
|
|
66
67
|
## 🆕 Recent Updates
|
|
67
68
|
|
|
69
|
+
### [v2.3.3](https://github.com/pcvelz/ccstatusline-usage/releases/tag/v2.3.3) - CI pipeline fix
|
|
70
|
+
|
|
71
|
+
- [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
|
|
72
|
+
- [pcvelz/ccstatusline-usage](https://github.com/pcvelz/ccstatusline-usage): **Release workflow** — Added mandatory CI pipeline check before tagging/releasing
|
|
73
|
+
|
|
74
|
+
### [v2.3.2](https://github.com/pcvelz/ccstatusline-usage/releases/tag/v2.3.2) - Off Peak widget + WeeklyPace compact fix
|
|
75
|
+
|
|
76
|
+
- [pcvelz/ccstatusline-usage](https://github.com/pcvelz/ccstatusline-usage): **Off Peak widget** — New widget showing `Off peak: Off-peak 2x` or `Off peak: Peak` during the Anthropic March 2026 Spring Break promotion (off-peak = weekdays outside 8 AM–2 PM ET, weekends all day). Widget automatically hides after March 28, 2026 23:59 PT.
|
|
77
|
+
- [pcvelz/ccstatusline-usage](https://github.com/pcvelz/ccstatusline-usage): **WeeklyPace compact fix** — Pendulum bar now falls back to text mode (`D6/7: -18%`) on narrow terminals (< 80 chars)
|
|
78
|
+
- [pcvelz/ccstatusline-usage](https://github.com/pcvelz/ccstatusline-usage): **Sonnet [1m] extra usage fix** — Extra usage spending now shown when a charged `[1m]` model (e.g. Sonnet) is active, regardless of weekly limit status
|
|
79
|
+
|
|
68
80
|
### [v2.3.1](https://github.com/pcvelz/ccstatusline-usage/releases/tag/v2.3.1) - Weekly Pace widget
|
|
69
81
|
|
|
70
82
|
- [pcvelz/ccstatusline-usage](https://github.com/pcvelz/ccstatusline-usage): **Weekly Pace widget** — New widget showing if weekly usage pace is on track, with pendulum bar or text display mode (PR #1 by @BenIsLegit)
|
|
@@ -550,6 +562,7 @@ bun run example
|
|
|
550
562
|
- **Skills** - Shows skill activity as last used, total count, or unique list (with optional list limit and hide-when-empty toggle)
|
|
551
563
|
- **Thinking Effort** - Shows the current Claude Code thinking effort level
|
|
552
564
|
- **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)
|
|
553
566
|
- **Separator** - Visual divider between widgets (available when Powerline mode is off and no default separator is configured)
|
|
554
567
|
- **Flex Separator** - Expands to fill available space (available when Powerline mode is off)
|
|
555
568
|
|
package/dist/ccstatusline.js
CHANGED
|
@@ -52428,7 +52428,9 @@ var init_Settings = __esm(() => {
|
|
|
52428
52428
|
{ id: "session-id", type: "claude-session-id", color: "cyan" }
|
|
52429
52429
|
],
|
|
52430
52430
|
[
|
|
52431
|
-
{ id: "context-bar", type: "context-bar", color: "blue" }
|
|
52431
|
+
{ id: "context-bar", type: "context-bar", color: "blue" },
|
|
52432
|
+
{ id: "sep-off-peak", type: "separator" },
|
|
52433
|
+
{ id: "off-peak", type: "off-peak", color: "green" }
|
|
52432
52434
|
],
|
|
52433
52435
|
[]
|
|
52434
52436
|
]),
|
|
@@ -52450,6 +52452,7 @@ var init_Settings = __esm(() => {
|
|
|
52450
52452
|
theme: undefined,
|
|
52451
52453
|
autoAlign: false
|
|
52452
52454
|
}),
|
|
52455
|
+
extraUsageBalance: exports_external.number().optional(),
|
|
52453
52456
|
updatemessage: exports_external.object({
|
|
52454
52457
|
message: exports_external.string().nullable().optional(),
|
|
52455
52458
|
remaining: exports_external.number().nullable().optional()
|
|
@@ -54069,7 +54072,7 @@ function getTerminalWidth() {
|
|
|
54069
54072
|
function canDetectTerminalWidth() {
|
|
54070
54073
|
return probeTerminalWidth() !== null;
|
|
54071
54074
|
}
|
|
54072
|
-
var __dirname = "/Users/peter/Documents/Code/ccstatusline-usage/src/utils", PACKAGE_VERSION = "2.3.
|
|
54075
|
+
var __dirname = "/Users/peter/Documents/Code/ccstatusline-usage/src/utils", PACKAGE_VERSION = "2.3.3";
|
|
54073
54076
|
var init_terminal = () => {};
|
|
54074
54077
|
|
|
54075
54078
|
// src/utils/renderer.ts
|
|
@@ -61429,7 +61432,7 @@ import * as path7 from "path";
|
|
|
61429
61432
|
function readTokenFromFile() {
|
|
61430
61433
|
try {
|
|
61431
61434
|
const creds = JSON.parse(fs9.readFileSync(CRED_FILE, "utf8"));
|
|
61432
|
-
return creds
|
|
61435
|
+
return creds.claudeAiOauth?.accessToken ?? null;
|
|
61433
61436
|
} catch {
|
|
61434
61437
|
return null;
|
|
61435
61438
|
}
|
|
@@ -61438,7 +61441,7 @@ function readTokenFromKeychain() {
|
|
|
61438
61441
|
try {
|
|
61439
61442
|
const result2 = execSync5('security find-generic-password -s "Claude Code-credentials" -w 2>/dev/null', { encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
61440
61443
|
const parsed = JSON.parse(result2);
|
|
61441
|
-
return parsed
|
|
61444
|
+
return parsed.claudeAiOauth?.accessToken ?? null;
|
|
61442
61445
|
} catch {
|
|
61443
61446
|
return null;
|
|
61444
61447
|
}
|
|
@@ -61455,8 +61458,7 @@ function getToken() {
|
|
|
61455
61458
|
let token = null;
|
|
61456
61459
|
if (process.platform === "darwin")
|
|
61457
61460
|
token = readTokenFromKeychain();
|
|
61458
|
-
|
|
61459
|
-
token = readTokenFromFile();
|
|
61461
|
+
token ??= readTokenFromFile();
|
|
61460
61462
|
if (token) {
|
|
61461
61463
|
cachedToken = token;
|
|
61462
61464
|
tokenCacheTime = now2;
|
|
@@ -61743,7 +61745,12 @@ class ResetTimerWidget {
|
|
|
61743
61745
|
const data = fetchApiData();
|
|
61744
61746
|
if (data.error)
|
|
61745
61747
|
return getErrorMessage(data.error);
|
|
61746
|
-
|
|
61748
|
+
const model = context.data?.model;
|
|
61749
|
+
const modelId = (typeof model === "string" ? model : model?.id) ?? "";
|
|
61750
|
+
const is1mModel = modelId.includes("[1m]");
|
|
61751
|
+
const isOpus = modelId.includes("opus");
|
|
61752
|
+
const isChargedModel = is1mModel && !isOpus;
|
|
61753
|
+
if (data.extraUsageEnabled && data.extraUsageUsed !== undefined && data.extraUsageLimit !== undefined && (data.weeklyUsage !== undefined && data.weeklyUsage >= 100 || isChargedModel)) {
|
|
61747
61754
|
const used = formatCents(data.extraUsageUsed);
|
|
61748
61755
|
const displayLimit = settings.extraUsageBalance ?? data.extraUsageLimit;
|
|
61749
61756
|
const limit = formatCents(displayLimit);
|
|
@@ -62569,7 +62576,8 @@ class WeeklyPaceWidget {
|
|
|
62569
62576
|
return null;
|
|
62570
62577
|
const actualPercent = Math.max(0, Math.min(100, data.weeklyUsage));
|
|
62571
62578
|
const { delta, dayOfWeek, status } = computePace(actualPercent, window2.elapsedPercent);
|
|
62572
|
-
|
|
62579
|
+
const mobile = (context.terminalWidth ?? 0) > 0 && (context.terminalWidth ?? 0) < MOBILE_THRESHOLD3;
|
|
62580
|
+
if (displayMode === "pendulum" && !mobile) {
|
|
62573
62581
|
const sign = delta >= 0 ? "+" : "";
|
|
62574
62582
|
const barDisplay = `${makePendulumBar(delta)} D${dayOfWeek}/7 ${sign}${Math.round(delta)}%`;
|
|
62575
62583
|
return formatRawOrLabeledValue(item, "Pace: ", barDisplay);
|
|
@@ -62588,10 +62596,91 @@ class WeeklyPaceWidget {
|
|
|
62588
62596
|
return true;
|
|
62589
62597
|
}
|
|
62590
62598
|
}
|
|
62599
|
+
var MOBILE_THRESHOLD3 = 80;
|
|
62591
62600
|
var init_WeeklyPace = __esm(() => {
|
|
62592
62601
|
init_usage();
|
|
62593
62602
|
});
|
|
62594
62603
|
|
|
62604
|
+
// 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
|
+
}
|
|
62610
|
+
const dayOfWeek = now2.getUTCDay();
|
|
62611
|
+
const isWeekend = dayOfWeek === 0 || dayOfWeek === 6;
|
|
62612
|
+
if (isWeekend)
|
|
62613
|
+
return true;
|
|
62614
|
+
const utcHour = now2.getUTCHours();
|
|
62615
|
+
const isPeak = utcHour >= PEAK_START_UTC_HOUR && utcHour < PEAK_END_UTC_HOUR;
|
|
62616
|
+
return !isPeak;
|
|
62617
|
+
}
|
|
62618
|
+
function minutesUntilFlip(now2) {
|
|
62619
|
+
const dayOfWeek = now2.getUTCDay();
|
|
62620
|
+
const isWeekend = dayOfWeek === 0 || dayOfWeek === 6;
|
|
62621
|
+
if (isWeekend)
|
|
62622
|
+
return null;
|
|
62623
|
+
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;
|
|
62626
|
+
const target = new Date(now2);
|
|
62627
|
+
if (!isPeak && utcHour >= PEAK_END_UTC_HOUR) {
|
|
62628
|
+
target.setUTCDate(now2.getUTCDate() + 1);
|
|
62629
|
+
}
|
|
62630
|
+
target.setUTCHours(flipHour, 0, 0, 0);
|
|
62631
|
+
return Math.max(0, Math.round((target.getTime() - now2.getTime()) / 60000));
|
|
62632
|
+
}
|
|
62633
|
+
function formatCountdown(minutes) {
|
|
62634
|
+
const h = Math.floor(minutes / 60);
|
|
62635
|
+
const m = minutes % 60;
|
|
62636
|
+
return `${h}:${String(m).padStart(2, "0")}`;
|
|
62637
|
+
}
|
|
62638
|
+
|
|
62639
|
+
class OffPeakWidget {
|
|
62640
|
+
getDefaultColor() {
|
|
62641
|
+
return "green";
|
|
62642
|
+
}
|
|
62643
|
+
getDescription() {
|
|
62644
|
+
return "Shows peak / off-peak 2x status during the March 2026 Anthropic usage promotion";
|
|
62645
|
+
}
|
|
62646
|
+
getDisplayName() {
|
|
62647
|
+
return "Off Peak";
|
|
62648
|
+
}
|
|
62649
|
+
getCategory() {
|
|
62650
|
+
return "Usage";
|
|
62651
|
+
}
|
|
62652
|
+
getEditorDisplay(_item) {
|
|
62653
|
+
return { displayText: this.getDisplayName() };
|
|
62654
|
+
}
|
|
62655
|
+
render(item, context, _settings) {
|
|
62656
|
+
if (context.isPreview) {
|
|
62657
|
+
return item.rawValue ? "Off-peak 2x (3:42)" : "Off-peak 2x (3:42)";
|
|
62658
|
+
}
|
|
62659
|
+
const now2 = new Date;
|
|
62660
|
+
const offPeak = isOffPeak(now2);
|
|
62661
|
+
if (offPeak === null)
|
|
62662
|
+
return null;
|
|
62663
|
+
const mins = minutesUntilFlip(now2);
|
|
62664
|
+
const countdown = mins !== null ? ` (${formatCountdown(mins)} hr)` : "";
|
|
62665
|
+
const mobile = (context.terminalWidth ?? 0) > 0 && (context.terminalWidth ?? 0) < 80;
|
|
62666
|
+
if (offPeak) {
|
|
62667
|
+
return mobile ? `2x${countdown}` : `Off-peak 2x${countdown}`;
|
|
62668
|
+
}
|
|
62669
|
+
return `Peak${countdown}`;
|
|
62670
|
+
}
|
|
62671
|
+
supportsRawValue() {
|
|
62672
|
+
return true;
|
|
62673
|
+
}
|
|
62674
|
+
supportsColors(_item) {
|
|
62675
|
+
return true;
|
|
62676
|
+
}
|
|
62677
|
+
}
|
|
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
|
+
});
|
|
62683
|
+
|
|
62595
62684
|
// src/widgets/index.ts
|
|
62596
62685
|
var init_widgets = __esm(async () => {
|
|
62597
62686
|
init_GitBranch();
|
|
@@ -62611,6 +62700,7 @@ var init_widgets = __esm(async () => {
|
|
|
62611
62700
|
init_Battery();
|
|
62612
62701
|
init_VimMode();
|
|
62613
62702
|
init_WeeklyPace();
|
|
62703
|
+
init_OffPeak();
|
|
62614
62704
|
await __promiseAll([
|
|
62615
62705
|
init_TokensInput(),
|
|
62616
62706
|
init_TokensOutput(),
|
|
@@ -62671,7 +62761,8 @@ var init_widget_manifest = __esm(async () => {
|
|
|
62671
62761
|
{ type: "thinking-effort", create: () => new ThinkingEffortWidget },
|
|
62672
62762
|
{ type: "battery", create: () => new BatteryWidget },
|
|
62673
62763
|
{ type: "vim-mode", create: () => new VimModeWidget },
|
|
62674
|
-
{ type: "weekly-pace", create: () => new WeeklyPaceWidget }
|
|
62764
|
+
{ type: "weekly-pace", create: () => new WeeklyPaceWidget },
|
|
62765
|
+
{ type: "off-peak", create: () => new OffPeakWidget }
|
|
62675
62766
|
];
|
|
62676
62767
|
LAYOUT_WIDGET_MANIFEST = [
|
|
62677
62768
|
{
|