ccstatusline 2.0.13 → 2.0.15

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
@@ -34,7 +34,9 @@
34
34
  - [Recent Updates](#-recent-updates)
35
35
  - [Features](#-features)
36
36
  - [Quick Start](#-quick-start)
37
+ - [Windows Support](#-windows-support)
37
38
  - [Usage](#-usage)
39
+ - [API Documentation](#-api-documentation)
38
40
  - [Development](#️-development)
39
41
  - [Contributing](#-contributing)
40
42
  - [License](#-license)
@@ -44,6 +46,14 @@
44
46
 
45
47
  ## 🆕 Recent Updates
46
48
 
49
+ ### v2.0.15 - Block Timer calculation fixes
50
+
51
+ - Fix miscalculation in the block timer
52
+
53
+ ### v2.0.14 - Add remaining mode toggle to Context Percentage widgets
54
+
55
+ - **Remaining Mode** - You can now toggle the Context Percentage widgets between usage percentage and remaining percentage when configuring them in the TUI by pressing the 'l' key.
56
+
47
57
  ### v2.0.12 - Custom Text widget now supports emojis
48
58
 
49
59
  - **👾 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:
@@ -145,6 +155,176 @@ The interactive configuration tool provides a terminal UI where you can:
145
155
 
146
156
  ---
147
157
 
158
+ ## 🪟 Windows Support
159
+
160
+ ccstatusline works seamlessly on Windows with full feature compatibility across PowerShell (5.1+ and 7+), Command Prompt, and Windows Subsystem for Linux (WSL).
161
+
162
+ ### Installation on Windows
163
+
164
+ #### Option 1: Using Bun (Recommended)
165
+ ```powershell
166
+ # Install Bun for Windows
167
+ irm bun.sh/install.ps1 | iex
168
+
169
+ # Run ccstatusline
170
+ bunx ccstatusline@latest
171
+ ```
172
+
173
+ #### Option 2: Using Node.js
174
+ ```powershell
175
+ # Using npm
176
+ npx ccstatusline@latest
177
+
178
+ # Or with Yarn
179
+ yarn dlx ccstatusline@latest
180
+
181
+ # Or with pnpm
182
+ pnpm dlx ccstatusline@latest
183
+ ```
184
+
185
+ ### Windows-Specific Features
186
+
187
+ #### Powerline Font Support
188
+ For optimal Powerline rendering on Windows:
189
+
190
+ **Windows Terminal** (Recommended):
191
+ - Supports Powerline fonts natively
192
+ - Download from [Microsoft Store](https://aka.ms/terminal)
193
+ - Auto-detects compatible fonts
194
+
195
+ **PowerShell/Command Prompt**:
196
+ ```powershell
197
+ # Install JetBrains Mono Nerd Font via winget
198
+ winget install DEVCOM.JetBrainsMonoNerdFont
199
+
200
+ # Alternative: Install base JetBrains Mono font
201
+ winget install "JetBrains.JetBrainsMono"
202
+
203
+ # Or download manually from: https://www.nerdfonts.com/font-downloads
204
+ ```
205
+
206
+ #### Path Handling
207
+ ccstatusline automatically handles Windows-specific paths:
208
+ - Git repositories work with both `/` and `\` path separators
209
+ - Current Working Directory widget displays Windows-style paths correctly
210
+ - Full support for mapped network drives and UNC paths
211
+ - Handles Windows drive letters (C:, D:, etc.)
212
+
213
+ ### Windows Troubleshooting
214
+
215
+ #### Common Issues & Solutions
216
+
217
+ **Issue**: Powerline symbols showing as question marks or boxes
218
+ ```powershell
219
+ # Solution: Install a compatible Nerd Font
220
+ winget install JetBrainsMono.NerdFont
221
+ # Then set the font in your terminal settings
222
+ ```
223
+
224
+ **Issue**: Git commands not recognized
225
+ ```powershell
226
+ # Check if Git is installed and in PATH
227
+ git --version
228
+
229
+ # If not found, install Git:
230
+ winget install Git.Git
231
+ # Or download from: https://git-scm.com/download/win
232
+ ```
233
+
234
+ **Issue**: Permission errors during installation
235
+ ```powershell
236
+ # Use non-global installation (recommended)
237
+ npx ccstatusline@latest
238
+
239
+ # Or run PowerShell as Administrator for global install
240
+ ```
241
+
242
+ **Issue**: "Execution Policy" errors in PowerShell
243
+ ```powershell
244
+ # Temporarily allow script execution
245
+ Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
246
+ ```
247
+
248
+ **Issue**: Windows Defender blocking execution
249
+ ```powershell
250
+ # If Windows Defender flags the binary:
251
+ # 1. Open Windows Security
252
+ # 2. Go to "Virus & threat protection"
253
+ # 3. Add exclusion for the ccstatusline binary location
254
+ # Or use temporary bypass (not recommended for production):
255
+ Add-MpPreference -ExclusionPath "$env:USERPROFILE\.bun\bin"
256
+ ```
257
+
258
+ #### Windows Subsystem for Linux (WSL)
259
+ ccstatusline works perfectly in WSL environments:
260
+
261
+ ```bash
262
+ # Install in WSL Ubuntu/Debian
263
+ curl -fsSL https://bun.sh/install | bash
264
+ source ~/.bashrc
265
+ bunx ccstatusline@latest
266
+ ```
267
+
268
+ **WSL Benefits**:
269
+ - Native Unix-style path handling
270
+ - Better font rendering in WSL terminals
271
+ - Seamless integration with Linux development workflows
272
+
273
+ ### Windows Terminal Configuration
274
+
275
+ For the best experience, configure Windows Terminal with these recommended settings:
276
+
277
+ #### Terminal Settings (settings.json)
278
+ ```json
279
+ {
280
+ "profiles": {
281
+ "defaults": {
282
+ "font": {
283
+ "face": "JetBrainsMono Nerd Font",
284
+ "size": 12
285
+ },
286
+ "colorScheme": "One Half Dark"
287
+ }
288
+ }
289
+ }
290
+ ```
291
+
292
+ #### Claude Code Integration
293
+ Configure ccstatusline in your Claude Code settings:
294
+
295
+ **For Bun users** (Windows: `%USERPROFILE%\.claude\settings.json`):
296
+ ```json
297
+ {
298
+ "statusLine": "bunx ccstatusline@latest"
299
+ }
300
+ ```
301
+
302
+ **For npm users**:
303
+ ```json
304
+ {
305
+ "statusLine": "npx ccstatusline@latest"
306
+ }
307
+ ```
308
+
309
+ ### Performance on Windows
310
+
311
+ ccstatusline is optimized for Windows performance:
312
+ - **Bun runtime**: Significantly faster startup times on Windows
313
+ - **Caching**: Intelligent caching of git status and file operations
314
+ - **Async operations**: Non-blocking command execution
315
+ - **Memory efficient**: Minimal resource usage
316
+
317
+ ### Windows-Specific Widget Behavior
318
+
319
+ Some widgets have Windows-specific optimizations:
320
+
321
+ - **Current Working Directory**: Displays Windows drive letters and UNC paths
322
+ - **Git Widgets**: Handle Windows line endings (CRLF) automatically
323
+ - **Custom Commands**: Support both PowerShell and cmd.exe commands
324
+ - **Block Timer**: Accounts for Windows timezone handling
325
+
326
+ ---
327
+
148
328
  ## 📖 Usage
149
329
 
150
330
  Once configured, ccstatusline automatically formats your Claude Code status line. The status line appears at the bottom of your terminal during Claude Code sessions.
@@ -291,6 +471,38 @@ When terminal width is detected, status lines automatically truncate with ellips
291
471
 
292
472
  ---
293
473
 
474
+ ## 📖 API Documentation
475
+
476
+ Complete API documentation is generated using TypeDoc and includes detailed information about:
477
+
478
+ - **Core Types**: Configuration interfaces, widget definitions, and render contexts
479
+ - **Widget System**: All available widgets and their customization options
480
+ - **Utility Functions**: Helper functions for rendering, configuration, and terminal handling
481
+ - **Status Line Rendering**: Core rendering engine and formatting options
482
+
483
+ ### Generating Documentation
484
+
485
+ To generate the API documentation locally:
486
+
487
+ ```bash
488
+ # Generate documentation
489
+ bun run docs
490
+
491
+ # Clean generated documentation
492
+ bun run docs:clean
493
+ ```
494
+
495
+ The documentation will be generated in the `docs/` directory and can be viewed by opening `docs/index.html` in your web browser.
496
+
497
+ ### Documentation Structure
498
+
499
+ - **Types**: Core TypeScript interfaces and type definitions
500
+ - **Widgets**: Individual widget implementations and their APIs
501
+ - **Utils**: Utility functions for configuration, rendering, and terminal operations
502
+ - **Main Module**: Primary entry point and orchestration functions
503
+
504
+ ---
505
+
294
506
  ## 🛠️ Development
295
507
 
296
508
  ### Prerequisites
@@ -51374,7 +51374,7 @@ import { execSync as execSync3 } from "child_process";
51374
51374
  import * as fs5 from "fs";
51375
51375
  import * as path4 from "path";
51376
51376
  var __dirname = "/Users/sirmalloc/Projects/Personal/ccstatusline/src/utils";
51377
- var PACKAGE_VERSION = "2.0.13";
51377
+ var PACKAGE_VERSION = "2.0.15";
51378
51378
  function getPackageVersion() {
51379
51379
  if (/^\d+\.\d+\.\d+/.test(PACKAGE_VERSION)) {
51380
51380
  return PACKAGE_VERSION;
@@ -53308,23 +53308,52 @@ class ContextPercentageWidget {
53308
53308
  return "blue";
53309
53309
  }
53310
53310
  getDescription() {
53311
- return "Shows percentage of context window used (of 200k tokens)";
53311
+ return "Shows percentage of context window used or remaining (of 200k tokens)";
53312
53312
  }
53313
53313
  getDisplayName() {
53314
53314
  return "Context %";
53315
53315
  }
53316
53316
  getEditorDisplay(item) {
53317
- return { displayText: this.getDisplayName() };
53317
+ const isInverse = item.metadata?.inverse === "true";
53318
+ const modifiers = [];
53319
+ if (isInverse) {
53320
+ modifiers.push("remaining");
53321
+ }
53322
+ return {
53323
+ displayText: this.getDisplayName(),
53324
+ modifierText: modifiers.length > 0 ? `(${modifiers.join(", ")})` : undefined
53325
+ };
53326
+ }
53327
+ handleEditorAction(action, item) {
53328
+ if (action === "toggle-inverse") {
53329
+ const currentState = item.metadata?.inverse === "true";
53330
+ return {
53331
+ ...item,
53332
+ metadata: {
53333
+ ...item.metadata,
53334
+ inverse: (!currentState).toString()
53335
+ }
53336
+ };
53337
+ }
53338
+ return null;
53318
53339
  }
53319
53340
  render(item, context, settings) {
53341
+ const isInverse = item.metadata?.inverse === "true";
53320
53342
  if (context.isPreview) {
53321
- return item.rawValue ? "9.3%" : "Ctx: 9.3%";
53343
+ const previewValue = isInverse ? "90.7%" : "9.3%";
53344
+ return item.rawValue ? previewValue : `Ctx: ${previewValue}`;
53322
53345
  } else if (context.tokenMetrics) {
53323
- const percentage = Math.min(100, context.tokenMetrics.contextLength / 200000 * 100);
53324
- return item.rawValue ? `${percentage.toFixed(1)}%` : `Ctx: ${percentage.toFixed(1)}%`;
53346
+ const usedPercentage = Math.min(100, context.tokenMetrics.contextLength / 200000 * 100);
53347
+ const displayPercentage = isInverse ? 100 - usedPercentage : usedPercentage;
53348
+ return item.rawValue ? `${displayPercentage.toFixed(1)}%` : `Ctx: ${displayPercentage.toFixed(1)}%`;
53325
53349
  }
53326
53350
  return null;
53327
53351
  }
53352
+ getCustomKeybinds() {
53353
+ return [
53354
+ { key: "l", label: "(l)eft/remaining", action: "toggle-inverse" }
53355
+ ];
53356
+ }
53328
53357
  supportsRawValue() {
53329
53358
  return true;
53330
53359
  }
@@ -53338,23 +53367,52 @@ class ContextPercentageUsableWidget {
53338
53367
  return "green";
53339
53368
  }
53340
53369
  getDescription() {
53341
- return "Shows percentage of usable context window used (of 160k tokens before auto-compact)";
53370
+ return "Shows percentage of usable context window used or remaining (of 160k tokens before auto-compact)";
53342
53371
  }
53343
53372
  getDisplayName() {
53344
53373
  return "Context % (usable)";
53345
53374
  }
53346
53375
  getEditorDisplay(item) {
53347
- return { displayText: this.getDisplayName() };
53376
+ const isInverse = item.metadata?.inverse === "true";
53377
+ const modifiers = [];
53378
+ if (isInverse) {
53379
+ modifiers.push("remaining");
53380
+ }
53381
+ return {
53382
+ displayText: this.getDisplayName(),
53383
+ modifierText: modifiers.length > 0 ? `(${modifiers.join(", ")})` : undefined
53384
+ };
53385
+ }
53386
+ handleEditorAction(action, item) {
53387
+ if (action === "toggle-inverse") {
53388
+ const currentState = item.metadata?.inverse === "true";
53389
+ return {
53390
+ ...item,
53391
+ metadata: {
53392
+ ...item.metadata,
53393
+ inverse: (!currentState).toString()
53394
+ }
53395
+ };
53396
+ }
53397
+ return null;
53348
53398
  }
53349
53399
  render(item, context, settings) {
53400
+ const isInverse = item.metadata?.inverse === "true";
53350
53401
  if (context.isPreview) {
53351
- return item.rawValue ? "11.6%" : "Ctx(u): 11.6%";
53402
+ const previewValue = isInverse ? "88.4%" : "11.6%";
53403
+ return item.rawValue ? previewValue : `Ctx(u): ${previewValue}`;
53352
53404
  } else if (context.tokenMetrics) {
53353
- const percentage = Math.min(100, context.tokenMetrics.contextLength / 160000 * 100);
53354
- return item.rawValue ? `${percentage.toFixed(1)}%` : `Ctx(u): ${percentage.toFixed(1)}%`;
53405
+ const usedPercentage = Math.min(100, context.tokenMetrics.contextLength / 160000 * 100);
53406
+ const displayPercentage = isInverse ? 100 - usedPercentage : usedPercentage;
53407
+ return item.rawValue ? `${displayPercentage.toFixed(1)}%` : `Ctx(u): ${displayPercentage.toFixed(1)}%`;
53355
53408
  }
53356
53409
  return null;
53357
53410
  }
53411
+ getCustomKeybinds() {
53412
+ return [
53413
+ { key: "l", label: "(l)eft/remaining", action: "toggle-inverse" }
53414
+ ];
53415
+ }
53358
53416
  supportsRawValue() {
53359
53417
  return true;
53360
53418
  }
@@ -53379,10 +53437,9 @@ class SessionClockWidget {
53379
53437
  render(item, context, settings) {
53380
53438
  if (context.isPreview) {
53381
53439
  return item.rawValue ? "2hr 15m" : "Session: 2hr 15m";
53382
- } else if (context.sessionDuration) {
53383
- return item.rawValue ? context.sessionDuration : `Session: ${context.sessionDuration}`;
53384
53440
  }
53385
- return null;
53441
+ const duration3 = context.sessionDuration ?? "0m";
53442
+ return item.rawValue ? duration3 : `Session: ${duration3}`;
53386
53443
  }
53387
53444
  supportsRawValue() {
53388
53445
  return true;
@@ -58973,12 +59030,21 @@ function getAllTimestampsFromFile(filePath) {
58973
59030
  for (const line of lines) {
58974
59031
  try {
58975
59032
  const json2 = JSON.parse(line);
58976
- if (json2.timestamp && typeof json2.timestamp === "string") {
58977
- const date5 = new Date(json2.timestamp);
58978
- if (!Number.isNaN(date5.getTime())) {
58979
- timestamps.push(date5);
58980
- }
58981
- }
59033
+ const usage = json2.message?.usage;
59034
+ if (!usage)
59035
+ continue;
59036
+ const hasInputTokens = typeof usage.input_tokens === "number";
59037
+ const hasOutputTokens = typeof usage.output_tokens === "number";
59038
+ if (!hasInputTokens || !hasOutputTokens)
59039
+ continue;
59040
+ if (json2.isSidechain === true)
59041
+ continue;
59042
+ const timestamp = json2.timestamp;
59043
+ if (typeof timestamp !== "string")
59044
+ continue;
59045
+ const date5 = new Date(timestamp);
59046
+ if (!Number.isNaN(date5.getTime()))
59047
+ timestamps.push(date5);
58982
59048
  } catch {
58983
59049
  continue;
58984
59050
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccstatusline",
3
- "version": "2.0.13",
3
+ "version": "2.0.15",
4
4
  "description": "A customizable status line formatter for Claude Code CLI",
5
5
  "module": "src/ccstatusline.ts",
6
6
  "type": "module",
@@ -17,12 +17,15 @@
17
17
  "example": "cat scripts/payload.example.json | bun start",
18
18
  "prepublishOnly": "bun run build",
19
19
  "lint": "bun tsc --noEmit; eslint . --config eslint.config.js --max-warnings=999999 --fix",
20
- "test": "bun vitest"
20
+ "test": "bun vitest",
21
+ "docs": "typedoc",
22
+ "docs:clean": "rm -rf docs"
21
23
  },
22
24
  "devDependencies": {
23
25
  "@eslint/js": "^9.33.0",
24
26
  "@stylistic/eslint-plugin": "^5.2.3",
25
27
  "@types/bun": "latest",
28
+ "@types/pluralize": "^0.0.33",
26
29
  "@types/react": "^19.1.10",
27
30
  "chalk": "^5.5.0",
28
31
  "eslint": "^9.33.0",
@@ -34,16 +37,16 @@
34
37
  "ink": "^6.2.0",
35
38
  "ink-gradient": "^3.0.0",
36
39
  "ink-select-input": "^6.2.0",
40
+ "pluralize": "^8.0.0",
37
41
  "react": "^19.1.1",
38
42
  "react-devtools-core": "^6.1.5",
39
43
  "strip-ansi": "^7.1.0",
40
44
  "tinyglobby": "^0.2.14",
45
+ "typedoc": "^0.28.12",
41
46
  "typescript": "^5.9.2",
42
47
  "typescript-eslint": "^8.39.1",
43
48
  "vitest": "^3.2.4",
44
- "zod": "^4.0.17",
45
- "pluralize": "^8.0.0",
46
- "@types/pluralize": "^0.0.33"
49
+ "zod": "^4.0.17"
47
50
  },
48
51
  "keywords": [
49
52
  "claude",