ccstatusline-usage 2.1.1 → 2.1.2

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
@@ -14,44 +14,18 @@
14
14
  **🎨 A highly customizable status line formatter for Claude Code CLI**
15
15
  *Display model info, git branch, token usage, and other metrics in your terminal*
16
16
 
17
- [![npm version](https://img.shields.io/npm/v/ccstatusline-usage.svg)](https://www.npmjs.com/package/ccstatusline-usage)
18
- [![npm downloads](https://img.shields.io/npm/dm/ccstatusline-usage.svg)](https://www.npmjs.com/package/ccstatusline-usage)
17
+ [![npm version](https://img.shields.io/npm/v/ccstatusline.svg)](https://www.npmjs.com/package/ccstatusline)
18
+ [![npm downloads](https://img.shields.io/npm/dm/ccstatusline.svg)](https://www.npmjs.com/package/ccstatusline)
19
19
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/sirmalloc/ccstatusline/blob/main/LICENSE)
20
- [![Node.js Version](https://img.shields.io/node/v/ccstatusline-usage.svg)](https://nodejs.org)
21
- [![install size](https://packagephobia.com/badge?p=ccstatusline-usage)](https://packagephobia.com/result?p=ccstatusline-usage)
20
+ [![Node.js Version](https://img.shields.io/node/v/ccstatusline.svg)](https://nodejs.org)
21
+ [![install size](https://packagephobia.com/badge?p=ccstatusline)](https://packagephobia.com/result?p=ccstatusline)
22
22
  [![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://github.com/sirmalloc/ccstatusline/graphs/commit-activity)
23
23
 
24
24
  [![Mentioned in Awesome Claude Code](https://awesome.re/mentioned-badge.svg)](https://github.com/hesreallyhim/awesome-claude-code)
25
25
  [![ClaudeLog - A comprehensive knowledge base for Claude](https://claudelog.com/img/claude_log_badge.svg)](https://claudelog.com/)
26
26
 
27
- ## Fork Enhancements
28
27
 
29
- This fork adds API-based usage widgets beyond the upstream:
30
-
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`)
33
- - **Reset Timer** - Time until 5-hour session window resets
34
- - **Context Window Display** - Visual bar showing context usage
35
- - **Two-line Layout** - Session info on line 1, context on line 2
36
- - **Narrow Terminal Detection** - Auto-compact rendering on terminals < 80 cols via tmux pane width detection
37
-
38
- ### Enhanced Status Line Preview
39
-
40
- **Desktop (full width):**
41
- ```
42
- Session: [████░░░░░░░░░░░] 27.0% | Weekly: [████████████░░░] 86.0% | 1:56 hr | Extra: $41.24/$47.00 | Model: Opus 4.6 | Session ID: 714aa815-8a...
43
- Context: [███████░░░░░░░░] 103k/200k (51%)
44
- ```
45
-
46
- **Narrow terminal (< 80 cols, e.g. mobile SSH via tmux):**
47
- ```
48
- S: [██░░] 51.0% | W: [████] 92.0% | 0:00 hr
49
- C: [██░░] 100k/200k
50
- ```
51
-
52
- These widgets are enabled by default. Just install and run!
53
-
54
- ![Status Bar Demo](screenshots/status-bar-demo.png)
28
+ ![Demo](https://raw.githubusercontent.com/sirmalloc/ccstatusline/main/screenshots/demo.gif)
55
29
 
56
30
  </div>
57
31
 
@@ -65,7 +39,6 @@ These widgets are enabled by default. Just install and run!
65
39
  - [API Documentation](#-api-documentation)
66
40
  - [Development](#️-development)
67
41
  - [Contributing](#-contributing)
68
- - [Uninstall](#️-uninstall)
69
42
  - [License](#-license)
70
43
  - [Related Projects](#-related-projects)
71
44
 
@@ -73,32 +46,11 @@ These widgets are enabled by default. Just install and run!
73
46
 
74
47
  ## 🆕 Recent Updates
75
48
 
76
- ### [v2.1.1](https://github.com/pcvelz/ccstatusline-usage/releases/tag/v2.1.1) - Automatic mobile/narrow terminal detection
77
-
78
- - **Automatic compact rendering** on terminals < 80 columns via tmux pane width detection:
79
- ```
80
- S: [██░░] 51.0% | W: [████] 92.0% | 0:00 hr
81
- C: [██░░] 100k/200k
82
- ```
83
- - Widgets hidden on narrow terminals: Model, Session Clock, Session ID
84
- - Progress bars shrink from 15 to 4 characters, labels abbreviated (Session → S, Weekly → W, Context → C)
85
- - Orphaned separators automatically removed when adjacent widgets are hidden
86
- - FlexMode `-40` override on narrow terminals (no auto-compact sidebar)
87
- - Works with any tmux-based remote access setup (SSH clients, mobile terminals, etc.)
88
-
89
- ### [v2.0.46](https://github.com/pcvelz/ccstatusline-usage/releases/tag/v2.0.46) - Upstream sync
90
-
91
- - Merged 101 upstream commits: line reorder move mode, Claude Session ID widget, `CLAUDE_CONFIG_DIR` support, Windows fixes, Block Timer fixes, model string/object handling fix, and more
92
-
93
- ### [v2.0.45](https://github.com/pcvelz/ccstatusline-usage/releases/tag/v2.0.45) - Extra usage spending display
94
-
95
- - Extra usage spending display in Reset Timer widget (e.g. `Extra: €41.24/€47.00`)
96
- - Auto-detect currency from timezone (Europe/* = €, else $)
49
+ ### [v2.1.2](https://github.com/pcvelz/ccstatusline-usage/releases/tag/v2.1.2) - Token auth fallback and 401 handling
97
50
 
98
- ### [v2.0.42](https://github.com/pcvelz/ccstatusline-usage/releases/tag/v2.0.42) - Fix reset timer API field
99
-
100
- - Fixed API field name from `reset_at` to `resets_at` — reset timer now displays correctly
101
- - Merged latest changes from upstream ccstatusline
51
+ - [pcvelz/ccstatusline-usage](https://github.com/pcvelz/ccstatusline-usage): macOS file credential fallback reads `~/.claude/.credentials.json` when Keychain entry is missing
52
+ - [pcvelz/ccstatusline-usage](https://github.com/pcvelz/ccstatusline-usage): 401 auth error handling — invalidates cached token so next call re-reads from disk after `/login`
53
+ - Synced with upstream (101 commits)
102
54
 
103
55
  ### v2.0.16 - Add fish style path abbreviation toggle to Current Working Directory widget
104
56
 
@@ -114,7 +66,7 @@ These widgets are enabled by default. Just install and run!
114
66
 
115
67
  - **👾 Emoji Support** - You can now paste emoji into the custom text widget. You can also turn on the merge option to get emoji labels for your widgets like this:
116
68
 
117
- ![Emoji Support](screenshots/emojiSupport.png)
69
+ ![Emoji Support](https://raw.githubusercontent.com/sirmalloc/ccstatusline/main/screenshots/emojiSupport.png)
118
70
 
119
71
  ### v2.0.11 - Unlimited Status Lines
120
72
 
@@ -127,13 +79,13 @@ These widgets are enabled by default. Just install and run!
127
79
 
128
80
  ### v2.0.8 - Powerline Auto-Alignment
129
81
 
130
- ![Powerline Auto-Alignment](screenshots/autoAlign.png)
82
+ ![Powerline Auto-Alignment](https://raw.githubusercontent.com/sirmalloc/ccstatusline/main/screenshots/autoAlign.png)
131
83
 
132
84
  - **🎯 Widget Alignment** - Auto-align widgets across multiple status lines in Powerline mode for a clean, columnar layout (toggle with 'a' in Powerline Setup)
133
85
 
134
86
  ### v2.0.7 - Current Working Directory & Session Cost
135
87
 
136
- ![Current Working Directory and Session Cost](screenshots/cwdAndSessionCost.png)
88
+ ![Current Working Directory and Session Cost](https://raw.githubusercontent.com/sirmalloc/ccstatusline/main/screenshots/cwdAndSessionCost.png)
137
89
 
138
90
  - **📁 Current Working Directory** - Display the current working directory with configurable segment display
139
91
  - Set the number of path segments to show (e.g., show only last 2 segments: `.../Personal/ccstatusline`)
@@ -151,7 +103,7 @@ These widgets are enabled by default. Just install and run!
151
103
 
152
104
  ### v2.0.2 - Block Timer Widget
153
105
 
154
- ![Block Timer](screenshots/blockTimerSmall.png)
106
+ ![Block Timer](https://raw.githubusercontent.com/sirmalloc/ccstatusline/main/screenshots/blockTimerSmall.png)
155
107
 
156
108
  - **⏱️ Block Timer** - Track your progress through 5-hour Claude Code blocks
157
109
  - Displays time elapsed in current block as hours/minutes (e.g., "3hr 45m")
@@ -170,13 +122,9 @@ These widgets are enabled by default. Just install and run!
170
122
 
171
123
  ---
172
124
 
173
- </div>
174
-
175
125
  ## ✨ Features
176
126
 
177
127
  - **📊 Real-time Metrics** - Display model name, git branch, token usage, session duration, block timer, and more
178
- - **📈 API Usage Tracking** - Real-time 5-hour session and weekly utilization from Anthropic API with progress bars
179
- - **⏱️ Reset Timer** - Countdown to when your 5-hour session window resets
180
128
  - **🎨 Fully Customizable** - Choose what to display and customize colors for each element
181
129
  - **⚡ Powerline Support** - Beautiful Powerline-style rendering with arrow separators, caps, and custom fonts
182
130
  - **📐 Multi-line Support** - Configure multiple independent status lines
@@ -184,7 +132,6 @@ These widgets are enabled by default. Just install and run!
184
132
  - **⚙️ Global Options** - Apply consistent formatting across all widgets (padding, separators, bold, background)
185
133
  - **🚀 Cross-platform** - Works seamlessly with both Bun and Node.js
186
134
  - **🔧 Flexible Configuration** - Supports custom Claude Code config directory via `CLAUDE_CONFIG_DIR` environment variable
187
- - **📱 Narrow Terminal Detection** - Auto-compact rendering on terminals < 80 columns via tmux pane width detection
188
135
  - **📏 Smart Width Detection** - Automatically adapts to terminal width with flex separators
189
136
  - **⚡ Zero Config** - Sensible defaults that work out of the box
190
137
 
@@ -196,10 +143,10 @@ These widgets are enabled by default. Just install and run!
196
143
 
197
144
  ```bash
198
145
  # Run the configuration TUI with npm
199
- npx ccstatusline-usage@latest
146
+ npx ccstatusline@latest
200
147
 
201
148
  # Or with Bun (faster)
202
- bunx ccstatusline-usage@latest
149
+ bunx ccstatusline@latest
203
150
  ```
204
151
 
205
152
  ### Configure ccstatusline
@@ -238,19 +185,19 @@ ccstatusline works seamlessly on Windows with full feature compatibility across
238
185
  irm bun.sh/install.ps1 | iex
239
186
 
240
187
  # Run ccstatusline
241
- bunx ccstatusline-usage@latest
188
+ bunx ccstatusline@latest
242
189
  ```
243
190
 
244
191
  #### Option 2: Using Node.js
245
192
  ```powershell
246
193
  # Using npm
247
- npx ccstatusline-usage@latest
194
+ npx ccstatusline@latest
248
195
 
249
196
  # Or with Yarn
250
- yarn dlx ccstatusline-usage@latest
197
+ yarn dlx ccstatusline@latest
251
198
 
252
199
  # Or with pnpm
253
- pnpm dlx ccstatusline-usage@latest
200
+ pnpm dlx ccstatusline@latest
254
201
  ```
255
202
 
256
203
  ### Windows-Specific Features
@@ -305,7 +252,7 @@ winget install Git.Git
305
252
  **Issue**: Permission errors during installation
306
253
  ```powershell
307
254
  # Use non-global installation (recommended)
308
- npx ccstatusline-usage@latest
255
+ npx ccstatusline@latest
309
256
 
310
257
  # Or run PowerShell as Administrator for global install
311
258
  ```
@@ -333,7 +280,7 @@ ccstatusline works perfectly in WSL environments:
333
280
  # Install in WSL Ubuntu/Debian
334
281
  curl -fsSL https://bun.sh/install | bash
335
282
  source ~/.bashrc
336
- bunx ccstatusline-usage@latest
283
+ bunx ccstatusline@latest
337
284
  ```
338
285
 
339
286
  **WSL Benefits**:
@@ -370,14 +317,14 @@ Configure ccstatusline in your Claude Code settings:
370
317
  **For Bun users**:
371
318
  ```json
372
319
  {
373
- "statusLine": "bunx ccstatusline-usage@latest"
320
+ "statusLine": "bunx ccstatusline@latest"
374
321
  }
375
322
  ```
376
323
 
377
324
  **For npm users**:
378
325
  ```json
379
326
  {
380
- "statusLine": "npx ccstatusline-usage@latest"
327
+ "statusLine": "npx ccstatusline@latest"
381
328
  }
382
329
  ```
383
330
 
@@ -408,15 +355,7 @@ Once configured, ccstatusline automatically formats your Claude Code status line
408
355
 
409
356
  ### 📊 Available Widgets
410
357
 
411
- #### API Usage Widgets ([pcvelz/ccstatusline-usage](https://github.com/pcvelz/ccstatusline-usage))
412
- - **Session Usage** - 5-hour session utilization with progress bar (e.g., "Session: [████░░░░░░░░░░░] 29.0%")
413
- - **Weekly Usage** - 7-day utilization with progress bar (e.g., "Weekly: [█░░░░░░░░░░░░░░] 7.0%")
414
- - **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")
415
- - **Context Bar** - Visual context window usage with bar (e.g., "Context: [███████░░░░░░░░] 103k/200k (51%)")
416
-
417
- #### Standard Widgets
418
358
  - **Model Name** - Shows the current Claude model (e.g., "Claude 3.5 Sonnet")
419
- - **Claude Session ID** - Shows the current session UUID
420
359
  - **Git Branch** - Displays current git branch name
421
360
  - **Git Changes** - Shows uncommitted insertions/deletions (e.g., "+42,-10")
422
361
  - **Git Worktree** - Shows the name of the current git worktree
@@ -546,7 +485,7 @@ Execute shell commands and display their output dynamically:
546
485
  3. Set timeout: `5000` (5 seconds for initial download)
547
486
  4. Enable "preserve colors" to keep ccusage's color formatting
548
487
 
549
- ![ccusage integration](screenshots/ccusage.png)
488
+ ![ccusage integration](https://raw.githubusercontent.com/sirmalloc/ccstatusline/main/screenshots/ccusage.png)
550
489
 
551
490
  > 📄 **How it works:** The command receives Claude Code's JSON data via stdin, allowing ccusage to access session information, model details, and transcript data for accurate usage tracking.
552
491
 
@@ -667,17 +606,6 @@ Contributions are welcome! Please feel free to submit a Pull Request.
667
606
 
668
607
  ---
669
608
 
670
- ## 🗑️ Uninstall
671
-
672
- ```bash
673
- npm uninstall -g ccstatusline-usage
674
- rm -rf ~/.npm/_npx ~/.config/ccstatusline ~/.cache/ccstatusline*
675
- jq 'del(.statusLine)' ~/.claude/settings.json > /tmp/cs.json && cat /tmp/cs.json > ~/.claude/settings.json
676
- ```
677
-
678
- ---
679
-
680
-
681
609
  ## 📄 License
682
610
 
683
611
  [MIT](LICENSE) © Matthew Breedlove
@@ -690,11 +618,6 @@ jq 'del(.statusLine)' ~/.claude/settings.json > /tmp/cs.json && cat /tmp/cs.json
690
618
 
691
619
  - GitHub: [@sirmalloc](https://github.com/sirmalloc)
692
620
 
693
- **PC van Velzen** ([pcvelz/ccstatusline-usage](https://github.com/pcvelz/ccstatusline-usage) fork)
694
-
695
- - GitHub: [@pcvelz](https://github.com/pcvelz)
696
-
697
-
698
621
  ---
699
622
 
700
623
  ## 🔗 Related Projects
@@ -732,8 +655,8 @@ Give a ⭐ if this project helped you!
732
655
  [![GitHub forks](https://img.shields.io/github/forks/sirmalloc/ccstatusline?style=social)](https://github.com/sirmalloc/ccstatusline/network/members)
733
656
  [![GitHub watchers](https://img.shields.io/github/watchers/sirmalloc/ccstatusline?style=social)](https://github.com/sirmalloc/ccstatusline/watchers)
734
657
 
735
- [![npm version](https://img.shields.io/npm/v/ccstatusline-usage.svg)](https://www.npmjs.com/package/ccstatusline-usage)
736
- [![npm downloads](https://img.shields.io/npm/dm/ccstatusline-usage.svg)](https://www.npmjs.com/package/ccstatusline-usage)
658
+ [![npm version](https://img.shields.io/npm/v/ccstatusline.svg)](https://www.npmjs.com/package/ccstatusline)
659
+ [![npm downloads](https://img.shields.io/npm/dm/ccstatusline.svg)](https://www.npmjs.com/package/ccstatusline)
737
660
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/sirmalloc/ccstatusline/blob/main/LICENSE)
738
661
  [![Made with Bun](https://img.shields.io/badge/Made%20with-Bun-000000.svg?logo=bun)](https://bun.sh)
739
662
 
@@ -51450,8 +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 MOBILE_THRESHOLD = 80;
51454
- var PACKAGE_VERSION = "2.1.1";
51453
+ var PACKAGE_VERSION = "2.1.2";
51455
51454
  function getPackageVersion() {
51456
51455
  if (/^\d+\.\d+\.\d+/.test(PACKAGE_VERSION)) {
51457
51456
  return PACKAGE_VERSION;
@@ -51531,60 +51530,6 @@ function canDetectTerminalWidth() {
51531
51530
  return false;
51532
51531
  }
51533
51532
  }
51534
- function parseTmuxClients() {
51535
- try {
51536
- const output = execSync3("tmux list-clients -F '#{client_width} #{client_height} #{client_tty}'", { encoding: "utf8", stdio: ["pipe", "pipe", "ignore"], timeout: 2000 }).trim();
51537
- if (!output)
51538
- return [];
51539
- const clients = [];
51540
- for (const line of output.split(`
51541
- `)) {
51542
- const parts = line.trim().split(" ");
51543
- if (parts.length >= 3) {
51544
- const width = parseInt(parts[0] ?? "", 10);
51545
- const height = parseInt(parts[1] ?? "", 10);
51546
- const tty2 = parts.slice(2).join(" ");
51547
- if (!isNaN(width) && !isNaN(height) && tty2) {
51548
- clients.push({ width, height, tty: tty2 });
51549
- }
51550
- }
51551
- }
51552
- return clients;
51553
- } catch {
51554
- return [];
51555
- }
51556
- }
51557
- function getTmuxPaneWidth() {
51558
- try {
51559
- const output = execSync3("tmux display-message -p '#{pane_width}'", { encoding: "utf8", stdio: ["pipe", "pipe", "ignore"], timeout: 2000 }).trim();
51560
- const parsed = parseInt(output, 10);
51561
- if (!isNaN(parsed) && parsed > 0)
51562
- return parsed;
51563
- } catch {}
51564
- return null;
51565
- }
51566
- function detectTerminalEnvironment() {
51567
- const inTmux = Boolean(process.env.TMUX);
51568
- let terminalWidth = getTerminalWidth();
51569
- let smallestClientWidth = null;
51570
- let tmuxClients = [];
51571
- if (inTmux) {
51572
- const paneWidth = getTmuxPaneWidth();
51573
- if (paneWidth !== null)
51574
- terminalWidth = paneWidth;
51575
- tmuxClients = parseTmuxClients();
51576
- if (tmuxClients.length > 0)
51577
- smallestClientWidth = Math.min(...tmuxClients.map((c) => c.width));
51578
- }
51579
- const isMobile = terminalWidth !== null && terminalWidth < MOBILE_THRESHOLD;
51580
- return {
51581
- inTmux,
51582
- tmuxClients,
51583
- terminalWidth,
51584
- isMobile,
51585
- smallestClientWidth
51586
- };
51587
- }
51588
51533
 
51589
51534
  // node_modules/ink-select-input/build/Indicator.js
51590
51535
  var import_react27 = __toESM(require_react(), 1);
@@ -52352,8 +52297,6 @@ class ModelWidget {
52352
52297
  if (context.isPreview) {
52353
52298
  return item.rawValue ? "Claude" : "Model: Claude";
52354
52299
  }
52355
- if (context.terminalEnv?.isMobile)
52356
- return null;
52357
52300
  const model = context.data?.model;
52358
52301
  const modelDisplayName = typeof model === "string" ? model : model?.display_name ?? model?.id;
52359
52302
  if (modelDisplayName) {
@@ -52701,8 +52644,6 @@ function renderPowerlineStatusLine(widgets, settings, context, lineIndex = 0, gl
52701
52644
  } else if (flexMode === "full-until-compact") {
52702
52645
  terminalWidth = detectedWidth - 6;
52703
52646
  }
52704
- } else if (context.terminalEnv?.isMobile) {
52705
- terminalWidth = detectedWidth - 6;
52706
52647
  } else {
52707
52648
  if (flexMode === "full") {
52708
52649
  terminalWidth = detectedWidth - 6;
@@ -53077,8 +53018,6 @@ function renderStatusLine(widgets, settings, context, preRenderedWidgets, preCal
53077
53018
  } else if (flexMode === "full-until-compact") {
53078
53019
  terminalWidth = detectedWidth - 6;
53079
53020
  }
53080
- } else if (context.terminalEnv?.isMobile) {
53081
- terminalWidth = detectedWidth - 6;
53082
53021
  } else {
53083
53022
  if (flexMode === "full") {
53084
53023
  terminalWidth = detectedWidth - 6;
@@ -53114,18 +53053,6 @@ function renderStatusLine(widgets, settings, context, preRenderedWidgets, preCal
53114
53053
  }
53115
53054
  if (!hasContentBefore)
53116
53055
  continue;
53117
- let hasContentAfter = false;
53118
- for (let j = i + 1;j < widgets.length; j++) {
53119
- const nextWidget = widgets[j];
53120
- if (nextWidget && nextWidget.type !== "separator" && nextWidget.type !== "flex-separator") {
53121
- if (preRenderedWidgets[j]?.content) {
53122
- hasContentAfter = true;
53123
- break;
53124
- }
53125
- }
53126
- }
53127
- if (!hasContentAfter)
53128
- continue;
53129
53056
  const sepChar = widget.character ?? (settings.defaultSeparator ?? "|");
53130
53057
  const formattedSep = formatSeparator(sepChar);
53131
53058
  let separatorColor = widget.color ?? "gray";
@@ -53529,18 +53456,6 @@ class ContextPercentageWidget {
53529
53456
  const usedPercentage = Math.min(100, context.tokenMetrics.contextLength / contextConfig.maxTokens * 100);
53530
53457
  const displayPercentage = isInverse ? 100 - usedPercentage : usedPercentage;
53531
53458
  return item.rawValue ? `${displayPercentage.toFixed(1)}%` : `Ctx: ${displayPercentage.toFixed(1)}%`;
53532
- } else if (context.data?.context_window) {
53533
- const ctxWindow = context.data.context_window;
53534
- let usedPercentage = null;
53535
- if (typeof ctxWindow.used_percentage === "number") {
53536
- usedPercentage = ctxWindow.used_percentage;
53537
- } else if (typeof ctxWindow.current_usage === "number" && ctxWindow.context_window_size) {
53538
- usedPercentage = Math.min(100, ctxWindow.current_usage / ctxWindow.context_window_size * 100);
53539
- }
53540
- if (usedPercentage !== null) {
53541
- const displayPercentage = isInverse ? 100 - usedPercentage : usedPercentage;
53542
- return item.rawValue ? `${displayPercentage.toFixed(1)}%` : `Ctx: ${displayPercentage.toFixed(1)}%`;
53543
- }
53544
53459
  }
53545
53460
  return null;
53546
53461
  }
@@ -53636,8 +53551,6 @@ class SessionClockWidget {
53636
53551
  if (context.isPreview) {
53637
53552
  return item.rawValue ? "2hr 15m" : "Session: 2hr 15m";
53638
53553
  }
53639
- if (context.terminalEnv?.isMobile)
53640
- return null;
53641
53554
  const duration3 = context.sessionDuration ?? "0m";
53642
53555
  return item.rawValue ? duration3 : `Session: ${duration3}`;
53643
53556
  }
@@ -54463,13 +54376,13 @@ class ClaudeSessionIdWidget {
54463
54376
  render(item, context, settings) {
54464
54377
  if (context.isPreview) {
54465
54378
  return item.rawValue ? "preview-session-id" : "Session ID: preview-session-id";
54379
+ } else {
54380
+ const sessionId = context.data?.session_id;
54381
+ if (!sessionId) {
54382
+ return null;
54383
+ }
54384
+ return item.rawValue ? sessionId : `Session ID: ${sessionId}`;
54466
54385
  }
54467
- if (context.terminalEnv?.isMobile)
54468
- return null;
54469
- const sessionId = context.data?.session_id;
54470
- if (!sessionId)
54471
- return null;
54472
- return item.rawValue ? sessionId : `Session ID: ${sessionId}`;
54473
54386
  }
54474
54387
  supportsRawValue() {
54475
54388
  return true;
@@ -54494,35 +54407,43 @@ var cachedData = null;
54494
54407
  var cacheTime = 0;
54495
54408
  var cachedToken = null;
54496
54409
  var tokenCacheTime = 0;
54410
+ var CRED_FILE = path5.join(process.env.HOME ?? "", ".claude", ".credentials.json");
54411
+ function readTokenFromFile() {
54412
+ try {
54413
+ const creds = JSON.parse(fs6.readFileSync(CRED_FILE, "utf8"));
54414
+ return creds?.claudeAiOauth?.accessToken ?? null;
54415
+ } catch {
54416
+ return null;
54417
+ }
54418
+ }
54419
+ function readTokenFromKeychain() {
54420
+ try {
54421
+ const result = execSync8('security find-generic-password -s "Claude Code-credentials" -w 2>/dev/null', { encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] }).trim();
54422
+ const parsed = JSON.parse(result);
54423
+ return parsed?.claudeAiOauth?.accessToken ?? null;
54424
+ } catch {
54425
+ return null;
54426
+ }
54427
+ }
54428
+ function invalidateTokenCache() {
54429
+ cachedToken = null;
54430
+ tokenCacheTime = 0;
54431
+ }
54497
54432
  function getToken() {
54498
54433
  const now = Math.floor(Date.now() / 1000);
54499
54434
  if (cachedToken && now - tokenCacheTime < TOKEN_CACHE_MAX_AGE) {
54500
54435
  return cachedToken;
54501
54436
  }
54502
- try {
54503
- const isMac = process.platform === "darwin";
54504
- if (isMac) {
54505
- const result = execSync8('security find-generic-password -s "Claude Code-credentials" -w 2>/dev/null', { encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] }).trim();
54506
- const parsed = JSON.parse(result);
54507
- const token = parsed?.claudeAiOauth?.accessToken ?? null;
54508
- if (token) {
54509
- cachedToken = token;
54510
- tokenCacheTime = now;
54511
- }
54512
- return token;
54513
- } else {
54514
- const credFile = path5.join(process.env.HOME ?? "", ".claude", ".credentials.json");
54515
- const creds = JSON.parse(fs6.readFileSync(credFile, "utf8"));
54516
- const token = creds?.claudeAiOauth?.accessToken ?? null;
54517
- if (token) {
54518
- cachedToken = token;
54519
- tokenCacheTime = now;
54520
- }
54521
- return token;
54522
- }
54523
- } catch {
54524
- return null;
54437
+ let token = null;
54438
+ if (process.platform === "darwin")
54439
+ token = readTokenFromKeychain();
54440
+ if (!token)
54441
+ token = readTokenFromFile();
54442
+ if (token) {
54443
+ cachedToken = token;
54444
+ tokenCacheTime = now;
54525
54445
  }
54446
+ return token;
54526
54447
  }
54527
54448
  function readStaleCache() {
54528
54449
  try {
@@ -54550,6 +54471,8 @@ function fetchFromApi(token) {
54550
54471
  res.on('end', () => {
54551
54472
  if (res.statusCode === 200) {
54552
54473
  process.stdout.write(data);
54474
+ } else if (res.statusCode === 401) {
54475
+ process.exit(2);
54553
54476
  } else {
54554
54477
  process.exit(1);
54555
54478
  }
@@ -54564,7 +54487,14 @@ function fetchFromApi(token) {
54564
54487
  timeout: 6000,
54565
54488
  env: { ...process.env, TOKEN: token }
54566
54489
  });
54567
- if (result.error || result.status !== 0 || !result.stdout) {
54490
+ if (result.error || !result.stdout) {
54491
+ if (result.status === 2)
54492
+ return "auth-error";
54493
+ return null;
54494
+ }
54495
+ if (result.status !== 0) {
54496
+ if (result.status === 2)
54497
+ return "auth-error";
54568
54498
  return null;
54569
54499
  }
54570
54500
  return result.stdout;
@@ -54612,6 +54542,13 @@ function fetchApiData() {
54612
54542
  }
54613
54543
  try {
54614
54544
  const response = fetchFromApi(token);
54545
+ if (response === "auth-error") {
54546
+ invalidateTokenCache();
54547
+ const stale = readStaleCache();
54548
+ if (stale && !stale.error)
54549
+ return stale;
54550
+ return { error: "api-error" };
54551
+ }
54615
54552
  if (!response) {
54616
54553
  const stale = readStaleCache();
54617
54554
  if (stale && !stale.error)
@@ -54668,8 +54605,12 @@ function getErrorMessage(error43) {
54668
54605
  return "[Parse Error]";
54669
54606
  }
54670
54607
  }
54608
+ var MOBILE_THRESHOLD = 80;
54671
54609
  var MOBILE_BAR_WIDTH = 4;
54672
54610
  var DEFAULT_BAR_WIDTH = 15;
54611
+ function isMobileWidth(context) {
54612
+ return (context.terminalWidth ?? 0) > 0 && (context.terminalWidth ?? 0) < MOBILE_THRESHOLD;
54613
+ }
54673
54614
  function makeProgressBar(percent, width = DEFAULT_BAR_WIDTH) {
54674
54615
  const filled = Math.round(percent / 100 * width);
54675
54616
  const empty = width - filled;
@@ -54701,7 +54642,7 @@ class SessionUsageWidget {
54701
54642
  return getErrorMessage(data.error);
54702
54643
  if (data.sessionUsage === undefined)
54703
54644
  return null;
54704
- return formatUsageBar("Session", "S", data.sessionUsage, Boolean(context.terminalEnv?.isMobile));
54645
+ return formatUsageBar("Session", "S", data.sessionUsage, isMobileWidth(context));
54705
54646
  }
54706
54647
  supportsRawValue() {
54707
54648
  return false;
@@ -54732,7 +54673,7 @@ class WeeklyUsageWidget {
54732
54673
  return getErrorMessage(data.error);
54733
54674
  if (data.weeklyUsage === undefined)
54734
54675
  return null;
54735
- return formatUsageBar("Weekly", "W", data.weeklyUsage, Boolean(context.terminalEnv?.isMobile));
54676
+ return formatUsageBar("Weekly", "W", data.weeklyUsage, isMobileWidth(context));
54736
54677
  }
54737
54678
  supportsRawValue() {
54738
54679
  return false;
@@ -54833,7 +54774,7 @@ class ContextBarWidget {
54833
54774
  const percent = total > 0 ? used / total * 100 : 0;
54834
54775
  const usedK = Math.round(used / 1000);
54835
54776
  const totalK = Math.round(total / 1000);
54836
- const mobile = Boolean(context.terminalEnv?.isMobile);
54777
+ const mobile = isMobileWidth(context);
54837
54778
  const bar = makeProgressBar(percent, mobile ? MOBILE_BAR_WIDTH : DEFAULT_BAR_WIDTH);
54838
54779
  const label = mobile ? "C" : "Context";
54839
54780
  const suffix = mobile ? "" : ` (${Math.round(percent)}%)`;
@@ -58506,7 +58447,7 @@ Continue?`;
58506
58447
  bold: true,
58507
58448
  children: /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(dist_default4, {
58508
58449
  name: "retro",
58509
- children: "CCStatusline Usage"
58450
+ children: "CCStatusline Configuration"
58510
58451
  }, undefined, false, undefined, this)
58511
58452
  }, undefined, false, undefined, this),
58512
58453
  /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
@@ -59812,15 +59753,12 @@ async function renderMultipleLines(data) {
59812
59753
  if (hasBlockTimer) {
59813
59754
  blockMetrics = getBlockMetrics();
59814
59755
  }
59815
- const terminalEnv = detectTerminalEnvironment();
59816
59756
  const context = {
59817
59757
  data,
59818
59758
  tokenMetrics,
59819
59759
  sessionDuration,
59820
59760
  blockMetrics,
59821
- terminalWidth: terminalEnv.terminalWidth,
59822
- isPreview: false,
59823
- terminalEnv
59761
+ isPreview: false
59824
59762
  };
59825
59763
  const preRenderedLines = preRenderAllWidgets(lines, settings, context);
59826
59764
  const preCalculatedMaxWidths = calculateMaxWidthsFromPreRendered(preRenderedLines, settings);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccstatusline-usage",
3
- "version": "2.1.1",
3
+ "version": "2.1.2",
4
4
  "description": "A customizable status line formatter for Claude Code CLI",
5
5
  "module": "src/ccstatusline.ts",
6
6
  "type": "module",
@@ -18,6 +18,7 @@
18
18
  "prepublishOnly": "bun run build",
19
19
  "lint": "bun tsc --noEmit; eslint . --config eslint.config.js --max-warnings=999999 --fix",
20
20
  "test": "bun vitest",
21
+ "publish:safe": "bash scripts/safe-publish.sh",
21
22
  "docs": "typedoc",
22
23
  "docs:clean": "rm -rf docs"
23
24
  },