ccstatusline-usage 2.0.41 → 2.0.44
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 +15 -3
- package/dist/ccstatusline.js +103 -22
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
This fork adds API-based usage widgets beyond the upstream:
|
|
30
30
|
|
|
31
31
|
- **Session/Weekly Usage** - Real utilization from Anthropic API with progress bars
|
|
32
|
+
- **Extra Usage** - When weekly limit is reached, shows extra usage spending (e.g. `Extra: €41.24/€47.00`)
|
|
32
33
|
- **Reset Timer** - Time until 5-hour session window resets
|
|
33
34
|
- **Context Window Display** - Visual bar showing context usage
|
|
34
35
|
- **Two-line Layout** - Session info on line 1, context on line 2
|
|
@@ -36,7 +37,7 @@ This fork adds API-based usage widgets beyond the upstream:
|
|
|
36
37
|
### Enhanced Status Line Preview
|
|
37
38
|
|
|
38
39
|
```
|
|
39
|
-
Session: [████░░░░░░░░░░░] 27.0% | Weekly: [████████████░░░] 86.0% | 1:56 hr | Model: Opus 4.
|
|
40
|
+
Session: [████░░░░░░░░░░░] 27.0% | Weekly: [████████████░░░] 86.0% | 1:56 hr | Extra: $41.24/$47.00 | Model: Opus 4.6 | Session ID: 714aa815-8a...
|
|
40
41
|
Context: [███████░░░░░░░░] 103k/200k (51%)
|
|
41
42
|
```
|
|
42
43
|
|
|
@@ -64,6 +65,17 @@ These widgets are enabled by default. Just install and run!
|
|
|
64
65
|
|
|
65
66
|
## 🆕 Recent Updates
|
|
66
67
|
|
|
68
|
+
### [v2.0.43](https://github.com/pcvelz/ccstatusline-usage/releases/tag/v2.0.43) - Extra usage spending display
|
|
69
|
+
|
|
70
|
+
- Show extra usage spending in Reset Timer widget when weekly limit is reached (e.g. `Extra: €41.24/€47.00`)
|
|
71
|
+
- Auto-detect currency from timezone (Europe/* = €, else $)
|
|
72
|
+
- Updated README release notes
|
|
73
|
+
|
|
74
|
+
### [v2.0.42](https://github.com/pcvelz/ccstatusline-usage/releases/tag/v2.0.42) - Fix reset timer API field
|
|
75
|
+
|
|
76
|
+
- Fixed API field name from `reset_at` to `resets_at` — reset timer now displays correctly
|
|
77
|
+
- Merged latest changes from upstream ccstatusline
|
|
78
|
+
|
|
67
79
|
### v2.0.16 - Add fish style path abbreviation toggle to Current Working Directory widget
|
|
68
80
|
|
|
69
81
|
### v2.0.15 - Block Timer calculation fixes
|
|
@@ -369,10 +381,10 @@ Once configured, ccstatusline automatically formats your Claude Code status line
|
|
|
369
381
|
|
|
370
382
|
### 📊 Available Widgets
|
|
371
383
|
|
|
372
|
-
#### API Usage Widgets (
|
|
384
|
+
#### API Usage Widgets ([pcvelz/ccstatusline-usage](https://github.com/pcvelz/ccstatusline-usage))
|
|
373
385
|
- **Session Usage** - 5-hour session utilization with progress bar (e.g., "Session: [████░░░░░░░░░░░] 29.0%")
|
|
374
386
|
- **Weekly Usage** - 7-day utilization with progress bar (e.g., "Weekly: [█░░░░░░░░░░░░░░] 7.0%")
|
|
375
|
-
- **Reset Timer** - Time until 5-hour session window resets (e.g., "2:59 hr")
|
|
387
|
+
- **Reset Timer / Extra Usage** - Time until 5-hour session window resets (e.g., "2:59 hr"), or extra usage spending when weekly limit is reached (e.g., "Extra: €41.24/€47.00")
|
|
376
388
|
- **Context Bar** - Visual context window usage with bar (e.g., "Context: [███████░░░░░░░░] 103k/200k (51%)")
|
|
377
389
|
|
|
378
390
|
#### Standard Widgets
|
package/dist/ccstatusline.js
CHANGED
|
@@ -51450,7 +51450,7 @@ import { execSync as execSync3 } from "child_process";
|
|
|
51450
51450
|
import * as fs5 from "fs";
|
|
51451
51451
|
import * as path4 from "path";
|
|
51452
51452
|
var __dirname = "/Users/peter/Documents/Code/ccstatusline-usage/src/utils";
|
|
51453
|
-
var PACKAGE_VERSION = "2.0.
|
|
51453
|
+
var PACKAGE_VERSION = "2.0.44";
|
|
51454
51454
|
function getPackageVersion() {
|
|
51455
51455
|
if (/^\d+\.\d+\.\d+/.test(PACKAGE_VERSION)) {
|
|
51456
51456
|
return PACKAGE_VERSION;
|
|
@@ -52296,8 +52296,11 @@ class ModelWidget {
|
|
|
52296
52296
|
render(item, context, settings) {
|
|
52297
52297
|
if (context.isPreview) {
|
|
52298
52298
|
return item.rawValue ? "Claude" : "Model: Claude";
|
|
52299
|
-
}
|
|
52300
|
-
|
|
52299
|
+
}
|
|
52300
|
+
const model = context.data?.model;
|
|
52301
|
+
const modelDisplayName = typeof model === "string" ? model : model?.display_name ?? model?.id;
|
|
52302
|
+
if (modelDisplayName) {
|
|
52303
|
+
return item.rawValue ? modelDisplayName : `Model: ${modelDisplayName}`;
|
|
52301
52304
|
}
|
|
52302
52305
|
return null;
|
|
52303
52306
|
}
|
|
@@ -52590,7 +52593,8 @@ function calculateContextPercentage(context) {
|
|
|
52590
52593
|
if (!context.tokenMetrics) {
|
|
52591
52594
|
return 0;
|
|
52592
52595
|
}
|
|
52593
|
-
const
|
|
52596
|
+
const model = context.data?.model;
|
|
52597
|
+
const modelId = typeof model === "string" ? model : model?.id;
|
|
52594
52598
|
const contextConfig = getContextConfig(modelId);
|
|
52595
52599
|
return Math.min(100, context.tokenMetrics.contextLength / contextConfig.maxTokens * 100);
|
|
52596
52600
|
}
|
|
@@ -53446,7 +53450,8 @@ class ContextPercentageWidget {
|
|
|
53446
53450
|
const previewValue = isInverse ? "90.7%" : "9.3%";
|
|
53447
53451
|
return item.rawValue ? previewValue : `Ctx: ${previewValue}`;
|
|
53448
53452
|
} else if (context.tokenMetrics) {
|
|
53449
|
-
const
|
|
53453
|
+
const model = context.data?.model;
|
|
53454
|
+
const modelId = typeof model === "string" ? model : model?.id;
|
|
53450
53455
|
const contextConfig = getContextConfig(modelId);
|
|
53451
53456
|
const usedPercentage = Math.min(100, context.tokenMetrics.contextLength / contextConfig.maxTokens * 100);
|
|
53452
53457
|
const displayPercentage = isInverse ? 100 - usedPercentage : usedPercentage;
|
|
@@ -53519,7 +53524,8 @@ class ContextPercentageUsableWidget {
|
|
|
53519
53524
|
const previewValue = isInverse ? "88.4%" : "11.6%";
|
|
53520
53525
|
return item.rawValue ? previewValue : `Ctx(u): ${previewValue}`;
|
|
53521
53526
|
} else if (context.tokenMetrics) {
|
|
53522
|
-
const
|
|
53527
|
+
const model = context.data?.model;
|
|
53528
|
+
const modelId = typeof model === "string" ? model : model?.id;
|
|
53523
53529
|
const contextConfig = getContextConfig(modelId);
|
|
53524
53530
|
const usedPercentage = Math.min(100, context.tokenMetrics.contextLength / contextConfig.usableTokens * 100);
|
|
53525
53531
|
const displayPercentage = isInverse ? 100 - usedPercentage : usedPercentage;
|
|
@@ -54398,7 +54404,10 @@ class ClaudeSessionIdWidget {
|
|
|
54398
54404
|
}
|
|
54399
54405
|
}
|
|
54400
54406
|
// src/widgets/ApiUsage.tsx
|
|
54401
|
-
import {
|
|
54407
|
+
import {
|
|
54408
|
+
execSync as execSync8,
|
|
54409
|
+
spawnSync
|
|
54410
|
+
} from "child_process";
|
|
54402
54411
|
import * as fs6 from "fs";
|
|
54403
54412
|
import * as path5 from "path";
|
|
54404
54413
|
var CACHE_FILE = path5.join(process.env.HOME ?? "", ".cache", "ccstatusline-api.json");
|
|
@@ -54538,11 +54547,17 @@ function fetchApiData() {
|
|
|
54538
54547
|
const apiData = {};
|
|
54539
54548
|
if (data.five_hour) {
|
|
54540
54549
|
apiData.sessionUsage = data.five_hour.utilization;
|
|
54541
|
-
apiData.sessionResetAt = data.five_hour.
|
|
54550
|
+
apiData.sessionResetAt = data.five_hour.resets_at;
|
|
54542
54551
|
}
|
|
54543
54552
|
if (data.seven_day) {
|
|
54544
54553
|
apiData.weeklyUsage = data.seven_day.utilization;
|
|
54545
54554
|
}
|
|
54555
|
+
if (data.extra_usage) {
|
|
54556
|
+
apiData.extraUsageEnabled = data.extra_usage.is_enabled === true;
|
|
54557
|
+
apiData.extraUsageLimit = data.extra_usage.monthly_limit;
|
|
54558
|
+
apiData.extraUsageUsed = data.extra_usage.used_credits;
|
|
54559
|
+
apiData.extraUsageUtilization = data.extra_usage.utilization;
|
|
54560
|
+
}
|
|
54546
54561
|
if (apiData.sessionUsage === undefined && apiData.weeklyUsage === undefined) {
|
|
54547
54562
|
const stale = readStaleCache();
|
|
54548
54563
|
if (stale && !stale.error)
|
|
@@ -54653,7 +54668,7 @@ class ResetTimerWidget {
|
|
|
54653
54668
|
return "brightBlue";
|
|
54654
54669
|
}
|
|
54655
54670
|
getDescription() {
|
|
54656
|
-
return "Shows time until
|
|
54671
|
+
return "Shows extra usage spending or time until limit reset";
|
|
54657
54672
|
}
|
|
54658
54673
|
getDisplayName() {
|
|
54659
54674
|
return "Reset Timer";
|
|
@@ -54667,6 +54682,11 @@ class ResetTimerWidget {
|
|
|
54667
54682
|
const data = fetchApiData();
|
|
54668
54683
|
if (data.error)
|
|
54669
54684
|
return getErrorMessage(data.error);
|
|
54685
|
+
if (data.extraUsageEnabled && data.extraUsageUsed !== undefined && data.extraUsageLimit !== undefined) {
|
|
54686
|
+
const used = formatCents(data.extraUsageUsed);
|
|
54687
|
+
const limit = formatCents(data.extraUsageLimit);
|
|
54688
|
+
return `Extra: ${used}/${limit}`;
|
|
54689
|
+
}
|
|
54670
54690
|
if (!data.sessionResetAt)
|
|
54671
54691
|
return null;
|
|
54672
54692
|
try {
|
|
@@ -54689,6 +54709,18 @@ class ResetTimerWidget {
|
|
|
54689
54709
|
return true;
|
|
54690
54710
|
}
|
|
54691
54711
|
}
|
|
54712
|
+
function getCurrencySymbol() {
|
|
54713
|
+
try {
|
|
54714
|
+
const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
54715
|
+
if (tz.startsWith("Europe/"))
|
|
54716
|
+
return "€";
|
|
54717
|
+
} catch {}
|
|
54718
|
+
return "$";
|
|
54719
|
+
}
|
|
54720
|
+
function formatCents(cents) {
|
|
54721
|
+
const symbol2 = getCurrencySymbol();
|
|
54722
|
+
return `${symbol2}${(cents / 100).toFixed(2)}`;
|
|
54723
|
+
}
|
|
54692
54724
|
|
|
54693
54725
|
class ContextBarWidget {
|
|
54694
54726
|
getDefaultColor() {
|
|
@@ -56306,6 +56338,7 @@ var LineSelector = ({
|
|
|
56306
56338
|
}) => {
|
|
56307
56339
|
const [selectedIndex, setSelectedIndex] = import_react37.useState(initialSelection);
|
|
56308
56340
|
const [showDeleteDialog, setShowDeleteDialog] = import_react37.useState(false);
|
|
56341
|
+
const [moveMode, setMoveMode] = import_react37.useState(false);
|
|
56309
56342
|
const [localLines, setLocalLines] = import_react37.useState(lines);
|
|
56310
56343
|
import_react37.useEffect(() => {
|
|
56311
56344
|
setLocalLines(lines);
|
|
@@ -56337,6 +56370,32 @@ var LineSelector = ({
|
|
|
56337
56370
|
onBack();
|
|
56338
56371
|
return;
|
|
56339
56372
|
}
|
|
56373
|
+
if (moveMode) {
|
|
56374
|
+
if (key.upArrow && selectedIndex > 0) {
|
|
56375
|
+
const newLines = [...localLines];
|
|
56376
|
+
const temp = newLines[selectedIndex];
|
|
56377
|
+
const prev = newLines[selectedIndex - 1];
|
|
56378
|
+
if (temp && prev) {
|
|
56379
|
+
[newLines[selectedIndex], newLines[selectedIndex - 1]] = [prev, temp];
|
|
56380
|
+
}
|
|
56381
|
+
setLocalLines(newLines);
|
|
56382
|
+
onLinesUpdate(newLines);
|
|
56383
|
+
setSelectedIndex(selectedIndex - 1);
|
|
56384
|
+
} else if (key.downArrow && selectedIndex < localLines.length - 1) {
|
|
56385
|
+
const newLines = [...localLines];
|
|
56386
|
+
const temp = newLines[selectedIndex];
|
|
56387
|
+
const next = newLines[selectedIndex + 1];
|
|
56388
|
+
if (temp && next) {
|
|
56389
|
+
[newLines[selectedIndex], newLines[selectedIndex + 1]] = [next, temp];
|
|
56390
|
+
}
|
|
56391
|
+
setLocalLines(newLines);
|
|
56392
|
+
onLinesUpdate(newLines);
|
|
56393
|
+
setSelectedIndex(selectedIndex + 1);
|
|
56394
|
+
} else if (key.escape || key.return) {
|
|
56395
|
+
setMoveMode(false);
|
|
56396
|
+
}
|
|
56397
|
+
return;
|
|
56398
|
+
}
|
|
56340
56399
|
switch (input) {
|
|
56341
56400
|
case "a":
|
|
56342
56401
|
if (allowEditing) {
|
|
@@ -56348,6 +56407,11 @@ var LineSelector = ({
|
|
|
56348
56407
|
setShowDeleteDialog(true);
|
|
56349
56408
|
}
|
|
56350
56409
|
return;
|
|
56410
|
+
case "m":
|
|
56411
|
+
if (allowEditing && localLines.length > 1 && selectedIndex < localLines.length) {
|
|
56412
|
+
setMoveMode(true);
|
|
56413
|
+
}
|
|
56414
|
+
return;
|
|
56351
56415
|
}
|
|
56352
56416
|
if (key.escape) {
|
|
56353
56417
|
onBack();
|
|
@@ -56470,17 +56534,31 @@ var LineSelector = ({
|
|
|
56470
56534
|
children: /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
|
|
56471
56535
|
flexDirection: "column",
|
|
56472
56536
|
children: [
|
|
56473
|
-
/* @__PURE__ */ jsx_dev_runtime9.jsxDEV(
|
|
56474
|
-
|
|
56475
|
-
|
|
56476
|
-
|
|
56537
|
+
/* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
|
|
56538
|
+
children: [
|
|
56539
|
+
/* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
|
|
56540
|
+
bold: true,
|
|
56541
|
+
children: [
|
|
56542
|
+
title ?? "Select Line to Edit",
|
|
56543
|
+
" "
|
|
56544
|
+
]
|
|
56545
|
+
}, undefined, true, undefined, this),
|
|
56546
|
+
moveMode && /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
|
|
56547
|
+
color: "blue",
|
|
56548
|
+
children: "[MOVE MODE]"
|
|
56549
|
+
}, undefined, false, undefined, this)
|
|
56550
|
+
]
|
|
56551
|
+
}, undefined, true, undefined, this),
|
|
56477
56552
|
/* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
|
|
56478
56553
|
dimColor: true,
|
|
56479
56554
|
children: "Choose which status line to configure"
|
|
56480
56555
|
}, undefined, false, undefined, this),
|
|
56481
|
-
/* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
|
|
56556
|
+
moveMode ? /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
|
|
56482
56557
|
dimColor: true,
|
|
56483
|
-
children:
|
|
56558
|
+
children: "↑↓ to move line, ESC or Enter to exit move mode"
|
|
56559
|
+
}, undefined, false, undefined, this) : /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
|
|
56560
|
+
dimColor: true,
|
|
56561
|
+
children: allowEditing ? localLines.length > 1 ? "(a) to append new line, (d) to delete line, (m) to move line, ESC to go back" : "(a) to append new line, ESC to go back" : "ESC to go back"
|
|
56484
56562
|
}, undefined, false, undefined, this),
|
|
56485
56563
|
/* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
|
|
56486
56564
|
marginTop: 1,
|
|
@@ -56491,10 +56569,10 @@ var LineSelector = ({
|
|
|
56491
56569
|
const suffix = line.length ? import_pluralize.default("widget", line.length, true) : "empty";
|
|
56492
56570
|
return /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
|
|
56493
56571
|
children: /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
|
|
56494
|
-
color: isSelected ? "green" : undefined,
|
|
56572
|
+
color: isSelected ? moveMode ? "blue" : "green" : undefined,
|
|
56495
56573
|
children: [
|
|
56496
56574
|
/* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
|
|
56497
|
-
children: isSelected ? "▶ " : " "
|
|
56575
|
+
children: isSelected ? moveMode ? "◆ " : "▶ " : " "
|
|
56498
56576
|
}, undefined, false, undefined, this),
|
|
56499
56577
|
/* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
|
|
56500
56578
|
children: [
|
|
@@ -56520,7 +56598,7 @@ var LineSelector = ({
|
|
|
56520
56598
|
}, undefined, true, undefined, this)
|
|
56521
56599
|
}, index, false, undefined, this);
|
|
56522
56600
|
}),
|
|
56523
|
-
/* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
|
|
56601
|
+
!moveMode && /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
|
|
56524
56602
|
marginTop: 1,
|
|
56525
56603
|
children: /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
|
|
56526
56604
|
color: selectedIndex === localLines.length ? "green" : undefined,
|
|
@@ -58540,10 +58618,13 @@ var StatusJSONSchema = exports_external.looseObject({
|
|
|
58540
58618
|
session_id: exports_external.string().optional(),
|
|
58541
58619
|
transcript_path: exports_external.string().optional(),
|
|
58542
58620
|
cwd: exports_external.string().optional(),
|
|
58543
|
-
model: exports_external.
|
|
58544
|
-
|
|
58545
|
-
|
|
58546
|
-
|
|
58621
|
+
model: exports_external.union([
|
|
58622
|
+
exports_external.string(),
|
|
58623
|
+
exports_external.object({
|
|
58624
|
+
id: exports_external.string().optional(),
|
|
58625
|
+
display_name: exports_external.string().optional()
|
|
58626
|
+
})
|
|
58627
|
+
]).optional(),
|
|
58547
58628
|
workspace: exports_external.object({
|
|
58548
58629
|
current_dir: exports_external.string().optional(),
|
|
58549
58630
|
project_dir: exports_external.string().optional()
|