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 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.5 | Session ID: 714aa815-8a...
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 (Fork Enhancement)
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
@@ -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.41";
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
- } else if (context.data?.model?.display_name) {
52300
- return item.rawValue ? context.data.model.display_name : `Model: ${context.data.model.display_name}`;
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 modelId = context.data?.model?.id;
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 modelId = context.data?.model?.id;
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 modelId = context.data?.model?.id;
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 { execSync as execSync8, spawnSync } from "child_process";
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.reset_at;
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 daily limit reset";
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(Text, {
56474
- bold: true,
56475
- children: title ?? "Select Line to Edit"
56476
- }, undefined, false, undefined, this),
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: allowEditing ? localLines.length > 1 ? "(a) to append new line, (d) to delete line, ESC to go back" : "(a) to append new line, ESC to go back" : "ESC to go back"
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.object({
58544
- id: exports_external.string().optional(),
58545
- display_name: exports_external.string().optional()
58546
- }).optional(),
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()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccstatusline-usage",
3
- "version": "2.0.41",
3
+ "version": "2.0.44",
4
4
  "description": "A customizable status line formatter for Claude Code CLI",
5
5
  "module": "src/ccstatusline.ts",
6
6
  "type": "module",