@chongdashu/cc-statusline 1.3.0 → 1.4.0

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/CHANGELOG.md CHANGED
@@ -5,6 +5,63 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.4.0] - 2025-12-24
9
+
10
+ ### Changed
11
+ - šŸš€ **Native Token Statistics** - Token counts and TPM now use Claude Code's native `context_window` data
12
+ - No longer relies on ccusage for token statistics
13
+ - Uses `context_window.total_input_tokens` and `total_output_tokens` from Claude Code's JSON input
14
+ - TPM (tokens per minute) calculated from native token counts and session duration
15
+ - More reliable and faster - no external tool calls needed for token data
16
+
17
+ - āš ļø **Session Reset Time Now Optional** - Session reset time feature is now **off by default**
18
+ - Clearly marked as "(requires ccusage)" in feature selection
19
+ - Only feature that still requires the external ccusage tool
20
+ - ccusage integration only enabled when session feature is selected
21
+
22
+ ### Removed
23
+ - šŸ—‘ļø **Reduced ccusage Dependency** - ccusage is no longer needed for most features
24
+ - Token statistics: Now native
25
+ - Tokens per minute: Now native
26
+ - Cost and burn rate: Already native since v1.3.0
27
+ - Only session reset time still requires ccusage
28
+
29
+ ### Technical
30
+ - Refactored `src/features/usage.ts` to extract tokens from `context_window` object
31
+ - Updated mock test data in `src/utils/tester.ts` to match Claude Code's full JSON structure
32
+ - Config summary now warns when ccusage is required (only for session feature)
33
+ - Cleaner generated bash scripts when session feature is disabled
34
+
35
+ ## [1.3.2] - 2025-08-28
36
+
37
+ ### Fixed
38
+ - 🪟 **Windows Bash Compatibility** - Fixed JSON extraction in bash fallback mode for Windows Git Bash/MinGW
39
+ - Improved nested JSON field extraction for `workspace.current_dir` and `model.display_name`
40
+ - Added Windows path conversion from backslashes to forward slashes
41
+ - Fixed cost data extraction without jq
42
+ - Generator now uses `bash .claude/statusline.sh` command in settings.json for Windows
43
+
44
+ ## [1.3.1] - 2025-08-28
45
+
46
+ ### Fixed
47
+ - šŸ› **Critical: Bash JSON Fallback Parser** - Fixed syntax error in fallback JSON parser for systems without jq
48
+ - Fixed malformed grep patterns with incorrect quote escaping in `bash-generator.ts`
49
+ - Statusline now works correctly on systems without jq installed
50
+ - Properly escapes quotes in generated bash script (`\"${field}\"` instead of `"${field}"`)
51
+
52
+ ### Added
53
+ - ✨ **jq Detection and Installation Guide** - Added automatic jq detection during init
54
+ - Checks if jq is installed and warns about limited functionality without it
55
+ - Provides platform-specific installation instructions (macOS, Linux, Windows)
56
+ - Asks users if they want to continue without jq
57
+ - Clear documentation in README about which features require jq
58
+
59
+ ### Changed
60
+ - šŸ“š **Enhanced Windows Documentation** - Clarified jq installation for Windows users
61
+ - Specific file names for download (`jq-windows-amd64.exe` for 64-bit)
62
+ - Step-by-step PATH configuration instructions
63
+ - Clear options between package managers and manual installation
64
+
8
65
  ## [1.3.0] - 2025-08-28
9
66
 
10
67
  ### Changed
package/CLAUDE.md CHANGED
@@ -24,6 +24,12 @@ npm run dev
24
24
 
25
25
  # Test as if installed globally
26
26
  npx . init
27
+
28
+ # Test the generated statusline with mock data
29
+ ./test_debug.sh
30
+
31
+ # Run installation tests
32
+ ./test/test-installation.sh
27
33
  ```
28
34
 
29
35
  ## Architecture
@@ -54,6 +60,15 @@ Key design patterns:
54
60
 
55
61
  **Testing Approach**: Preview command uses mock Claude Code JSON data to test statuslines before installation. Real testing requires manual verification with Claude Code running.
56
62
 
63
+ ## Critical Bug-Prone Areas
64
+
65
+ **JSON Parsing in Bash**: The `bash-generator.ts` file contains a fallback JSON parser for systems without `jq`. This uses complex grep/sed patterns with careful quote escaping. The quotes in the grep patterns must be escaped as `\\"` in the TypeScript template strings to generate valid bash code.
66
+
67
+ **Quote Escaping in bash-generator.ts**: Lines 100-105 contain grep patterns that require double escaping:
68
+ - TypeScript template literal needs `\\` for a single backslash
69
+ - Bash needs `\"` for escaped quotes
70
+ - Combined: `\\"\\${field}\\"` to produce `"${field}"` in the final bash script
71
+
57
72
  ## Important Conventions
58
73
 
59
74
  - Use ESM imports with `.js` extensions (even for `.ts` files)
package/README.md CHANGED
@@ -24,14 +24,72 @@ npx @chongdashu/cc-statusline@latest init
24
24
 
25
25
  That's it! Answer a few simple questions, restart Claude Code, and enjoy your new statusline.
26
26
 
27
- ### šŸ†• Installation Options (v1.2.4+)
28
- - **šŸ  Global Installation** (`~/.claude/`) - Use across all your projects
29
- - **šŸ“‚ Project Installation** (`./.claude/`) - Keep settings project-specific
27
+ ## šŸ“‹ Prerequisites
28
+
29
+ ### Required
30
+ - **Node.js 16+** - Required for the CLI tool
31
+ - **Claude Code** - The tool you're already using
32
+
33
+ ### Strongly Recommended
34
+ - **jq** - JSON processor for advanced features (see installation guide below)
35
+ - Required for: context tracking, token stats, session timer
36
+ - Without jq: basic features still work with fallback parser
37
+
38
+ > **Without jq, your statusline will have LIMITED functionality:**
39
+ > - āŒ No context remaining percentage
40
+ > - āŒ No token statistics from ccusage
41
+ > - āŒ No session timer
42
+ > - āš ļø Basic fallback parser is used (less reliable)
43
+
44
+ #### macOS
45
+ ```bash
46
+ brew install jq
47
+ ```
48
+
49
+ #### Linux
50
+ ```bash
51
+ # Ubuntu/Debian
52
+ sudo apt-get install jq
53
+
54
+ # CentOS/RHEL/Fedora
55
+ sudo yum install jq
56
+
57
+ # Arch Linux
58
+ sudo pacman -S jq
59
+ ```
60
+
61
+ #### Windows 10/11
62
+
63
+ **Option 1: Package Manager (Recommended)**
64
+ ```bash
65
+ # Chocolatey
66
+ choco install jq
67
+
68
+ # Scoop
69
+ scoop install jq
70
+
71
+ # Winget
72
+ winget install jqlang.jq
73
+ ```
74
+
75
+ **Option 2: Manual Download**
76
+ 1. Go to https://github.com/jqlang/jq/releases/latest
77
+ 2. Download:
78
+ - **64-bit**: `jq-windows-amd64.exe`
79
+ - **32-bit**: `jq-windows-i386.exe`
80
+ 3. Rename to `jq.exe`
81
+ 4. Place in `C:\Windows\System32\` (requires admin) or add to PATH
82
+ 5. Test: `jq --version`
83
+
84
+ ### Verify Installation
85
+ ```bash
86
+ jq --version
87
+ # Should output: jq-1.6 or higher
88
+ ```
30
89
 
31
- ### šŸ“ˆ What's New in v1.3.0
32
- - **šŸ”„ Improved Burn Rate** - Now calculates $/hour directly from Claude Code data (no ccusage dependency)
33
- - **šŸ“ Smart Logging** - Logs are created relative to statusline installation location
34
- - **✨ Version Headers** - Generated statuslines now include the cc-statusline version
90
+ ### Optional
91
+ - **git** - For branch display (you probably have this)
92
+ - **ccusage** - For usage stats (works via `npx` - no install needed)
35
93
 
36
94
  ## šŸŽÆ Simple Setup
37
95
 
@@ -44,15 +102,19 @@ Enhance your Claude Code terminal with useful information:
44
102
  - **šŸ“ Directory Display** - Current folder with `~` abbreviation
45
103
  - **🌿 Git Integration** - Current branch name
46
104
  - **šŸ¤– Model Info** - Shows which Claude model you're using plus Claude Code version
47
- - **🧠 Context Usage** - Real-time context window usage with progress bars
48
- - **šŸ’° Cost Tracking** - Live cost monitoring with burn rates via ccusage
49
- - **āŒ› Session Timer** - Time remaining until usage limit resets
50
- - **šŸ“Š Token Analytics** - Token consumption and burn rate metrics
105
+ - **🧠 Context Usage** - Real-time context window usage with progress bars **(requires jq)**
106
+ - **šŸ’° Cost Tracking** - Live cost monitoring with burn rates via ccusage **(partial without jq)**
107
+ - **āŒ› Session Timer** - Time remaining until usage limit resets **(requires jq)**
108
+ - **šŸ“Š Token Analytics** - Token consumption and burn rate metrics **(requires jq)**
51
109
  - **šŸŽØ Color Support** - 256-color palette for Claude Code terminals
52
110
  - **⚔ Fast Execution** - Optimized bash script with <100ms execution time
53
111
 
54
112
  ## šŸŽ›ļø Features Overview
55
113
 
114
+ ### šŸ†• Installation Options (v1.2.4+)
115
+ - **šŸ  Global Installation** (`~/.claude/`) - Use across all your projects
116
+ - **šŸ“‚ Project Installation** (`./.claude/`) - Keep settings project-specific
117
+
56
118
  ### šŸ”„ Default Features (All Pre-selected in v1.2.2+)
57
119
  | Feature | Description | Example |
58
120
  |---------|-------------|---------|
@@ -136,20 +198,7 @@ npm install -g @chongdashu/cc-statusline
136
198
  - **šŸ“¦ Zero Dependencies** - Self-contained script with graceful fallbacks
137
199
  - **šŸ”’ Secure** - No network requests except ccusage integration
138
200
 
139
- ## šŸ“‹ Requirements
140
-
141
- ### āœ… Required (You Already Have These!)
142
- - **Claude Code** - The tool you're already using
143
- - **jq** - JSON processing (pre-installed on most systems)
144
-
145
- ### šŸŽ Optional Enhancements
146
- - **git** - For branch display (you probably have this)
147
- - **ccusage** - For usage stats (works via `npx` - no install needed)
148
201
 
149
- ### Quick Compatibility Check
150
- ```bash
151
- command -v jq && echo "āœ… Ready to go!"
152
- ```
153
202
 
154
203
  ## šŸ“‚ File Structure
155
204
 
@@ -188,7 +237,7 @@ If auto-configuration fails, simply add this to `.claude/settings.json`:
188
237
  - **Disable ccusage**: Remove usage tracking if not needed
189
238
 
190
239
  ### 🧩 Missing Features
191
- - **Install jq**: `brew install jq` (macOS) or `apt install jq` (Ubuntu)
240
+ - **Install jq**: See the jq installation guide below
192
241
  - **ccusage setup**: Works automatically via `npx ccusage@latest`
193
242
  - **Git not found**: Install git for branch display
194
243
  - **Context not showing**: Ensure you're in an active Claude Code session with context usage
@@ -273,6 +322,8 @@ ps aux | grep ccusage | grep -v grep
273
322
 
274
323
  </div>
275
324
 
325
+
326
+
276
327
  ## šŸ”— Related Projects
277
328
 
278
329
  - **[ccusage](https://github.com/ryoppippi/ccusage)** - Claude Code usage analytics (would not be possible with it!)
package/dist/index.js CHANGED
@@ -61,12 +61,36 @@ function generateMockClaudeInput(config) {
61
61
  transcript_path: "/home/user/.claude/conversations/test.jsonl",
62
62
  cwd: "/home/user/projects/my-project",
63
63
  workspace: {
64
- current_dir: "/home/user/projects/my-project"
64
+ current_dir: "/home/user/projects/my-project",
65
+ project_dir: "/home/user/projects/my-project"
65
66
  },
66
67
  model: {
67
68
  id: "claude-opus-4-1-20250805",
68
69
  display_name: "Opus 4.1",
69
70
  version: "20250805"
71
+ },
72
+ version: "1.0.80",
73
+ output_style: {
74
+ name: "default"
75
+ },
76
+ cost: {
77
+ total_cost_usd: 0.42,
78
+ total_duration_ms: 18e4,
79
+ // 3 minutes
80
+ total_api_duration_ms: 2300,
81
+ total_lines_added: 156,
82
+ total_lines_removed: 23
83
+ },
84
+ context_window: {
85
+ total_input_tokens: 15234,
86
+ total_output_tokens: 4521,
87
+ context_window_size: 2e5,
88
+ current_usage: {
89
+ input_tokens: 8500,
90
+ output_tokens: 1200,
91
+ cache_creation_input_tokens: 5e3,
92
+ cache_read_input_tokens: 2e3
93
+ }
70
94
  }
71
95
  };
72
96
  }
@@ -310,9 +334,9 @@ async function collectConfiguration() {
310
334
  { name: "\u{1F916} Model Name & Version", value: "model", checked: true },
311
335
  { name: "\u{1F9E0} Context Remaining", value: "context", checked: true },
312
336
  { name: "\u{1F4B5} Usage & Cost", value: "usage", checked: true },
313
- { name: "\u231B Session Time Remaining", value: "session", checked: true },
314
337
  { name: "\u{1F4CA} Token Statistics", value: "tokens", checked: true },
315
- { name: "\u26A1 Burn Rate (tokens/min)", value: "burnrate", checked: true }
338
+ { name: "\u26A1 Burn Rate ($/hr & tokens/min)", value: "burnrate", checked: true },
339
+ { name: "\u231B Session Reset Time (requires ccusage)", value: "session", checked: false }
316
340
  ],
317
341
  validate: (answer) => {
318
342
  if (answer.length < 1) {
@@ -345,13 +369,13 @@ async function collectConfiguration() {
345
369
  default: "project"
346
370
  }
347
371
  ]);
372
+ const needsCcusage = config.features.includes("session");
348
373
  return {
349
374
  features: config.features,
350
375
  runtime: "bash",
351
376
  colors: config.colors,
352
377
  theme: "detailed",
353
- ccusageIntegration: true,
354
- // Always enabled since npx works
378
+ ccusageIntegration: needsCcusage,
355
379
  logging: config.logging,
356
380
  customEmojis: false,
357
381
  installLocation: config.installLocation
@@ -440,50 +464,82 @@ cost_color() { :; }
440
464
  burn_color() { :; }
441
465
  session_color() { :; }
442
466
  `;
467
+ const needsCcusage = config.showSession || config.showProgressBar;
443
468
  return `${colorCode}
444
469
  # ---- cost and usage extraction ----
445
470
  session_txt=""; session_pct=0; session_bar=""
446
471
  cost_usd=""; cost_per_hour=""; tpm=""; tot_tokens=""
447
472
 
448
- # Extract cost data from Claude Code input
449
- if command -v jq >/dev/null 2>&1; then
450
- # Get cost data from Claude Code's input
473
+ # Extract cost and token data from Claude Code's native input
474
+ if [ "$HAS_JQ" -eq 1 ]; then
475
+ # Cost data
451
476
  cost_usd=$(echo "$input" | jq -r '.cost.total_cost_usd // empty' 2>/dev/null)
452
477
  total_duration_ms=$(echo "$input" | jq -r '.cost.total_duration_ms // empty' 2>/dev/null)
453
-
478
+
454
479
  # Calculate burn rate ($/hour) from cost and duration
455
480
  if [ -n "$cost_usd" ] && [ -n "$total_duration_ms" ] && [ "$total_duration_ms" -gt 0 ]; then
456
- # Convert ms to hours and calculate rate
457
481
  cost_per_hour=$(echo "$cost_usd $total_duration_ms" | awk '{printf "%.2f", $1 * 3600000 / $2}')
458
482
  fi
459
- fi
483
+ ${config.showTokens ? `
484
+ # Token data from native context_window (no ccusage needed)
485
+ input_tokens=$(echo "$input" | jq -r '.context_window.total_input_tokens // 0' 2>/dev/null)
486
+ output_tokens=$(echo "$input" | jq -r '.context_window.total_output_tokens // 0' 2>/dev/null)
487
+
488
+ if [ "$input_tokens" != "null" ] && [ "$output_tokens" != "null" ]; then
489
+ tot_tokens=$(( input_tokens + output_tokens ))
490
+ [ "$tot_tokens" -eq 0 ] && tot_tokens=""
491
+ fi` : ""}
492
+ ${config.showBurnRate && config.showTokens ? `
493
+ # Calculate tokens per minute from native data
494
+ if [ -n "$tot_tokens" ] && [ -n "$total_duration_ms" ] && [ "$total_duration_ms" -gt 0 ]; then
495
+ # Convert ms to minutes and calculate rate
496
+ tpm=$(echo "$tot_tokens $total_duration_ms" | awk '{if ($2 > 0) printf "%.0f", $1 * 60000 / $2; else print ""}')
497
+ fi` : ""}
498
+ else
499
+ # Bash fallback for cost extraction
500
+ cost_usd=$(echo "$input" | grep -o '"total_cost_usd"[[:space:]]*:[[:space:]]*[0-9.]*' | sed 's/.*:[[:space:]]*\\([0-9.]*\\).*/\\1/')
501
+ total_duration_ms=$(echo "$input" | grep -o '"total_duration_ms"[[:space:]]*:[[:space:]]*[0-9]*' | sed 's/.*:[[:space:]]*\\([0-9]*\\).*/\\1/')
502
+
503
+ # Calculate burn rate ($/hour) from cost and duration
504
+ if [ -n "$cost_usd" ] && [ -n "$total_duration_ms" ] && [ "$total_duration_ms" -gt 0 ]; then
505
+ cost_per_hour=$(echo "$cost_usd $total_duration_ms" | awk '{printf "%.2f", $1 * 3600000 / $2}')
506
+ fi
507
+ ${config.showTokens ? `
508
+ # Token data from native context_window (bash fallback)
509
+ input_tokens=$(echo "$input" | grep -o '"total_input_tokens"[[:space:]]*:[[:space:]]*[0-9]*' | sed 's/.*:[[:space:]]*\\([0-9]*\\).*/\\1/')
510
+ output_tokens=$(echo "$input" | grep -o '"total_output_tokens"[[:space:]]*:[[:space:]]*[0-9]*' | sed 's/.*:[[:space:]]*\\([0-9]*\\).*/\\1/')
460
511
 
461
- # Get token data and session info from ccusage if available
462
- if command -v ccusage >/dev/null 2>&1 && command -v jq >/dev/null 2>&1; then
512
+ if [ -n "$input_tokens" ] && [ -n "$output_tokens" ]; then
513
+ tot_tokens=$(( input_tokens + output_tokens ))
514
+ [ "$tot_tokens" -eq 0 ] && tot_tokens=""
515
+ fi` : ""}
516
+ ${config.showBurnRate && config.showTokens ? `
517
+ # Calculate tokens per minute from native data
518
+ if [ -n "$tot_tokens" ] && [ -n "$total_duration_ms" ] && [ "$total_duration_ms" -gt 0 ]; then
519
+ tpm=$(echo "$tot_tokens $total_duration_ms" | awk '{if ($2 > 0) printf "%.0f", $1 * 60000 / $2; else print ""}')
520
+ fi` : ""}
521
+ fi
522
+ ${needsCcusage ? `
523
+ # Session reset time requires ccusage (only feature that needs external tool)
524
+ if command -v ccusage >/dev/null 2>&1 && [ "$HAS_JQ" -eq 1 ]; then
463
525
  blocks_output=""
464
-
465
- # Try ccusage with timeout for token data and session info
526
+
527
+ # Try ccusage with timeout
466
528
  if command -v timeout >/dev/null 2>&1; then
467
529
  blocks_output=$(timeout 5s ccusage blocks --json 2>/dev/null)
468
530
  elif command -v gtimeout >/dev/null 2>&1; then
469
- # macOS with coreutils installed
470
531
  blocks_output=$(gtimeout 5s ccusage blocks --json 2>/dev/null)
471
532
  else
472
- # No timeout available, run directly (ccusage should be fast)
473
533
  blocks_output=$(ccusage blocks --json 2>/dev/null)
474
534
  fi
535
+
475
536
  if [ -n "$blocks_output" ]; then
476
537
  active_block=$(echo "$blocks_output" | jq -c '.blocks[] | select(.isActive == true)' 2>/dev/null | head -n1)
477
- if [ -n "$active_block" ]; then${config.showTokens ? `
478
- # Get token count from ccusage
479
- tot_tokens=$(echo "$active_block" | jq -r '.totalTokens // empty')` : ""}${config.showBurnRate && config.showTokens ? `
480
- # Get tokens per minute from ccusage
481
- tpm=$(echo "$active_block" | jq -r '.burnRate.tokensPerMinute // empty')` : ""}${config.showSession || config.showProgressBar ? `
482
-
538
+ if [ -n "$active_block" ]; then
483
539
  # Session time calculation from ccusage
484
540
  reset_time_str=$(echo "$active_block" | jq -r '.usageLimitResetTime // .endTime // empty')
485
541
  start_time_str=$(echo "$active_block" | jq -r '.startTime // empty')
486
-
542
+
487
543
  if [ -n "$reset_time_str" ] && [ -n "$start_time_str" ]; then
488
544
  start_sec=$(to_epoch "$start_time_str"); end_sec=$(to_epoch "$reset_time_str"); now_sec=$(date +%s)
489
545
  total=$(( end_sec - start_sec )); (( total<1 )) && total=1
@@ -494,10 +550,10 @@ if command -v ccusage >/dev/null 2>&1 && command -v jq >/dev/null 2>&1; then
494
550
  end_hm=$(fmt_time_hm "$end_sec")${config.showSession ? `
495
551
  session_txt="$(printf '%dh %dm until reset at %s (%d%%)' "$rh" "$rm" "$end_hm" "$session_pct")"` : ""}${config.showProgressBar ? `
496
552
  session_bar=$(progress_bar "$session_pct" 10)` : ""}
497
- fi` : ""}
553
+ fi
498
554
  fi
499
555
  fi
500
- fi`;
556
+ fi` : ""}`;
501
557
  }
502
558
  function generateUsageUtilities() {
503
559
  return `
@@ -528,7 +584,7 @@ progress_bar() {
528
584
  }
529
585
 
530
586
  // src/generators/bash-generator.ts
531
- var VERSION = "1.3.0";
587
+ var VERSION = "1.4.0";
532
588
  function generateBashStatusline(config) {
533
589
  const hasGit = config.features.includes("git");
534
590
  const hasUsage = config.features.some((f) => ["usage", "session", "tokens", "burnrate"].includes(f));
@@ -555,8 +611,15 @@ function generateBashStatusline(config) {
555
611
  # Generated by cc-statusline v${VERSION} (https://www.npmjs.com/package/@chongdashu/cc-statusline)
556
612
  # Custom Claude Code statusline - Created: ${timestamp}
557
613
  # Theme: ${config.theme} | Colors: ${config.colors} | Features: ${config.features.join(", ")}
614
+ STATUSLINE_VERSION="${VERSION}"
558
615
 
559
616
  input=$(cat)
617
+
618
+ # ---- check jq availability ----
619
+ HAS_JQ=0
620
+ if command -v jq >/dev/null 2>&1; then
621
+ HAS_JQ=1
622
+ fi
560
623
  ${config.logging ? generateLoggingCode() : ""}
561
624
  ${generateColorBashCode({ enabled: config.colors, theme: config.theme })}
562
625
  ${config.colors ? generateBasicColors() : ""}
@@ -580,16 +643,59 @@ TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
580
643
 
581
644
  # ---- logging ----
582
645
  {
583
- echo "[$TIMESTAMP] Status line triggered with input:"
584
- (echo "$input" | jq . 2>/dev/null) || echo "$input"
646
+ echo "[$TIMESTAMP] Status line triggered (cc-statusline v\${STATUSLINE_VERSION})"
647
+ echo "[$TIMESTAMP] Input:"
648
+ if [ "$HAS_JQ" -eq 1 ]; then
649
+ echo "$input" | jq . 2>/dev/null || echo "$input"
650
+ echo "[$TIMESTAMP] Using jq for JSON parsing"
651
+ else
652
+ echo "$input"
653
+ echo "[$TIMESTAMP] WARNING: jq not found, using bash fallback for JSON parsing"
654
+ fi
585
655
  echo "---"
586
656
  } >> "$LOG_FILE" 2>/dev/null
587
657
  `;
588
658
  }
659
+ function generateJsonExtractorCode() {
660
+ return `
661
+ # ---- JSON extraction utilities ----
662
+ # Pure bash JSON value extractor (fallback when jq not available)
663
+ extract_json_string() {
664
+ local json="$1"
665
+ local key="$2"
666
+ local default="\${3:-}"
667
+
668
+ # For nested keys like workspace.current_dir, get the last part
669
+ local field="\${key##*.}"
670
+ field="\${field%% *}" # Remove any jq operators
671
+
672
+ # Try to extract string value (quoted)
673
+ local value=$(echo "$json" | grep -o "\\"\\\${field}\\"[[:space:]]*:[[:space:]]*\\"[^\\"]*\\"" | head -1 | sed 's/.*:[[:space:]]*"\\([^"]*\\)".*/\\1/')
674
+
675
+ # Convert escaped backslashes to forward slashes for Windows paths
676
+ if [ -n "$value" ]; then
677
+ value=$(echo "$value" | sed 's/\\\\\\\\/\\//g')
678
+ fi
679
+
680
+ # If no string value found, try to extract number value (unquoted)
681
+ if [ -z "$value" ] || [ "$value" = "null" ]; then
682
+ value=$(echo "$json" | grep -o "\\"\\\${field}\\"[[:space:]]*:[[:space:]]*[0-9.]\\+" | head -1 | sed 's/.*:[[:space:]]*\\([0-9.]\\+\\).*/\\1/')
683
+ fi
684
+
685
+ # Return value or default
686
+ if [ -n "$value" ] && [ "$value" != "null" ]; then
687
+ echo "$value"
688
+ else
689
+ echo "$default"
690
+ fi
691
+ }
692
+ `;
693
+ }
589
694
  function generateBasicDataExtraction(hasDirectory, hasModel, hasContext) {
590
695
  return `
696
+ ${generateJsonExtractorCode()}
591
697
  # ---- basics ----
592
- if command -v jq >/dev/null 2>&1; then${hasDirectory ? `
698
+ if [ "$HAS_JQ" -eq 1 ]; then${hasDirectory ? `
593
699
  current_dir=$(echo "$input" | jq -r '.workspace.current_dir // .cwd // "unknown"' 2>/dev/null | sed "s|^$HOME|~|g")` : ""}${hasModel ? `
594
700
  model_name=$(echo "$input" | jq -r '.model.display_name // "Claude"' 2>/dev/null)
595
701
  model_version=$(echo "$input" | jq -r '.model.version // ""' 2>/dev/null)` : ""}${hasContext ? `
@@ -597,57 +703,56 @@ if command -v jq >/dev/null 2>&1; then${hasDirectory ? `
597
703
  cc_version=$(echo "$input" | jq -r '.version // ""' 2>/dev/null)
598
704
  output_style=$(echo "$input" | jq -r '.output_style.name // ""' 2>/dev/null)
599
705
  else${hasDirectory ? `
600
- current_dir="unknown"` : ""}${hasModel ? `
601
- model_name="Claude"; model_version=""` : ""}${hasContext ? `
602
- session_id=""` : ""}
603
- cc_version=""
604
- output_style=""
706
+ # Bash fallback for JSON extraction
707
+ # Extract current_dir from workspace object - look for the pattern workspace":{"current_dir":"..."}
708
+ current_dir=$(echo "$input" | grep -o '"workspace"[[:space:]]*:[[:space:]]*{[^}]*"current_dir"[[:space:]]*:[[:space:]]*"[^"]*"' | sed 's/.*"current_dir"[[:space:]]*:[[:space:]]*"\\([^"]*\\)".*/\\1/' | sed 's/\\\\\\\\/\\//g')
709
+
710
+ # Fall back to cwd if workspace extraction failed
711
+ if [ -z "$current_dir" ] || [ "$current_dir" = "null" ]; then
712
+ current_dir=$(echo "$input" | grep -o '"cwd"[[:space:]]*:[[:space:]]*"[^"]*"' | sed 's/.*"cwd"[[:space:]]*:[[:space:]]*"\\([^"]*\\)".*/\\1/' | sed 's/\\\\\\\\/\\//g')
713
+ fi
714
+
715
+ # Fallback to unknown if all extraction failed
716
+ [ -z "$current_dir" ] && current_dir="unknown"
717
+ current_dir=$(echo "$current_dir" | sed "s|^$HOME|~|g")` : ""}${hasModel ? `
718
+
719
+ # Extract model name from nested model object
720
+ model_name=$(echo "$input" | grep -o '"model"[[:space:]]*:[[:space:]]*{[^}]*"display_name"[[:space:]]*:[[:space:]]*"[^"]*"' | sed 's/.*"display_name"[[:space:]]*:[[:space:]]*"\\([^"]*\\)".*/\\1/')
721
+ [ -z "$model_name" ] && model_name="Claude"
722
+ # Model version is in the model ID, not a separate field
723
+ model_version="" # Not available in Claude Code JSON` : ""}${hasContext ? `
724
+ session_id=$(extract_json_string "$input" "session_id" "")` : ""}
725
+ # CC version is at the root level
726
+ cc_version=$(echo "$input" | grep -o '"version"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*"version"[[:space:]]*:[[:space:]]*"\\([^"]*\\)".*/\\1/')
727
+ # Output style is nested
728
+ output_style=$(echo "$input" | grep -o '"output_style"[[:space:]]*:[[:space:]]*{[^}]*"name"[[:space:]]*:[[:space:]]*"[^"]*"' | sed 's/.*"name"[[:space:]]*:[[:space:]]*"\\([^"]*\\)".*/\\1/')
605
729
  fi
606
730
  `;
607
731
  }
608
732
  function generateContextBashCode(colors) {
609
733
  return `
610
- # ---- context window calculation ----
734
+ # ---- context window calculation (native) ----
611
735
  context_pct=""
736
+ context_remaining_pct=""
612
737
  context_color() { if [ "$use_color" -eq 1 ]; then printf '\\033[1;37m'; fi; } # default white
613
738
 
614
- # Determine max context based on model
615
- get_max_context() {
616
- local model_name="$1"
617
- case "$model_name" in
618
- *"Opus 4"*|*"opus 4"*|*"Opus"*|*"opus"*)
619
- echo "200000" # 200K for all Opus versions
620
- ;;
621
- *"Sonnet 4"*|*"sonnet 4"*|*"Sonnet 3.5"*|*"sonnet 3.5"*|*"Sonnet"*|*"sonnet"*)
622
- echo "200000" # 200K for Sonnet 3.5+ and 4.x
623
- ;;
624
- *"Haiku 3.5"*|*"haiku 3.5"*|*"Haiku 4"*|*"haiku 4"*|*"Haiku"*|*"haiku"*)
625
- echo "200000" # 200K for modern Haiku
626
- ;;
627
- *"Claude 3 Haiku"*|*"claude 3 haiku"*)
628
- echo "100000" # 100K for original Claude 3 Haiku
629
- ;;
630
- *)
631
- echo "200000" # Default to 200K
632
- ;;
633
- esac
634
- }
635
-
636
- if [ -n "$session_id" ] && command -v jq >/dev/null 2>&1; then
637
- MAX_CONTEXT=$(get_max_context "$model_name")
638
-
639
- # Convert current dir to session file path
640
- project_dir=$(echo "$current_dir" | sed "s|~|$HOME|g" | sed 's|/|-|g' | sed 's|^-||')
641
- session_file="$HOME/.claude/projects/-\${project_dir}/\${session_id}.jsonl"
642
-
643
- if [ -f "$session_file" ]; then
644
- # Get the latest input token count from the session file
645
- latest_tokens=$(tail -20 "$session_file" | jq -r 'select(.message.usage) | .message.usage | ((.input_tokens // 0) + (.cache_read_input_tokens // 0))' 2>/dev/null | tail -1)
646
-
647
- if [ -n "$latest_tokens" ] && [ "$latest_tokens" -gt 0 ]; then
648
- context_used_pct=$(( latest_tokens * 100 / MAX_CONTEXT ))
739
+ if [ "$HAS_JQ" -eq 1 ]; then
740
+ # Get context window size and current usage from native Claude Code input
741
+ CONTEXT_SIZE=$(echo "$input" | jq -r '.context_window.context_window_size // 200000' 2>/dev/null)
742
+ USAGE=$(echo "$input" | jq '.context_window.current_usage' 2>/dev/null)
743
+
744
+ if [ "$USAGE" != "null" ] && [ -n "$USAGE" ]; then
745
+ # Calculate current context from current_usage fields
746
+ # Formula: input_tokens + cache_creation_input_tokens + cache_read_input_tokens
747
+ CURRENT_TOKENS=$(echo "$USAGE" | jq '(.input_tokens // 0) + (.cache_creation_input_tokens // 0) + (.cache_read_input_tokens // 0)' 2>/dev/null)
748
+
749
+ if [ -n "$CURRENT_TOKENS" ] && [ "$CURRENT_TOKENS" -gt 0 ] 2>/dev/null; then
750
+ context_used_pct=$(( CURRENT_TOKENS * 100 / CONTEXT_SIZE ))
649
751
  context_remaining_pct=$(( 100 - context_used_pct ))
650
-
752
+ # Clamp to valid range
753
+ (( context_remaining_pct < 0 )) && context_remaining_pct=0
754
+ (( context_remaining_pct > 100 )) && context_remaining_pct=100
755
+
651
756
  # Set color based on remaining percentage
652
757
  if [ "$context_remaining_pct" -le 20 ]; then
653
758
  context_color() { if [ "$use_color" -eq 1 ]; then printf '\\033[38;5;203m'; fi; } # coral red
@@ -656,7 +761,7 @@ if [ -n "$session_id" ] && command -v jq >/dev/null 2>&1; then
656
761
  else
657
762
  context_color() { if [ "$use_color" -eq 1 ]; then printf '\\033[38;5;158m'; fi; } # mint green
658
763
  fi
659
-
764
+
660
765
  context_pct="\${context_remaining_pct}%"
661
766
  fi
662
767
  fi
@@ -668,6 +773,9 @@ function generateLoggingOutput() {
668
773
  # ---- log extracted data ----
669
774
  {
670
775
  echo "[$TIMESTAMP] Extracted: dir=\${current_dir:-}, model=\${model_name:-}, version=\${model_version:-}, git=\${git_branch:-}, context=\${context_pct:-}, cost=\${cost_usd:-}, cost_ph=\${cost_per_hour:-}, tokens=\${tot_tokens:-}, tpm=\${tpm:-}, session_pct=\${session_pct:-}"
776
+ if [ "$HAS_JQ" -eq 0 ]; then
777
+ echo "[$TIMESTAMP] Note: Context, tokens, and session info require jq for full functionality"
778
+ fi
671
779
  } >> "$LOG_FILE" 2>/dev/null
672
780
  `;
673
781
  }
@@ -845,7 +953,7 @@ async function updateSettingsJson(claudeDir, scriptName, isGlobal) {
845
953
  }
846
954
  }
847
955
  }
848
- const commandPath = isGlobal ? `~/.claude/${scriptName}` : `.claude/${scriptName}`;
956
+ const commandPath = process.platform === "win32" ? `bash ${isGlobal ? ".claude" : ".claude"}/${scriptName}` : isGlobal ? `~/.claude/${scriptName}` : `.claude/${scriptName}`;
849
957
  settings.statusLine = {
850
958
  type: "command",
851
959
  command: commandPath,
@@ -863,11 +971,97 @@ import chalk from "chalk";
863
971
  import ora from "ora";
864
972
  import path4 from "path";
865
973
  import os2 from "os";
974
+ import { execSync } from "child_process";
975
+ function checkJqInstallation() {
976
+ try {
977
+ execSync("command -v jq", { stdio: "ignore" });
978
+ return true;
979
+ } catch {
980
+ return false;
981
+ }
982
+ }
983
+ function getJqInstallInstructions() {
984
+ const platform = process.platform;
985
+ if (platform === "darwin") {
986
+ return `
987
+ ${chalk.cyan("\u{1F4E6} Install jq for better performance and reliability:")}
988
+
989
+ ${chalk.green("Using Homebrew (recommended):")}
990
+ brew install jq
991
+
992
+ ${chalk.green("Using MacPorts:")}
993
+ sudo port install jq
994
+
995
+ ${chalk.green("Or download directly:")}
996
+ https://github.com/jqlang/jq/releases
997
+ `;
998
+ } else if (platform === "linux") {
999
+ return `
1000
+ ${chalk.cyan("\u{1F4E6} Install jq for better performance and reliability:")}
1001
+
1002
+ ${chalk.green("Ubuntu/Debian:")}
1003
+ sudo apt-get install jq
1004
+
1005
+ ${chalk.green("CentOS/RHEL/Fedora:")}
1006
+ sudo yum install jq
1007
+
1008
+ ${chalk.green("Arch Linux:")}
1009
+ sudo pacman -S jq
1010
+
1011
+ ${chalk.green("Or download directly:")}
1012
+ https://github.com/jqlang/jq/releases
1013
+ `;
1014
+ } else if (platform === "win32") {
1015
+ return `
1016
+ ${chalk.cyan("\u{1F4E6} Install jq for better performance and reliability:")}
1017
+
1018
+ ${chalk.green("Option 1: Using Package Manager")}
1019
+ ${chalk.dim("Chocolatey:")} choco install jq
1020
+ ${chalk.dim("Scoop:")} scoop install jq
1021
+
1022
+ ${chalk.green("Option 2: Manual Download")}
1023
+ 1. Download from: https://github.com/jqlang/jq/releases/latest
1024
+ 2. Choose file:
1025
+ ${chalk.dim("\u2022 64-bit Windows:")} jq-windows-amd64.exe
1026
+ ${chalk.dim("\u2022 32-bit Windows:")} jq-windows-i386.exe
1027
+ 3. Rename to: jq.exe
1028
+ 4. Move to: C:\\Windows\\System32\\ ${chalk.dim("(or add to PATH)")}
1029
+ 5. Test: Open new terminal and run: jq --version
1030
+ `;
1031
+ } else {
1032
+ return `
1033
+ ${chalk.cyan("\u{1F4E6} Install jq for better performance and reliability:")}
1034
+
1035
+ ${chalk.green("Download for your platform:")}
1036
+ https://github.com/jqlang/jq/releases
1037
+ `;
1038
+ }
1039
+ }
866
1040
  async function initCommand(options) {
867
1041
  try {
868
1042
  const spinner = ora("Initializing statusline generator...").start();
869
1043
  await new Promise((resolve) => setTimeout(resolve, 500));
870
1044
  spinner.stop();
1045
+ const hasJq = checkJqInstallation();
1046
+ if (!hasJq) {
1047
+ console.log(chalk.yellow("\n\u26A0\uFE0F jq is not installed"));
1048
+ console.log(chalk.dim("Your statusline will work without jq, but with limited functionality:"));
1049
+ console.log(chalk.dim(" \u2022 Context remaining percentage won't be displayed"));
1050
+ console.log(chalk.dim(" \u2022 Token statistics may not work"));
1051
+ console.log(chalk.dim(" \u2022 Performance will be slower"));
1052
+ console.log(getJqInstallInstructions());
1053
+ const inquirer3 = (await import("inquirer")).default;
1054
+ const { continueWithoutJq } = await inquirer3.prompt([{
1055
+ type: "confirm",
1056
+ name: "continueWithoutJq",
1057
+ message: "Continue without jq?",
1058
+ default: true
1059
+ }]);
1060
+ if (!continueWithoutJq) {
1061
+ console.log(chalk.cyan("\n\u{1F44D} Install jq and run this command again"));
1062
+ process.exit(0);
1063
+ }
1064
+ }
871
1065
  const config = await collectConfiguration();
872
1066
  const validation = validateConfig(config);
873
1067
  if (!validation.isValid) {
@@ -905,7 +1099,9 @@ async function initCommand(options) {
905
1099
  \u{1F4C1} ${isGlobal ? "Global" : "Project"} installation complete: ${chalk.white(resolvedPath)}`));
906
1100
  console.log(chalk.cyan("\nNext steps:"));
907
1101
  console.log(chalk.white(" 1. Restart Claude Code to see your new statusline"));
908
- console.log(chalk.white(" 2. Usage statistics work via: npx ccusage@latest"));
1102
+ if (config.features.includes("session")) {
1103
+ console.log(chalk.white(" 2. Session reset time requires ccusage: npx ccusage@latest"));
1104
+ }
909
1105
  } catch (error) {
910
1106
  console.log(chalk.red("\n\u274C Failed to install statusline"));
911
1107
  if (error instanceof Error && error.message === "USER_CANCELLED_OVERWRITE") {
@@ -945,7 +1141,7 @@ async function initCommand(options) {
945
1141
 
946
1142
  // src/index.ts
947
1143
  import chalk3 from "chalk";
948
- var VERSION2 = "1.3.0";
1144
+ var VERSION2 = "1.4.0";
949
1145
  var program = new Command();
950
1146
  program.name("cc-statusline").description("Interactive CLI tool for generating custom Claude Code statuslines").version(VERSION2);
951
1147
  program.command("init").description("Create a custom statusline with interactive prompts").option("-o, --output <path>", "Output path for statusline.sh", "./.claude/statusline.sh").option("--no-install", "Don't automatically install to .claude/statusline.sh").action(initCommand);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../node_modules/tsup/assets/esm_shims.js","../src/utils/tester.ts","../src/cli/preview.ts","../src/index.ts","../src/cli/commands.ts","../src/cli/prompts.ts","../src/generators/bash-generator.ts","../src/features/colors.ts","../src/features/git.ts","../src/features/usage.ts","../src/utils/validator.ts","../src/utils/installer.ts"],"sourcesContent":["// Shim globals in esm bundle\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nconst getFilename = () => fileURLToPath(import.meta.url)\nconst getDirname = () => path.dirname(getFilename())\n\nexport const __dirname = /* @__PURE__ */ getDirname()\nexport const __filename = /* @__PURE__ */ getFilename()\n","import { StatuslineConfig } from '../cli/prompts.js'\nimport { spawn } from 'child_process'\nimport { promises as fs } from 'fs'\nimport path from 'path'\n\nexport interface TestResult {\n success: boolean\n output: string\n error?: string\n executionTime: number\n}\n\nexport async function testStatuslineScript(script: string, mockData?: any): Promise<TestResult> {\n const startTime = Date.now()\n \n try {\n // Create temporary script file\n const tempDir = '/tmp'\n const scriptPath = path.join(tempDir, `statusline-test-${Date.now()}.sh`)\n \n await fs.writeFile(scriptPath, script, { mode: 0o755 })\n \n // Generate mock input if not provided\n const input = mockData || generateMockClaudeInput()\n \n // Execute script\n const result = await executeScript(scriptPath, JSON.stringify(input))\n \n // Cleanup\n await fs.unlink(scriptPath).catch(() => {}) // Ignore cleanup errors\n \n const executionTime = Date.now() - startTime\n \n return {\n success: result.success,\n output: result.output,\n error: result.error,\n executionTime\n }\n \n } catch (error) {\n return {\n success: false,\n output: '',\n error: error instanceof Error ? error.message : String(error),\n executionTime: Date.now() - startTime\n }\n }\n}\n\nexport function generateMockClaudeInput(config?: Partial<StatuslineConfig>): any {\n return {\n session_id: \"test-session-123\",\n transcript_path: \"/home/user/.claude/conversations/test.jsonl\",\n cwd: \"/home/user/projects/my-project\",\n workspace: {\n current_dir: \"/home/user/projects/my-project\"\n },\n model: {\n id: \"claude-opus-4-1-20250805\",\n display_name: \"Opus 4.1\",\n version: \"20250805\"\n }\n }\n}\n\nexport function generateMockCcusageOutput(): any {\n return {\n blocks: [\n {\n id: \"2025-08-13T08:00:00.000Z\",\n startTime: \"2025-08-13T08:00:00.000Z\",\n endTime: \"2025-08-13T13:00:00.000Z\",\n usageLimitResetTime: \"2025-08-13T13:00:00.000Z\",\n actualEndTime: \"2025-08-13T09:30:34.698Z\",\n isActive: true,\n isGap: false,\n entries: 12,\n tokenCounts: {\n inputTokens: 1250,\n outputTokens: 2830,\n cacheCreationInputTokens: 15000,\n cacheReadInputTokens: 45000\n },\n totalTokens: 64080,\n costUSD: 3.42,\n models: [\"claude-opus-4-1-20250805\"],\n burnRate: {\n tokensPerMinute: 850.5,\n tokensPerMinuteForIndicator: 850,\n costPerHour: 12.45\n },\n projection: {\n totalTokens: 128000,\n totalCost: 6.84,\n remainingMinutes: 210\n }\n }\n ]\n }\n}\n\nasync function executeScript(scriptPath: string, input: string): Promise<{ success: boolean, output: string, error?: string }> {\n return new Promise((resolve) => {\n const process = spawn('bash', [scriptPath], {\n stdio: ['pipe', 'pipe', 'pipe']\n })\n \n let stdout = ''\n let stderr = ''\n \n process.stdout.on('data', (data) => {\n stdout += data.toString()\n })\n \n process.stderr.on('data', (data) => {\n stderr += data.toString()\n })\n \n process.on('close', (code) => {\n resolve({\n success: code === 0,\n output: stdout.trim(),\n error: stderr.trim() || undefined\n })\n })\n \n process.on('error', (err) => {\n resolve({\n success: false,\n output: '',\n error: err.message\n })\n })\n \n // Send input and close stdin\n process.stdin.write(input)\n process.stdin.end()\n \n // Timeout after 5 seconds\n setTimeout(() => {\n process.kill()\n resolve({\n success: false,\n output: stdout,\n error: 'Script execution timed out (5s)'\n })\n }, 5000)\n })\n}\n\nexport function analyzeTestResult(result: TestResult, config: StatuslineConfig): {\n performance: 'excellent' | 'good' | 'slow' | 'timeout'\n hasRequiredFeatures: boolean\n issues: string[]\n suggestions: string[]\n} {\n const issues: string[] = []\n const suggestions: string[] = []\n \n // Performance analysis\n let performance: 'excellent' | 'good' | 'slow' | 'timeout'\n if (result.executionTime > 1000) {\n performance = 'timeout'\n issues.push('Script execution is very slow (>1s)')\n } else if (result.executionTime > 500) {\n performance = 'slow'\n issues.push('Script execution is slow (>500ms)')\n } else if (result.executionTime > 100) {\n performance = 'good'\n } else {\n performance = 'excellent'\n }\n \n // Feature validation\n let hasRequiredFeatures = true\n \n if (config.features.includes('directory') && !result.output.includes('projects')) {\n hasRequiredFeatures = false\n issues.push('Directory feature not working properly')\n }\n \n if (config.features.includes('model') && !result.output.includes('Opus')) {\n hasRequiredFeatures = false\n issues.push('Model feature not working properly')\n }\n \n if (config.features.includes('git') && config.ccusageIntegration && !result.output.includes('git')) {\n suggestions.push('Git integration may require actual git repository')\n }\n \n // Error analysis\n if (result.error) {\n issues.push(`Script errors: ${result.error}`)\n }\n \n if (!result.success) {\n issues.push('Script failed to execute successfully')\n }\n \n // Performance suggestions\n if (config.features.length > 6) {\n suggestions.push('Consider reducing number of features for better performance')\n }\n \n if (config.ccusageIntegration && result.executionTime > 200) {\n suggestions.push('ccusage integration may slow down statusline - consider caching')\n }\n \n return {\n performance,\n hasRequiredFeatures,\n issues,\n suggestions\n }\n}","import { StatuslineConfig } from './prompts.js'\nimport { generateBashStatusline } from '../generators/bash-generator.js'\nimport { testStatuslineScript, generateMockClaudeInput, analyzeTestResult } from '../utils/tester.js'\nimport { promises as fs } from 'fs'\nimport chalk from 'chalk'\nimport ora from 'ora'\n\nexport async function previewCommand(scriptPath: string): Promise<void> {\n console.log(chalk.cyan('šŸ” Statusline Preview Mode\\n'))\n \n let script: string\n \n // Load existing statusline script\n try {\n const spinner = ora(`Loading statusline script from ${scriptPath}...`).start()\n script = await fs.readFile(scriptPath, 'utf-8')\n spinner.succeed('Script loaded!')\n \n // Try to extract config info from the script header\n const headerMatch = script.match(/# Theme: (\\w+) \\| Colors: (\\w+) \\| Features: ([^\\n]+)/i)\n if (headerMatch) {\n console.log(chalk.yellow('Detected Configuration:'))\n console.log(` Theme: ${headerMatch[1]}`)\n console.log(` Colors: ${headerMatch[2]}`) \n console.log(` Features: ${headerMatch[3]}\\n`)\n }\n \n // Extract generation info if available\n const generationMatch = script.match(/# Generated by cc-statusline.*\\n# Custom Claude Code statusline - Created: ([^\\n]+)/i)\n if (generationMatch) {\n console.log(chalk.gray(`Generated: ${generationMatch[1]}\\n`))\n }\n \n } catch (error) {\n console.error(chalk.red(`āŒ Failed to load script: ${error instanceof Error ? error.message : String(error)}`))\n return\n }\n \n // Test the script\n const testSpinner = ora('Testing statusline with mock data...').start()\n const mockInput = generateMockClaudeInput()\n \n console.log(chalk.gray('\\nMock Claude Code Input:'))\n console.log(chalk.gray(JSON.stringify(mockInput, null, 2)))\n \n const testResult = await testStatuslineScript(script, mockInput)\n \n if (testResult.success) {\n testSpinner.succeed(`Test completed in ${testResult.executionTime}ms`)\n \n console.log(chalk.green('\\nāœ… Statusline Output:'))\n console.log(chalk.white('━'.repeat(60)))\n console.log(testResult.output)\n console.log(chalk.white('━'.repeat(60)))\n \n // Basic performance analysis\n console.log(chalk.cyan(`\\nšŸ“Š Performance: ${getPerformanceEmoji(getPerformanceLevel(testResult.executionTime))} ${getPerformanceLevel(testResult.executionTime)} (${testResult.executionTime}ms)`))\n \n // Basic output validation\n if (testResult.output.includes('šŸ“') || testResult.output.includes('🌿') || testResult.output.includes('šŸ¤–')) {\n console.log(chalk.green('āœ… Statusline features appear to be working'))\n } else {\n console.log(chalk.yellow('āš ļø Basic features may not be displaying correctly'))\n }\n \n } else {\n testSpinner.fail('Test failed')\n console.error(chalk.red(`\\nāŒ Error: ${testResult.error}`))\n if (testResult.output) {\n console.log(chalk.gray('\\nPartial output:'))\n console.log(testResult.output)\n }\n }\n \n console.log(chalk.green('\\n✨ Preview complete! Use `cc-statusline init` to generate a new statusline.'))\n}\n\nfunction getPerformanceEmoji(performance: string): string {\n switch (performance) {\n case 'excellent': return 'šŸš€'\n case 'good': return 'āœ…'\n case 'slow': return 'āš ļø'\n case 'timeout': return '🐌'\n default: return 'ā“'\n }\n}\n\nfunction getPerformanceLevel(executionTime: number): string {\n if (executionTime > 1000) return 'timeout'\n if (executionTime > 500) return 'slow'\n if (executionTime > 100) return 'good'\n return 'excellent'\n}","import { Command } from 'commander'\nimport { initCommand } from './cli/commands.js'\nimport chalk from 'chalk'\n\n// Hard-code version to avoid bundling issues\nconst VERSION = '1.3.0'\n\nconst program = new Command()\n\nprogram\n .name('cc-statusline')\n .description('Interactive CLI tool for generating custom Claude Code statuslines')\n .version(VERSION)\n\nprogram\n .command('init')\n .description('Create a custom statusline with interactive prompts')\n .option('-o, --output <path>', 'Output path for statusline.sh', './.claude/statusline.sh')\n .option('--no-install', 'Don\\'t automatically install to .claude/statusline.sh')\n .action(initCommand)\n\nprogram\n .command('preview')\n .description('Preview existing statusline.sh with mock data')\n .argument('<script-path>', 'Path to statusline.sh file to preview')\n .action(async (scriptPath) => {\n const { previewCommand } = await import('./cli/preview.js')\n await previewCommand(scriptPath)\n })\n\nprogram\n .command('test')\n .description('Test statusline with real Claude Code JSON input')\n .option('-c, --config <path>', 'Configuration file to test')\n .action(() => {\n console.log(chalk.yellow('Test command coming soon!'))\n })\n\n// Show help if no command provided\nif (!process.argv.slice(2).length) {\n program.outputHelp()\n}\n\nprogram.parse(process.argv)","import { collectConfiguration, displayConfigSummary } from './prompts.js'\nimport { generateBashStatusline } from '../generators/bash-generator.js'\nimport { validateConfig } from '../utils/validator.js'\nimport { installStatusline } from '../utils/installer.js'\nimport chalk from 'chalk'\nimport ora from 'ora'\nimport path from 'path'\nimport os from 'os'\n\ninterface InitOptions {\n output?: string\n install?: boolean\n}\n\nexport async function initCommand(options: InitOptions): Promise<void> {\n try {\n const spinner = ora('Initializing statusline generator...').start()\n await new Promise(resolve => setTimeout(resolve, 500)) // Brief pause for UX\n spinner.stop()\n\n // Collect user configuration\n const config = await collectConfiguration()\n \n // Validate configuration\n const validation = validateConfig(config)\n if (!validation.isValid) {\n console.error(chalk.red('āŒ Configuration validation failed:'))\n validation.errors.forEach(error => console.error(chalk.red(` • ${error}`)))\n process.exit(1)\n }\n\n // Generate statusline script\n const generationSpinner = ora('Generating statusline script...').start()\n \n const script = generateBashStatusline(config)\n const filename = 'statusline.sh'\n \n generationSpinner.succeed('Statusline script generated!')\n\n // Show preview of what it will look like\n console.log(chalk.cyan('\\n✨ Your statusline will look like:'))\n console.log(chalk.white('━'.repeat(60)))\n \n // Generate preview using the test function\n const { testStatuslineScript, generateMockClaudeInput } = await import('../utils/tester.js')\n const mockInput = generateMockClaudeInput()\n const testResult = await testStatuslineScript(script, mockInput)\n \n if (testResult.success) {\n console.log(testResult.output)\n } else {\n console.log(chalk.gray('šŸ“ ~/projects/my-app 🌿 main šŸ¤– Claude šŸ’µ $2.48 ($12.50/h)'))\n console.log(chalk.gray('(Preview unavailable - will work when Claude Code runs it)'))\n }\n \n console.log(chalk.white('━'.repeat(60)))\n\n // Determine output path based on installation location\n const isGlobal = config.installLocation === 'global'\n const baseDir = isGlobal ? os.homedir() : '.'\n const outputPath = options.output || path.join(baseDir, '.claude', filename)\n const resolvedPath = path.resolve(outputPath)\n\n // Install the statusline\n if (options.install !== false) {\n console.log(chalk.cyan('\\nšŸ“¦ Installing statusline...'))\n \n try {\n await installStatusline(script, resolvedPath, config)\n \n console.log(chalk.green('\\nāœ… Statusline installed!'))\n console.log(chalk.green('\\nšŸŽ‰ Success! Your custom statusline is ready!'))\n console.log(chalk.cyan(`\\nšŸ“ ${isGlobal ? 'Global' : 'Project'} installation complete: ${chalk.white(resolvedPath)}`))\n console.log(chalk.cyan('\\nNext steps:'))\n console.log(chalk.white(' 1. Restart Claude Code to see your new statusline'))\n console.log(chalk.white(' 2. Usage statistics work via: npx ccusage@latest'))\n \n } catch (error) {\n console.log(chalk.red('\\nāŒ Failed to install statusline'))\n \n if (error instanceof Error && error.message === 'USER_CANCELLED_OVERWRITE') {\n console.log(chalk.yellow('\\nāš ļø Installation cancelled. Existing statusline.sh was not overwritten.'))\n } else if (error instanceof Error && error.message === 'SETTINGS_UPDATE_FAILED') {\n const commandPath = isGlobal ? '~/.claude/statusline.sh' : '.claude/statusline.sh'\n console.log(chalk.yellow('\\nāš ļø Settings.json could not be updated automatically.'))\n console.log(chalk.cyan('\\nManual Configuration Required:'))\n console.log(chalk.white(`Add this to your ${isGlobal ? '~/.claude' : '.claude'}/settings.json file:`))\n console.log(chalk.gray('\\n{'))\n console.log(chalk.gray(' \"statusLine\": {'))\n console.log(chalk.gray(' \"type\": \"command\",'))\n console.log(chalk.gray(` \"command\": \"${commandPath}\",`))\n console.log(chalk.gray(' \"padding\": 0'))\n console.log(chalk.gray(' }'))\n console.log(chalk.gray('}'))\n console.log(chalk.cyan(`\\nšŸ“ Statusline script saved to: ${chalk.white(resolvedPath)}`))\n } else {\n console.error(chalk.red(`Error: ${error instanceof Error ? error.message : String(error)}`))\n console.log(chalk.cyan(`\\nšŸ“ You can manually save the script to: ${chalk.white(resolvedPath)}`))\n }\n }\n } else {\n // Just display where to save it\n console.log(chalk.green('\\nāœ… Statusline generated successfully!'))\n console.log(chalk.cyan(`\\nšŸ“ Save this script to: ${chalk.white(resolvedPath)}`))\n console.log(chalk.cyan('\\nThen restart Claude Code to see your new statusline.'))\n }\n\n } catch (error) {\n console.error(chalk.red('āŒ An error occurred:'))\n console.error(chalk.red(error instanceof Error ? error.message : String(error)))\n process.exit(1)\n }\n}","import inquirer from 'inquirer'\n\nexport interface StatuslineConfig {\n features: string[]\n runtime: 'bash' | 'python' | 'node'\n colors: boolean\n theme: 'minimal' | 'detailed' | 'compact'\n ccusageIntegration: boolean\n logging: boolean\n customEmojis: boolean\n installLocation?: 'global' | 'project'\n}\n\nexport async function collectConfiguration(): Promise<StatuslineConfig> {\n console.log('šŸš€ Welcome to cc-statusline! Let\\'s create your custom Claude Code statusline.\\n')\n console.log('✨ All features are enabled by default. Use ↑/↓ arrows to navigate, SPACE to toggle, ENTER to continue.\\n')\n \n const config = await inquirer.prompt([\n {\n type: 'checkbox',\n name: 'features',\n message: 'Select statusline features (scroll down for more options):',\n choices: [\n { name: 'šŸ“ Working Directory', value: 'directory', checked: true },\n { name: '🌿 Git Branch', value: 'git', checked: true },\n { name: 'šŸ¤– Model Name & Version', value: 'model', checked: true },\n { name: '🧠 Context Remaining', value: 'context', checked: true },\n { name: 'šŸ’µ Usage & Cost', value: 'usage', checked: true },\n { name: 'āŒ› Session Time Remaining', value: 'session', checked: true },\n { name: 'šŸ“Š Token Statistics', value: 'tokens', checked: true },\n { name: '⚔ Burn Rate (tokens/min)', value: 'burnrate', checked: true }\n ],\n validate: (answer: string[]) => {\n if (answer.length < 1) {\n return 'You must choose at least one feature.'\n }\n return true\n },\n pageSize: 10\n },\n {\n type: 'confirm',\n name: 'colors',\n message: '\\nšŸŽØ Enable modern color scheme and emojis?',\n default: true\n },\n {\n type: 'confirm',\n name: 'logging',\n message: '\\nšŸ“ Enable debug logging to .claude/statusline.log?',\n default: false\n },\n {\n type: 'list',\n name: 'installLocation',\n message: '\\nšŸ“ Where would you like to install the statusline?',\n choices: [\n { name: 'šŸ  Global (~/.claude) - Use across all projects', value: 'global' },\n { name: 'šŸ“‚ Project (./.claude) - Only for this project', value: 'project' }\n ],\n default: 'project'\n }\n ])\n\n // Set intelligent defaults\n return {\n features: config.features,\n runtime: 'bash',\n colors: config.colors,\n theme: 'detailed',\n ccusageIntegration: true, // Always enabled since npx works\n logging: config.logging,\n customEmojis: false,\n installLocation: config.installLocation\n } as StatuslineConfig\n}\n\nexport function displayConfigSummary(config: StatuslineConfig): void {\n console.log('\\nāœ… Configuration Summary:')\n console.log(` Runtime: ${config.runtime}`)\n console.log(` Theme: ${config.theme}`)\n console.log(` Colors: ${config.colors ? 'āœ…' : 'āŒ'}`)\n console.log(` Features: ${config.features.join(', ')}`)\n \n if (config.ccusageIntegration) {\n console.log(' šŸ“Š ccusage integration enabled')\n }\n \n if (config.logging) {\n console.log(' šŸ“ Debug logging enabled')\n }\n \n console.log('')\n}","import { StatuslineConfig } from '../cli/prompts.js'\nimport { generateColorBashCode, generateBasicColors } from '../features/colors.js'\nimport { generateGitBashCode, generateGitDisplayCode, generateGitUtilities } from '../features/git.js'\nimport { generateUsageBashCode, generateUsageDisplayCode, generateUsageUtilities } from '../features/usage.js'\n\n// Hard-code version to avoid bundling issues\nconst VERSION = '1.3.0'\n\nexport function generateBashStatusline(config: StatuslineConfig): string {\n const hasGit = config.features.includes('git')\n const hasUsage = config.features.some(f => ['usage', 'session', 'tokens', 'burnrate'].includes(f))\n const hasDirectory = config.features.includes('directory')\n const hasModel = config.features.includes('model')\n const hasContext = config.features.includes('context')\n\n // Build usage feature config\n const usageConfig = {\n enabled: hasUsage && config.ccusageIntegration,\n showCost: config.features.includes('usage'),\n showTokens: config.features.includes('tokens'),\n showBurnRate: config.features.includes('burnrate'),\n showSession: config.features.includes('session'),\n showProgressBar: config.theme !== 'minimal' && config.features.includes('session')\n }\n\n // Build git feature config\n const gitConfig = {\n enabled: hasGit,\n showBranch: hasGit,\n showChanges: false, // Removed delta changes per user request\n compactMode: config.theme === 'compact'\n }\n\n const timestamp = new Date().toISOString()\n const script = `#!/bin/bash\n# Generated by cc-statusline v${VERSION} (https://www.npmjs.com/package/@chongdashu/cc-statusline)\n# Custom Claude Code statusline - Created: ${timestamp}\n# Theme: ${config.theme} | Colors: ${config.colors} | Features: ${config.features.join(', ')}\n\ninput=$(cat)\n${config.logging ? generateLoggingCode() : ''}\n${generateColorBashCode({ enabled: config.colors, theme: config.theme })}\n${config.colors ? generateBasicColors() : ''}\n${hasUsage ? generateUsageUtilities() : ''}\n${hasGit ? generateGitUtilities() : ''}\n${generateBasicDataExtraction(hasDirectory, hasModel, hasContext)}\n${hasGit ? generateGitBashCode(gitConfig, config.colors) : ''}\n${hasContext ? generateContextBashCode(config.colors) : ''}\n${hasUsage ? generateUsageBashCode(usageConfig, config.colors) : ''}\n${config.logging ? generateLoggingOutput() : ''}\n${generateDisplaySection(config, gitConfig, usageConfig)}\n`\n\n return script.replace(/\\n\\n\\n+/g, '\\n\\n').trim() + '\\n'\n}\n\nfunction generateLoggingCode(): string {\n return `\n# Get the directory where this statusline script is located\nSCRIPT_DIR=\"$(cd \"$(dirname \"\\${BASH_SOURCE[0]}\")\" && pwd)\"\nLOG_FILE=\"\\${SCRIPT_DIR}/statusline.log\"\nTIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')\n\n# ---- logging ----\n{\n echo \"[$TIMESTAMP] Status line triggered with input:\"\n (echo \"$input\" | jq . 2>/dev/null) || echo \"$input\"\n echo \"---\"\n} >> \"$LOG_FILE\" 2>/dev/null\n`\n}\n\nfunction generateBasicDataExtraction(hasDirectory: boolean, hasModel: boolean, hasContext: boolean): string {\n return `\n# ---- basics ----\nif command -v jq >/dev/null 2>&1; then${hasDirectory ? `\n current_dir=$(echo \"$input\" | jq -r '.workspace.current_dir // .cwd // \"unknown\"' 2>/dev/null | sed \"s|^$HOME|~|g\")` : ''}${hasModel ? `\n model_name=$(echo \"$input\" | jq -r '.model.display_name // \"Claude\"' 2>/dev/null)\n model_version=$(echo \"$input\" | jq -r '.model.version // \"\"' 2>/dev/null)` : ''}${hasContext ? `\n session_id=$(echo \"$input\" | jq -r '.session_id // \"\"' 2>/dev/null)` : ''}\n cc_version=$(echo \"$input\" | jq -r '.version // \"\"' 2>/dev/null)\n output_style=$(echo \"$input\" | jq -r '.output_style.name // \"\"' 2>/dev/null)\nelse${hasDirectory ? `\n current_dir=\"unknown\"` : ''}${hasModel ? `\n model_name=\"Claude\"; model_version=\"\"` : ''}${hasContext ? `\n session_id=\"\"` : ''}\n cc_version=\"\"\n output_style=\"\"\nfi\n`\n}\n\nfunction generateContextBashCode(colors: boolean): string {\n return `\n# ---- context window calculation ----\ncontext_pct=\"\"\ncontext_color() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[1;37m'; fi; } # default white\n\n# Determine max context based on model\nget_max_context() {\n local model_name=\"$1\"\n case \"$model_name\" in\n *\"Opus 4\"*|*\"opus 4\"*|*\"Opus\"*|*\"opus\"*)\n echo \"200000\" # 200K for all Opus versions\n ;;\n *\"Sonnet 4\"*|*\"sonnet 4\"*|*\"Sonnet 3.5\"*|*\"sonnet 3.5\"*|*\"Sonnet\"*|*\"sonnet\"*)\n echo \"200000\" # 200K for Sonnet 3.5+ and 4.x\n ;;\n *\"Haiku 3.5\"*|*\"haiku 3.5\"*|*\"Haiku 4\"*|*\"haiku 4\"*|*\"Haiku\"*|*\"haiku\"*)\n echo \"200000\" # 200K for modern Haiku\n ;;\n *\"Claude 3 Haiku\"*|*\"claude 3 haiku\"*)\n echo \"100000\" # 100K for original Claude 3 Haiku\n ;;\n *)\n echo \"200000\" # Default to 200K\n ;;\n esac\n}\n\nif [ -n \"$session_id\" ] && command -v jq >/dev/null 2>&1; then\n MAX_CONTEXT=$(get_max_context \"$model_name\")\n \n # Convert current dir to session file path\n project_dir=$(echo \"$current_dir\" | sed \"s|~|$HOME|g\" | sed 's|/|-|g' | sed 's|^-||')\n session_file=\"$HOME/.claude/projects/-\\${project_dir}/\\${session_id}.jsonl\"\n \n if [ -f \"$session_file\" ]; then\n # Get the latest input token count from the session file\n latest_tokens=$(tail -20 \"$session_file\" | jq -r 'select(.message.usage) | .message.usage | ((.input_tokens // 0) + (.cache_read_input_tokens // 0))' 2>/dev/null | tail -1)\n \n if [ -n \"$latest_tokens\" ] && [ \"$latest_tokens\" -gt 0 ]; then\n context_used_pct=$(( latest_tokens * 100 / MAX_CONTEXT ))\n context_remaining_pct=$(( 100 - context_used_pct ))\n \n # Set color based on remaining percentage\n if [ \"$context_remaining_pct\" -le 20 ]; then\n context_color() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[38;5;203m'; fi; } # coral red\n elif [ \"$context_remaining_pct\" -le 40 ]; then\n context_color() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[38;5;215m'; fi; } # peach\n else\n context_color() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[38;5;158m'; fi; } # mint green\n fi\n \n context_pct=\"\\${context_remaining_pct}%\"\n fi\n fi\nfi\n`\n}\n\nfunction generateLoggingOutput(): string {\n return `\n# ---- log extracted data ----\n{\n echo \"[\\$TIMESTAMP] Extracted: dir=\\${current_dir:-}, model=\\${model_name:-}, version=\\${model_version:-}, git=\\${git_branch:-}, context=\\${context_pct:-}, cost=\\${cost_usd:-}, cost_ph=\\${cost_per_hour:-}, tokens=\\${tot_tokens:-}, tpm=\\${tpm:-}, session_pct=\\${session_pct:-}\"\n} >> \"$LOG_FILE\" 2>/dev/null\n`\n}\n\nfunction generateDisplaySection(config: StatuslineConfig, gitConfig: any, usageConfig: any): string {\n const emojis = config.colors && !config.customEmojis\n\n return `\n# ---- render statusline ----\n# Line 1: Core info (directory, git, model, claude code version, output style)\n${config.features.includes('directory') ? `printf 'šŸ“ %s%s%s' \"$(dir_color)\" \"$current_dir\" \"$(rst)\"` : ''}${gitConfig.enabled ? `\nif [ -n \"$git_branch\" ]; then\n printf ' 🌿 %s%s%s' \"$(git_color)\" \"$git_branch\" \"$(rst)\"\nfi` : ''}${config.features.includes('model') ? `\nprintf ' šŸ¤– %s%s%s' \"$(model_color)\" \"$model_name\" \"$(rst)\"\nif [ -n \"$model_version\" ] && [ \"$model_version\" != \"null\" ]; then\n printf ' šŸ·ļø %s%s%s' \"$(version_color)\" \"$model_version\" \"$(rst)\"\nfi` : ''}\nif [ -n \"$cc_version\" ] && [ \"$cc_version\" != \"null\" ]; then\n printf ' šŸ“Ÿ %sv%s%s' \"$(cc_version_color)\" \"$cc_version\" \"$(rst)\"\nfi\nif [ -n \"$output_style\" ] && [ \"$output_style\" != \"null\" ]; then\n printf ' šŸŽØ %s%s%s' \"$(style_color)\" \"$output_style\" \"$(rst)\"\nfi\n\n# Line 2: Context and session time\nline2=\"\"${config.features.includes('context') ? `\nif [ -n \"$context_pct\" ]; then\n context_bar=$(progress_bar \"$context_remaining_pct\" 10)\n line2=\"🧠 $(context_color)Context Remaining: \\${context_pct} [\\${context_bar}]$(rst)\"\nfi` : ''}${usageConfig.showSession ? `\nif [ -n \"$session_txt\" ]; then\n if [ -n \"$line2\" ]; then\n line2=\"$line2 āŒ› $(session_color)\\${session_txt}$(rst) $(session_color)[\\${session_bar}]$(rst)\"\n else\n line2=\"āŒ› $(session_color)\\${session_txt}$(rst) $(session_color)[\\${session_bar}]$(rst)\"\n fi\nfi` : ''}${config.features.includes('context') ? `\nif [ -z \"$line2\" ] && [ -z \"$context_pct\" ]; then\n line2=\"🧠 $(context_color)Context Remaining: TBD$(rst)\"\nfi` : ''}\n\n# Line 3: Cost and usage analytics\nline3=\"\"${usageConfig.showCost ? `\nif [ -n \"$cost_usd\" ] && [[ \"$cost_usd\" =~ ^[0-9.]+$ ]]; then${usageConfig.showBurnRate ? `\n if [ -n \"$cost_per_hour\" ] && [[ \"$cost_per_hour\" =~ ^[0-9.]+$ ]]; then\n cost_per_hour_formatted=$(printf '%.2f' \"$cost_per_hour\")\n line3=\"šŸ’° $(cost_color)\\\\$$(printf '%.2f' \"$cost_usd\")$(rst) ($(burn_color)\\\\$\\${cost_per_hour_formatted}/h$(rst))\"\n else\n line3=\"šŸ’° $(cost_color)\\\\$$(printf '%.2f' \"$cost_usd\")$(rst)\"\n fi` : `\n line3=\"šŸ’° $(cost_color)\\\\$$(printf '%.2f' \"$cost_usd\")$(rst)\"`}\nfi` : ''}${usageConfig.showTokens ? `\nif [ -n \"$tot_tokens\" ] && [[ \"$tot_tokens\" =~ ^[0-9]+$ ]]; then${usageConfig.showBurnRate ? `\n if [ -n \"$tpm\" ] && [[ \"$tpm\" =~ ^[0-9.]+$ ]]; then\n tpm_formatted=$(printf '%.0f' \"$tpm\")\n if [ -n \"$line3\" ]; then\n line3=\"$line3 šŸ“Š $(usage_color)\\${tot_tokens} tok (\\${tpm_formatted} tpm)$(rst)\"\n else\n line3=\"šŸ“Š $(usage_color)\\${tot_tokens} tok (\\${tpm_formatted} tpm)$(rst)\"\n fi\n else\n if [ -n \"$line3\" ]; then\n line3=\"$line3 šŸ“Š $(usage_color)\\${tot_tokens} tok$(rst)\"\n else\n line3=\"šŸ“Š $(usage_color)\\${tot_tokens} tok$(rst)\"\n fi\n fi` : `\n if [ -n \"$line3\" ]; then\n line3=\"$line3 šŸ“Š $(usage_color)\\${tot_tokens} tok$(rst)\"\n else\n line3=\"šŸ“Š $(usage_color)\\${tot_tokens} tok$(rst)\"\n fi`}\nfi` : ''}\n\n# Print lines\nif [ -n \"$line2\" ]; then\n printf '\\\\n%s' \"$line2\"\nfi\nif [ -n \"$line3\" ]; then\n printf '\\\\n%s' \"$line3\"\nfi\nprintf '\\\\n'`\n}","export interface ColorConfig {\n enabled: boolean\n theme: 'minimal' | 'detailed' | 'compact'\n}\n\nexport function generateColorBashCode(config: ColorConfig): string {\n if (!config.enabled) {\n return `\n# ---- color helpers (disabled) ----\nuse_color=0\nC() { :; }\nRST() { :; }\n`\n }\n\n return `\n# ---- color helpers (force colors for Claude Code) ----\nuse_color=1\n[ -n \"$NO_COLOR\" ] && use_color=0\n\nC() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[%sm' \"$1\"; fi; }\nRST() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[0m'; fi; }\n`\n}\n\nexport function generateBasicColors(): string {\n return `\n# ---- modern sleek colors ----\ndir_color() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[38;5;117m'; fi; } # sky blue\nmodel_color() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[38;5;147m'; fi; } # light purple \nversion_color() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[38;5;180m'; fi; } # soft yellow\ncc_version_color() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[38;5;249m'; fi; } # light gray\nstyle_color() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[38;5;245m'; fi; } # gray\nrst() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[0m'; fi; }\n`\n}\n\nexport const COLOR_CODES = {\n // Basic colors\n BLACK: '30',\n RED: '31', \n GREEN: '32',\n YELLOW: '33',\n BLUE: '34',\n MAGENTA: '35',\n CYAN: '36',\n WHITE: '37',\n \n // Bright colors (bold)\n BRIGHT_BLACK: '1;30',\n BRIGHT_RED: '1;31',\n BRIGHT_GREEN: '1;32', \n BRIGHT_YELLOW: '1;33',\n BRIGHT_BLUE: '1;34',\n BRIGHT_MAGENTA: '1;35',\n BRIGHT_CYAN: '1;36',\n BRIGHT_WHITE: '1;37',\n \n // Reset\n RESET: '0'\n} as const\n\nexport function getThemeColors(theme: 'minimal' | 'detailed' | 'compact') {\n switch (theme) {\n case 'minimal':\n return {\n directory: COLOR_CODES.CYAN,\n git: COLOR_CODES.GREEN,\n model: COLOR_CODES.MAGENTA,\n usage: COLOR_CODES.YELLOW,\n session: COLOR_CODES.BLUE\n }\n case 'detailed':\n return {\n directory: COLOR_CODES.BRIGHT_CYAN,\n git: COLOR_CODES.BRIGHT_GREEN,\n model: COLOR_CODES.BRIGHT_MAGENTA,\n usage: COLOR_CODES.BRIGHT_YELLOW,\n session: COLOR_CODES.BRIGHT_BLUE\n }\n case 'compact':\n return {\n directory: COLOR_CODES.CYAN,\n git: COLOR_CODES.GREEN,\n model: COLOR_CODES.BLUE,\n usage: COLOR_CODES.YELLOW,\n session: COLOR_CODES.RED\n }\n }\n}","export interface GitFeature {\n enabled: boolean\n showBranch: boolean\n showChanges: boolean\n compactMode: boolean\n}\n\nexport function generateGitBashCode(config: GitFeature, colors: boolean): string {\n if (!config.enabled) return ''\n\n const colorCode = colors ? `\n# ---- git colors ----\ngit_color() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[38;5;150m'; fi; } # soft green\nrst() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[0m'; fi; }\n` : `\ngit_color() { :; }\nrst() { :; }\n`\n\n return `${colorCode}\n# ---- git ----\ngit_branch=\"\"\nif git rev-parse --git-dir >/dev/null 2>&1; then\n git_branch=$(git branch --show-current 2>/dev/null || git rev-parse --short HEAD 2>/dev/null)\nfi`\n}\n\nexport function generateGitDisplayCode(config: GitFeature, colors: boolean, emojis: boolean): string {\n if (!config.enabled) return ''\n\n const branchEmoji = emojis ? '🌿' : 'git:'\n\n let displayCode = `\n# git display\nif [ -n \"$git_branch\" ]; then\n printf ' ${branchEmoji} %s%s%s' \"$(git_color)\" \"$git_branch\" \"$(rst)\"\nfi`\n\n return displayCode\n}\n\nexport function generateGitUtilities(): string {\n return `\n# git utilities\nnum_or_zero() { v=\"$1\"; [[ \"$v\" =~ ^[0-9]+$ ]] && echo \"$v\" || echo 0; }`\n}","export interface UsageFeature {\n enabled: boolean\n showCost: boolean\n showTokens: boolean\n showBurnRate: boolean\n showSession: boolean\n showProgressBar: boolean\n}\n\nexport function generateUsageBashCode(config: UsageFeature, colors: boolean): string {\n if (!config.enabled) return ''\n\n const colorCode = colors ? `\n# ---- usage colors ----\nusage_color() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[38;5;189m'; fi; } # lavender\ncost_color() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[38;5;222m'; fi; } # light gold\nburn_color() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[38;5;220m'; fi; } # bright gold\nsession_color() { \n rem_pct=$(( 100 - session_pct ))\n if (( rem_pct <= 10 )); then SCLR='38;5;210' # light pink\n elif (( rem_pct <= 25 )); then SCLR='38;5;228' # light yellow \n else SCLR='38;5;194'; fi # light green\n if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[%sm' \"$SCLR\"; fi\n}\n` : `\nusage_color() { :; }\ncost_color() { :; }\nburn_color() { :; }\nsession_color() { :; }\n`\n\n return `${colorCode}\n# ---- cost and usage extraction ----\nsession_txt=\"\"; session_pct=0; session_bar=\"\"\ncost_usd=\"\"; cost_per_hour=\"\"; tpm=\"\"; tot_tokens=\"\"\n\n# Extract cost data from Claude Code input\nif command -v jq >/dev/null 2>&1; then\n # Get cost data from Claude Code's input\n cost_usd=$(echo \"$input\" | jq -r '.cost.total_cost_usd // empty' 2>/dev/null)\n total_duration_ms=$(echo \"$input\" | jq -r '.cost.total_duration_ms // empty' 2>/dev/null)\n \n # Calculate burn rate ($/hour) from cost and duration\n if [ -n \"$cost_usd\" ] && [ -n \"$total_duration_ms\" ] && [ \"$total_duration_ms\" -gt 0 ]; then\n # Convert ms to hours and calculate rate\n cost_per_hour=$(echo \"$cost_usd $total_duration_ms\" | awk '{printf \"%.2f\", $1 * 3600000 / $2}')\n fi\nfi\n\n# Get token data and session info from ccusage if available\nif command -v ccusage >/dev/null 2>&1 && command -v jq >/dev/null 2>&1; then\n blocks_output=\"\"\n \n # Try ccusage with timeout for token data and session info\n if command -v timeout >/dev/null 2>&1; then\n blocks_output=$(timeout 5s ccusage blocks --json 2>/dev/null)\n elif command -v gtimeout >/dev/null 2>&1; then\n # macOS with coreutils installed\n blocks_output=$(gtimeout 5s ccusage blocks --json 2>/dev/null)\n else\n # No timeout available, run directly (ccusage should be fast)\n blocks_output=$(ccusage blocks --json 2>/dev/null)\n fi\n if [ -n \"$blocks_output\" ]; then\n active_block=$(echo \"$blocks_output\" | jq -c '.blocks[] | select(.isActive == true)' 2>/dev/null | head -n1)\n if [ -n \"$active_block\" ]; then${config.showTokens ? `\n # Get token count from ccusage\n tot_tokens=$(echo \"$active_block\" | jq -r '.totalTokens // empty')` : ''}${config.showBurnRate && config.showTokens ? `\n # Get tokens per minute from ccusage\n tpm=$(echo \"$active_block\" | jq -r '.burnRate.tokensPerMinute // empty')` : ''}${config.showSession || config.showProgressBar ? `\n \n # Session time calculation from ccusage\n reset_time_str=$(echo \"$active_block\" | jq -r '.usageLimitResetTime // .endTime // empty')\n start_time_str=$(echo \"$active_block\" | jq -r '.startTime // empty')\n \n if [ -n \"$reset_time_str\" ] && [ -n \"$start_time_str\" ]; then\n start_sec=$(to_epoch \"$start_time_str\"); end_sec=$(to_epoch \"$reset_time_str\"); now_sec=$(date +%s)\n total=$(( end_sec - start_sec )); (( total<1 )) && total=1\n elapsed=$(( now_sec - start_sec )); (( elapsed<0 ))&&elapsed=0; (( elapsed>total ))&&elapsed=$total\n session_pct=$(( elapsed * 100 / total ))\n remaining=$(( end_sec - now_sec )); (( remaining<0 )) && remaining=0\n rh=$(( remaining / 3600 )); rm=$(( (remaining % 3600) / 60 ))\n end_hm=$(fmt_time_hm \"$end_sec\")${config.showSession ? `\n session_txt=\"$(printf '%dh %dm until reset at %s (%d%%)' \"$rh\" \"$rm\" \"$end_hm\" \"$session_pct\")\"` : ''}${config.showProgressBar ? `\n session_bar=$(progress_bar \"$session_pct\" 10)` : ''}\n fi` : ''}\n fi\n fi\nfi`\n}\n\nexport function generateUsageUtilities(): string {\n return `\n# ---- time helpers ----\nto_epoch() {\n ts=\"$1\"\n if command -v gdate >/dev/null 2>&1; then gdate -d \"$ts\" +%s 2>/dev/null && return; fi\n date -u -j -f \"%Y-%m-%dT%H:%M:%S%z\" \"\\${ts/Z/+0000}\" +%s 2>/dev/null && return\n python3 - \"$ts\" <<'PY' 2>/dev/null\nimport sys, datetime\ns=sys.argv[1].replace('Z','+00:00')\nprint(int(datetime.datetime.fromisoformat(s).timestamp()))\nPY\n}\n\nfmt_time_hm() {\n epoch=\"$1\"\n if date -r 0 +%s >/dev/null 2>&1; then date -r \"$epoch\" +\"%H:%M\"; else date -d \"@$epoch\" +\"%H:%M\"; fi\n}\n\nprogress_bar() {\n pct=\"\\${1:-0}\"; width=\"\\${2:-10}\"\n [[ \"$pct\" =~ ^[0-9]+$ ]] || pct=0; ((pct<0))&&pct=0; ((pct>100))&&pct=100\n filled=$(( pct * width / 100 )); empty=$(( width - filled ))\n printf '%*s' \"$filled\" '' | tr ' ' '='\n printf '%*s' \"$empty\" '' | tr ' ' '-'\n}`\n}\n\nexport function generateUsageDisplayCode(config: UsageFeature, colors: boolean, emojis: boolean): string {\n if (!config.enabled) return ''\n\n let displayCode = ''\n\n if (config.showSession) {\n const sessionEmoji = emojis ? 'āŒ›' : 'session:'\n displayCode += `\n# session time\nif [ -n \"$session_txt\" ]; then\n printf ' ${sessionEmoji} %s%s%s' \"$(session_color)\" \"$session_txt\" \"$(rst)\"${config.showProgressBar ? `\n printf ' %s[%s]%s' \"$(session_color)\" \"$session_bar\" \"$(rst)\"` : ''}\nfi`\n }\n\n if (config.showCost) {\n const costEmoji = emojis ? 'šŸ’µ' : '$'\n displayCode += `\n# cost\nif [ -n \"$cost_usd\" ] && [[ \"$cost_usd\" =~ ^[0-9.]+$ ]]; then\n if [ -n \"$cost_per_hour\" ] && [[ \"$cost_per_hour\" =~ ^[0-9.]+$ ]]; then\n printf ' ${costEmoji} %s$%.2f ($%.2f/h)%s' \"$(cost_color)\" \"$cost_usd\" \"$cost_per_hour\" \"$(rst)\"\n else\n printf ' ${costEmoji} %s$%.2f%s' \"$(cost_color)\" \"$cost_usd\" \"$(rst)\"\n fi\nfi`\n }\n\n if (config.showTokens) {\n const tokenEmoji = emojis ? 'šŸ“Š' : 'tok:'\n displayCode += `\n# tokens\nif [ -n \"$tot_tokens\" ] && [[ \"$tot_tokens\" =~ ^[0-9]+$ ]]; then\n if [ -n \"$tpm\" ] && [[ \"$tpm\" =~ ^[0-9.]+$ ]] && ${config.showBurnRate ? 'true' : 'false'}; then\n printf ' ${tokenEmoji} %s%s tok (%.0f tpm)%s' \"$(usage_color)\" \"$tot_tokens\" \"$tpm\" \"$(rst)\"\n else\n printf ' ${tokenEmoji} %s%s tok%s' \"$(usage_color)\" \"$tot_tokens\" \"$(rst)\"\n fi\nfi`\n }\n\n return displayCode\n}","import { StatuslineConfig } from '../cli/prompts.js'\n\nexport interface ValidationResult {\n isValid: boolean\n errors: string[]\n warnings: string[]\n}\n\nexport function validateConfig(config: StatuslineConfig): ValidationResult {\n const errors: string[] = []\n const warnings: string[] = []\n\n // Validate features\n if (!config.features || config.features.length === 0) {\n errors.push('At least one display feature must be selected')\n }\n\n // Validate runtime\n if (!['bash', 'python', 'node'].includes(config.runtime)) {\n errors.push(`Invalid runtime: ${config.runtime}`)\n }\n\n // Validate theme\n if (!['minimal', 'detailed', 'compact'].includes(config.theme)) {\n errors.push(`Invalid theme: ${config.theme}`)\n }\n\n // Check for usage features without ccusage integration\n const usageFeatures = ['usage', 'session', 'tokens', 'burnrate']\n const hasUsageFeatures = config.features.some(f => usageFeatures.includes(f))\n \n if (hasUsageFeatures && !config.ccusageIntegration) {\n warnings.push('Usage features selected but ccusage integration is disabled. Some features may not work properly.')\n }\n\n // Warn about performance with many features\n if (config.features.length > 5) {\n warnings.push('Many features selected. This may impact statusline performance.')\n }\n\n // Validate color/emoji consistency\n if (config.customEmojis && !config.colors) {\n warnings.push('Custom emojis enabled but colors disabled. Visual distinction may be limited.')\n }\n\n return {\n isValid: errors.length === 0,\n errors,\n warnings\n }\n}\n\nexport function validateDependencies(): {\n jq: boolean\n git: boolean\n ccusage: boolean\n python?: boolean\n node?: boolean\n} {\n // This would check system dependencies\n // For now, return placeholder\n return {\n jq: true, // Would check: command -v jq >/dev/null 2>&1\n git: true, // Would check: command -v git >/dev/null 2>&1\n ccusage: false, // Would check: command -v ccusage >/dev/null 2>&1\n python: true, // Would check: command -v python3 >/dev/null 2>&1\n node: true // Would check: command -v node >/dev/null 2>&1\n }\n}","import { StatuslineConfig } from '../cli/prompts.js'\nimport { promises as fs } from 'fs'\nimport path from 'path'\nimport os from 'os'\nimport inquirer from 'inquirer'\n\nexport async function installStatusline(\n script: string,\n outputPath: string,\n config: StatuslineConfig\n): Promise<void> {\n try {\n // Determine the target directory based on install location\n const isGlobal = config.installLocation === 'global'\n const claudeDir = isGlobal ? path.join(os.homedir(), '.claude') : './.claude'\n const scriptPath = path.join(claudeDir, 'statusline.sh')\n \n // Ensure the directory exists\n await fs.mkdir(claudeDir, { recursive: true })\n\n // Check if statusline.sh already exists\n let shouldWrite = true\n try {\n await fs.access(scriptPath)\n // File exists, ask for confirmation\n const { confirmOverwrite } = await inquirer.prompt([{\n type: 'confirm',\n name: 'confirmOverwrite',\n message: `āš ļø ${isGlobal ? 'Global' : 'Project'} statusline.sh already exists. Overwrite?`,\n default: false\n }])\n shouldWrite = confirmOverwrite\n } catch {\n // File doesn't exist, proceed\n }\n\n if (shouldWrite) {\n // Write the script\n await fs.writeFile(scriptPath, script, { mode: 0o755 })\n } else {\n throw new Error('USER_CANCELLED_OVERWRITE')\n }\n\n // Update settings.json safely\n await updateSettingsJson(claudeDir, 'statusline.sh', isGlobal)\n\n // Note: statusline-config.json removed per user feedback - not needed\n // The statusline script contains all necessary configuration info\n\n } catch (error) {\n throw new Error(`Failed to install statusline: ${error instanceof Error ? error.message : String(error)}`)\n }\n}\n\nasync function updateSettingsJson(claudeDir: string, scriptName: string, isGlobal: boolean): Promise<void> {\n const settingsPath = path.join(claudeDir, 'settings.json')\n \n try {\n let settings: any = {}\n let existingStatusLine: any = null\n \n // Try to read existing settings\n try {\n const settingsContent = await fs.readFile(settingsPath, 'utf-8')\n settings = JSON.parse(settingsContent)\n existingStatusLine = settings.statusLine\n } catch {\n // File doesn't exist or invalid JSON, start fresh\n }\n\n // Check if statusLine already exists\n if (existingStatusLine && existingStatusLine.command) {\n // Only update if it's a statusline.sh command or user confirms\n const isOurStatusline = existingStatusLine.command?.includes('statusline.sh')\n \n if (!isOurStatusline) {\n // There's a different statusline configured, ask user\n const { confirmReplace } = await inquirer.prompt([{\n type: 'confirm',\n name: 'confirmReplace',\n message: `āš ļø ${isGlobal ? 'Global' : 'Project'} settings.json already has a statusLine configured (${existingStatusLine.command}). Replace it?`,\n default: false\n }])\n \n if (!confirmReplace) {\n console.warn('\\nāš ļø Statusline script was saved but settings.json was not updated.')\n console.warn(' Your existing statusLine configuration was preserved.')\n return\n }\n }\n }\n\n // Update statusLine configuration\n const commandPath = isGlobal ? `~/.claude/${scriptName}` : `.claude/${scriptName}`\n settings.statusLine = {\n type: 'command',\n command: commandPath,\n padding: 0\n }\n\n // Write updated settings\n await fs.writeFile(settingsPath, JSON.stringify(settings, null, 2))\n \n } catch (error) {\n // Settings update failed, but don't fail the entire installation\n console.warn(`Warning: Could not update settings.json: ${error instanceof Error ? error.message : String(error)}`)\n throw new Error('SETTINGS_UPDATE_FAILED') // Signal that manual config is needed\n }\n}\n\nexport async function checkClaudeCodeSetup(): Promise<{\n hasClaudeDir: boolean\n hasSettings: boolean\n currentStatusline?: string\n}> {\n const claudeDir = './.claude'\n const settingsPath = path.join(claudeDir, 'settings.json')\n \n try {\n const dirExists = await fs.access(claudeDir).then(() => true).catch(() => false)\n const settingsExists = await fs.access(settingsPath).then(() => true).catch(() => false)\n \n let currentStatusline: string | undefined\n \n if (settingsExists) {\n try {\n const settings = JSON.parse(await fs.readFile(settingsPath, 'utf-8'))\n currentStatusline = settings.statusLine?.command\n } catch {\n // Ignore JSON parse errors\n }\n }\n \n return {\n hasClaudeDir: dirExists,\n hasSettings: settingsExists,\n currentStatusline\n }\n } catch {\n return {\n hasClaudeDir: false,\n hasSettings: false\n }\n }\n}"],"mappings":"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","names":["fs","path","process","fs","chalk","ora","path","inquirer","path","os","testStatuslineScript","generateMockClaudeInput","chalk","VERSION","previewCommand"]}
1
+ {"version":3,"sources":["../node_modules/tsup/assets/esm_shims.js","../src/utils/tester.ts","../src/cli/preview.ts","../src/index.ts","../src/cli/commands.ts","../src/cli/prompts.ts","../src/generators/bash-generator.ts","../src/features/colors.ts","../src/features/git.ts","../src/features/usage.ts","../src/utils/validator.ts","../src/utils/installer.ts"],"sourcesContent":["// Shim globals in esm bundle\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nconst getFilename = () => fileURLToPath(import.meta.url)\nconst getDirname = () => path.dirname(getFilename())\n\nexport const __dirname = /* @__PURE__ */ getDirname()\nexport const __filename = /* @__PURE__ */ getFilename()\n","import { StatuslineConfig } from '../cli/prompts.js'\nimport { spawn } from 'child_process'\nimport { promises as fs } from 'fs'\nimport path from 'path'\n\nexport interface TestResult {\n success: boolean\n output: string\n error?: string\n executionTime: number\n}\n\nexport async function testStatuslineScript(script: string, mockData?: any): Promise<TestResult> {\n const startTime = Date.now()\n \n try {\n // Create temporary script file\n const tempDir = '/tmp'\n const scriptPath = path.join(tempDir, `statusline-test-${Date.now()}.sh`)\n \n await fs.writeFile(scriptPath, script, { mode: 0o755 })\n \n // Generate mock input if not provided\n const input = mockData || generateMockClaudeInput()\n \n // Execute script\n const result = await executeScript(scriptPath, JSON.stringify(input))\n \n // Cleanup\n await fs.unlink(scriptPath).catch(() => {}) // Ignore cleanup errors\n \n const executionTime = Date.now() - startTime\n \n return {\n success: result.success,\n output: result.output,\n error: result.error,\n executionTime\n }\n \n } catch (error) {\n return {\n success: false,\n output: '',\n error: error instanceof Error ? error.message : String(error),\n executionTime: Date.now() - startTime\n }\n }\n}\n\nexport function generateMockClaudeInput(config?: Partial<StatuslineConfig>): any {\n return {\n session_id: \"test-session-123\",\n transcript_path: \"/home/user/.claude/conversations/test.jsonl\",\n cwd: \"/home/user/projects/my-project\",\n workspace: {\n current_dir: \"/home/user/projects/my-project\",\n project_dir: \"/home/user/projects/my-project\"\n },\n model: {\n id: \"claude-opus-4-1-20250805\",\n display_name: \"Opus 4.1\",\n version: \"20250805\"\n },\n version: \"1.0.80\",\n output_style: {\n name: \"default\"\n },\n cost: {\n total_cost_usd: 0.42,\n total_duration_ms: 180000, // 3 minutes\n total_api_duration_ms: 2300,\n total_lines_added: 156,\n total_lines_removed: 23\n },\n context_window: {\n total_input_tokens: 15234,\n total_output_tokens: 4521,\n context_window_size: 200000,\n current_usage: {\n input_tokens: 8500,\n output_tokens: 1200,\n cache_creation_input_tokens: 5000,\n cache_read_input_tokens: 2000\n }\n }\n }\n}\n\nexport function generateMockCcusageOutput(): any {\n return {\n blocks: [\n {\n id: \"2025-08-13T08:00:00.000Z\",\n startTime: \"2025-08-13T08:00:00.000Z\",\n endTime: \"2025-08-13T13:00:00.000Z\",\n usageLimitResetTime: \"2025-08-13T13:00:00.000Z\",\n actualEndTime: \"2025-08-13T09:30:34.698Z\",\n isActive: true,\n isGap: false,\n entries: 12,\n tokenCounts: {\n inputTokens: 1250,\n outputTokens: 2830,\n cacheCreationInputTokens: 15000,\n cacheReadInputTokens: 45000\n },\n totalTokens: 64080,\n costUSD: 3.42,\n models: [\"claude-opus-4-1-20250805\"],\n burnRate: {\n tokensPerMinute: 850.5,\n tokensPerMinuteForIndicator: 850,\n costPerHour: 12.45\n },\n projection: {\n totalTokens: 128000,\n totalCost: 6.84,\n remainingMinutes: 210\n }\n }\n ]\n }\n}\n\nasync function executeScript(scriptPath: string, input: string): Promise<{ success: boolean, output: string, error?: string }> {\n return new Promise((resolve) => {\n const process = spawn('bash', [scriptPath], {\n stdio: ['pipe', 'pipe', 'pipe']\n })\n \n let stdout = ''\n let stderr = ''\n \n process.stdout.on('data', (data) => {\n stdout += data.toString()\n })\n \n process.stderr.on('data', (data) => {\n stderr += data.toString()\n })\n \n process.on('close', (code) => {\n resolve({\n success: code === 0,\n output: stdout.trim(),\n error: stderr.trim() || undefined\n })\n })\n \n process.on('error', (err) => {\n resolve({\n success: false,\n output: '',\n error: err.message\n })\n })\n \n // Send input and close stdin\n process.stdin.write(input)\n process.stdin.end()\n \n // Timeout after 5 seconds\n setTimeout(() => {\n process.kill()\n resolve({\n success: false,\n output: stdout,\n error: 'Script execution timed out (5s)'\n })\n }, 5000)\n })\n}\n\nexport function analyzeTestResult(result: TestResult, config: StatuslineConfig): {\n performance: 'excellent' | 'good' | 'slow' | 'timeout'\n hasRequiredFeatures: boolean\n issues: string[]\n suggestions: string[]\n} {\n const issues: string[] = []\n const suggestions: string[] = []\n \n // Performance analysis\n let performance: 'excellent' | 'good' | 'slow' | 'timeout'\n if (result.executionTime > 1000) {\n performance = 'timeout'\n issues.push('Script execution is very slow (>1s)')\n } else if (result.executionTime > 500) {\n performance = 'slow'\n issues.push('Script execution is slow (>500ms)')\n } else if (result.executionTime > 100) {\n performance = 'good'\n } else {\n performance = 'excellent'\n }\n \n // Feature validation\n let hasRequiredFeatures = true\n \n if (config.features.includes('directory') && !result.output.includes('projects')) {\n hasRequiredFeatures = false\n issues.push('Directory feature not working properly')\n }\n \n if (config.features.includes('model') && !result.output.includes('Opus')) {\n hasRequiredFeatures = false\n issues.push('Model feature not working properly')\n }\n \n if (config.features.includes('git') && config.ccusageIntegration && !result.output.includes('git')) {\n suggestions.push('Git integration may require actual git repository')\n }\n \n // Error analysis\n if (result.error) {\n issues.push(`Script errors: ${result.error}`)\n }\n \n if (!result.success) {\n issues.push('Script failed to execute successfully')\n }\n \n // Performance suggestions\n if (config.features.length > 6) {\n suggestions.push('Consider reducing number of features for better performance')\n }\n \n if (config.ccusageIntegration && result.executionTime > 200) {\n suggestions.push('ccusage integration may slow down statusline - consider caching')\n }\n \n return {\n performance,\n hasRequiredFeatures,\n issues,\n suggestions\n }\n}","import { StatuslineConfig } from './prompts.js'\nimport { generateBashStatusline } from '../generators/bash-generator.js'\nimport { testStatuslineScript, generateMockClaudeInput, analyzeTestResult } from '../utils/tester.js'\nimport { promises as fs } from 'fs'\nimport chalk from 'chalk'\nimport ora from 'ora'\n\nexport async function previewCommand(scriptPath: string): Promise<void> {\n console.log(chalk.cyan('šŸ” Statusline Preview Mode\\n'))\n \n let script: string\n \n // Load existing statusline script\n try {\n const spinner = ora(`Loading statusline script from ${scriptPath}...`).start()\n script = await fs.readFile(scriptPath, 'utf-8')\n spinner.succeed('Script loaded!')\n \n // Try to extract config info from the script header\n const headerMatch = script.match(/# Theme: (\\w+) \\| Colors: (\\w+) \\| Features: ([^\\n]+)/i)\n if (headerMatch) {\n console.log(chalk.yellow('Detected Configuration:'))\n console.log(` Theme: ${headerMatch[1]}`)\n console.log(` Colors: ${headerMatch[2]}`) \n console.log(` Features: ${headerMatch[3]}\\n`)\n }\n \n // Extract generation info if available\n const generationMatch = script.match(/# Generated by cc-statusline.*\\n# Custom Claude Code statusline - Created: ([^\\n]+)/i)\n if (generationMatch) {\n console.log(chalk.gray(`Generated: ${generationMatch[1]}\\n`))\n }\n \n } catch (error) {\n console.error(chalk.red(`āŒ Failed to load script: ${error instanceof Error ? error.message : String(error)}`))\n return\n }\n \n // Test the script\n const testSpinner = ora('Testing statusline with mock data...').start()\n const mockInput = generateMockClaudeInput()\n \n console.log(chalk.gray('\\nMock Claude Code Input:'))\n console.log(chalk.gray(JSON.stringify(mockInput, null, 2)))\n \n const testResult = await testStatuslineScript(script, mockInput)\n \n if (testResult.success) {\n testSpinner.succeed(`Test completed in ${testResult.executionTime}ms`)\n \n console.log(chalk.green('\\nāœ… Statusline Output:'))\n console.log(chalk.white('━'.repeat(60)))\n console.log(testResult.output)\n console.log(chalk.white('━'.repeat(60)))\n \n // Basic performance analysis\n console.log(chalk.cyan(`\\nšŸ“Š Performance: ${getPerformanceEmoji(getPerformanceLevel(testResult.executionTime))} ${getPerformanceLevel(testResult.executionTime)} (${testResult.executionTime}ms)`))\n \n // Basic output validation\n if (testResult.output.includes('šŸ“') || testResult.output.includes('🌿') || testResult.output.includes('šŸ¤–')) {\n console.log(chalk.green('āœ… Statusline features appear to be working'))\n } else {\n console.log(chalk.yellow('āš ļø Basic features may not be displaying correctly'))\n }\n \n } else {\n testSpinner.fail('Test failed')\n console.error(chalk.red(`\\nāŒ Error: ${testResult.error}`))\n if (testResult.output) {\n console.log(chalk.gray('\\nPartial output:'))\n console.log(testResult.output)\n }\n }\n \n console.log(chalk.green('\\n✨ Preview complete! Use `cc-statusline init` to generate a new statusline.'))\n}\n\nfunction getPerformanceEmoji(performance: string): string {\n switch (performance) {\n case 'excellent': return 'šŸš€'\n case 'good': return 'āœ…'\n case 'slow': return 'āš ļø'\n case 'timeout': return '🐌'\n default: return 'ā“'\n }\n}\n\nfunction getPerformanceLevel(executionTime: number): string {\n if (executionTime > 1000) return 'timeout'\n if (executionTime > 500) return 'slow'\n if (executionTime > 100) return 'good'\n return 'excellent'\n}","import { Command } from 'commander'\nimport { initCommand } from './cli/commands.js'\nimport chalk from 'chalk'\n\n// Hard-code version to avoid bundling issues\nconst VERSION = '1.4.0'\n\nconst program = new Command()\n\nprogram\n .name('cc-statusline')\n .description('Interactive CLI tool for generating custom Claude Code statuslines')\n .version(VERSION)\n\nprogram\n .command('init')\n .description('Create a custom statusline with interactive prompts')\n .option('-o, --output <path>', 'Output path for statusline.sh', './.claude/statusline.sh')\n .option('--no-install', 'Don\\'t automatically install to .claude/statusline.sh')\n .action(initCommand)\n\nprogram\n .command('preview')\n .description('Preview existing statusline.sh with mock data')\n .argument('<script-path>', 'Path to statusline.sh file to preview')\n .action(async (scriptPath) => {\n const { previewCommand } = await import('./cli/preview.js')\n await previewCommand(scriptPath)\n })\n\nprogram\n .command('test')\n .description('Test statusline with real Claude Code JSON input')\n .option('-c, --config <path>', 'Configuration file to test')\n .action(() => {\n console.log(chalk.yellow('Test command coming soon!'))\n })\n\n// Show help if no command provided\nif (!process.argv.slice(2).length) {\n program.outputHelp()\n}\n\nprogram.parse(process.argv)","import { collectConfiguration, displayConfigSummary } from './prompts.js'\nimport { generateBashStatusline } from '../generators/bash-generator.js'\nimport { validateConfig } from '../utils/validator.js'\nimport { installStatusline } from '../utils/installer.js'\nimport chalk from 'chalk'\nimport ora from 'ora'\nimport path from 'path'\nimport os from 'os'\nimport { execSync } from 'child_process'\n\ninterface InitOptions {\n output?: string\n install?: boolean\n}\n\nfunction checkJqInstallation(): boolean {\n try {\n execSync('command -v jq', { stdio: 'ignore' })\n return true\n } catch {\n return false\n }\n}\n\nfunction getJqInstallInstructions(): string {\n const platform = process.platform\n \n if (platform === 'darwin') {\n return `\n${chalk.cyan('šŸ“¦ Install jq for better performance and reliability:')}\n\n${chalk.green('Using Homebrew (recommended):')}\n brew install jq\n\n${chalk.green('Using MacPorts:')}\n sudo port install jq\n\n${chalk.green('Or download directly:')}\n https://github.com/jqlang/jq/releases\n`\n } else if (platform === 'linux') {\n return `\n${chalk.cyan('šŸ“¦ Install jq for better performance and reliability:')}\n\n${chalk.green('Ubuntu/Debian:')}\n sudo apt-get install jq\n\n${chalk.green('CentOS/RHEL/Fedora:')}\n sudo yum install jq\n\n${chalk.green('Arch Linux:')}\n sudo pacman -S jq\n\n${chalk.green('Or download directly:')}\n https://github.com/jqlang/jq/releases\n`\n } else if (platform === 'win32') {\n return `\n${chalk.cyan('šŸ“¦ Install jq for better performance and reliability:')}\n\n${chalk.green('Option 1: Using Package Manager')}\n ${chalk.dim('Chocolatey:')} choco install jq\n ${chalk.dim('Scoop:')} scoop install jq\n\n${chalk.green('Option 2: Manual Download')}\n 1. Download from: https://github.com/jqlang/jq/releases/latest\n 2. Choose file:\n ${chalk.dim('• 64-bit Windows:')} jq-windows-amd64.exe\n ${chalk.dim('• 32-bit Windows:')} jq-windows-i386.exe\n 3. Rename to: jq.exe\n 4. Move to: C:\\\\Windows\\\\System32\\\\ ${chalk.dim('(or add to PATH)')}\n 5. Test: Open new terminal and run: jq --version\n`\n } else {\n return `\n${chalk.cyan('šŸ“¦ Install jq for better performance and reliability:')}\n\n${chalk.green('Download for your platform:')}\n https://github.com/jqlang/jq/releases\n`\n }\n}\n\nexport async function initCommand(options: InitOptions): Promise<void> {\n try {\n const spinner = ora('Initializing statusline generator...').start()\n await new Promise(resolve => setTimeout(resolve, 500)) // Brief pause for UX\n spinner.stop()\n\n // Check for jq installation\n const hasJq = checkJqInstallation()\n if (!hasJq) {\n console.log(chalk.yellow('\\nāš ļø jq is not installed'))\n console.log(chalk.dim('Your statusline will work without jq, but with limited functionality:'))\n console.log(chalk.dim(' • Context remaining percentage won\\'t be displayed'))\n console.log(chalk.dim(' • Token statistics may not work'))\n console.log(chalk.dim(' • Performance will be slower'))\n console.log(getJqInstallInstructions())\n \n // Ask if they want to continue without jq\n const inquirer = (await import('inquirer')).default\n const { continueWithoutJq } = await inquirer.prompt([{\n type: 'confirm',\n name: 'continueWithoutJq',\n message: 'Continue without jq?',\n default: true\n }])\n \n if (!continueWithoutJq) {\n console.log(chalk.cyan('\\nšŸ‘ Install jq and run this command again'))\n process.exit(0)\n }\n }\n\n // Collect user configuration\n const config = await collectConfiguration()\n \n // Validate configuration\n const validation = validateConfig(config)\n if (!validation.isValid) {\n console.error(chalk.red('āŒ Configuration validation failed:'))\n validation.errors.forEach(error => console.error(chalk.red(` • ${error}`)))\n process.exit(1)\n }\n\n // Generate statusline script\n const generationSpinner = ora('Generating statusline script...').start()\n \n const script = generateBashStatusline(config)\n const filename = 'statusline.sh'\n \n generationSpinner.succeed('Statusline script generated!')\n\n // Show preview of what it will look like\n console.log(chalk.cyan('\\n✨ Your statusline will look like:'))\n console.log(chalk.white('━'.repeat(60)))\n \n // Generate preview using the test function\n const { testStatuslineScript, generateMockClaudeInput } = await import('../utils/tester.js')\n const mockInput = generateMockClaudeInput()\n const testResult = await testStatuslineScript(script, mockInput)\n \n if (testResult.success) {\n console.log(testResult.output)\n } else {\n console.log(chalk.gray('šŸ“ ~/projects/my-app 🌿 main šŸ¤– Claude šŸ’µ $2.48 ($12.50/h)'))\n console.log(chalk.gray('(Preview unavailable - will work when Claude Code runs it)'))\n }\n \n console.log(chalk.white('━'.repeat(60)))\n\n // Determine output path based on installation location\n const isGlobal = config.installLocation === 'global'\n const baseDir = isGlobal ? os.homedir() : '.'\n const outputPath = options.output || path.join(baseDir, '.claude', filename)\n const resolvedPath = path.resolve(outputPath)\n\n // Install the statusline\n if (options.install !== false) {\n console.log(chalk.cyan('\\nšŸ“¦ Installing statusline...'))\n \n try {\n await installStatusline(script, resolvedPath, config)\n \n console.log(chalk.green('\\nāœ… Statusline installed!'))\n console.log(chalk.green('\\nšŸŽ‰ Success! Your custom statusline is ready!'))\n console.log(chalk.cyan(`\\nšŸ“ ${isGlobal ? 'Global' : 'Project'} installation complete: ${chalk.white(resolvedPath)}`))\n console.log(chalk.cyan('\\nNext steps:'))\n console.log(chalk.white(' 1. Restart Claude Code to see your new statusline'))\n if (config.features.includes('session')) {\n console.log(chalk.white(' 2. Session reset time requires ccusage: npx ccusage@latest'))\n }\n \n } catch (error) {\n console.log(chalk.red('\\nāŒ Failed to install statusline'))\n \n if (error instanceof Error && error.message === 'USER_CANCELLED_OVERWRITE') {\n console.log(chalk.yellow('\\nāš ļø Installation cancelled. Existing statusline.sh was not overwritten.'))\n } else if (error instanceof Error && error.message === 'SETTINGS_UPDATE_FAILED') {\n const commandPath = isGlobal ? '~/.claude/statusline.sh' : '.claude/statusline.sh'\n console.log(chalk.yellow('\\nāš ļø Settings.json could not be updated automatically.'))\n console.log(chalk.cyan('\\nManual Configuration Required:'))\n console.log(chalk.white(`Add this to your ${isGlobal ? '~/.claude' : '.claude'}/settings.json file:`))\n console.log(chalk.gray('\\n{'))\n console.log(chalk.gray(' \"statusLine\": {'))\n console.log(chalk.gray(' \"type\": \"command\",'))\n console.log(chalk.gray(` \"command\": \"${commandPath}\",`))\n console.log(chalk.gray(' \"padding\": 0'))\n console.log(chalk.gray(' }'))\n console.log(chalk.gray('}'))\n console.log(chalk.cyan(`\\nšŸ“ Statusline script saved to: ${chalk.white(resolvedPath)}`))\n } else {\n console.error(chalk.red(`Error: ${error instanceof Error ? error.message : String(error)}`))\n console.log(chalk.cyan(`\\nšŸ“ You can manually save the script to: ${chalk.white(resolvedPath)}`))\n }\n }\n } else {\n // Just display where to save it\n console.log(chalk.green('\\nāœ… Statusline generated successfully!'))\n console.log(chalk.cyan(`\\nšŸ“ Save this script to: ${chalk.white(resolvedPath)}`))\n console.log(chalk.cyan('\\nThen restart Claude Code to see your new statusline.'))\n }\n\n } catch (error) {\n console.error(chalk.red('āŒ An error occurred:'))\n console.error(chalk.red(error instanceof Error ? error.message : String(error)))\n process.exit(1)\n }\n}","import inquirer from 'inquirer'\n\nexport interface StatuslineConfig {\n features: string[]\n runtime: 'bash' | 'python' | 'node'\n colors: boolean\n theme: 'minimal' | 'detailed' | 'compact'\n ccusageIntegration: boolean\n logging: boolean\n customEmojis: boolean\n installLocation?: 'global' | 'project'\n}\n\nexport async function collectConfiguration(): Promise<StatuslineConfig> {\n console.log('šŸš€ Welcome to cc-statusline! Let\\'s create your custom Claude Code statusline.\\n')\n console.log('✨ All features are enabled by default. Use ↑/↓ arrows to navigate, SPACE to toggle, ENTER to continue.\\n')\n \n const config = await inquirer.prompt([\n {\n type: 'checkbox',\n name: 'features',\n message: 'Select statusline features (scroll down for more options):',\n choices: [\n { name: 'šŸ“ Working Directory', value: 'directory', checked: true },\n { name: '🌿 Git Branch', value: 'git', checked: true },\n { name: 'šŸ¤– Model Name & Version', value: 'model', checked: true },\n { name: '🧠 Context Remaining', value: 'context', checked: true },\n { name: 'šŸ’µ Usage & Cost', value: 'usage', checked: true },\n { name: 'šŸ“Š Token Statistics', value: 'tokens', checked: true },\n { name: '⚔ Burn Rate ($/hr & tokens/min)', value: 'burnrate', checked: true },\n { name: 'āŒ› Session Reset Time (requires ccusage)', value: 'session', checked: false }\n ],\n validate: (answer: string[]) => {\n if (answer.length < 1) {\n return 'You must choose at least one feature.'\n }\n return true\n },\n pageSize: 10\n },\n {\n type: 'confirm',\n name: 'colors',\n message: '\\nšŸŽØ Enable modern color scheme and emojis?',\n default: true\n },\n {\n type: 'confirm',\n name: 'logging',\n message: '\\nšŸ“ Enable debug logging to .claude/statusline.log?',\n default: false\n },\n {\n type: 'list',\n name: 'installLocation',\n message: '\\nšŸ“ Where would you like to install the statusline?',\n choices: [\n { name: 'šŸ  Global (~/.claude) - Use across all projects', value: 'global' },\n { name: 'šŸ“‚ Project (./.claude) - Only for this project', value: 'project' }\n ],\n default: 'project'\n }\n ])\n\n // Set intelligent defaults\n // ccusage is only needed for session reset time feature\n const needsCcusage = config.features.includes('session')\n\n return {\n features: config.features,\n runtime: 'bash',\n colors: config.colors,\n theme: 'detailed',\n ccusageIntegration: needsCcusage,\n logging: config.logging,\n customEmojis: false,\n installLocation: config.installLocation\n } as StatuslineConfig\n}\n\nexport function displayConfigSummary(config: StatuslineConfig): void {\n console.log('\\nāœ… Configuration Summary:')\n console.log(` Runtime: ${config.runtime}`)\n console.log(` Theme: ${config.theme}`)\n console.log(` Colors: ${config.colors ? 'āœ…' : 'āŒ'}`)\n console.log(` Features: ${config.features.join(', ')}`)\n\n if (config.ccusageIntegration) {\n console.log(' āš ļø Session reset time requires ccusage (npx ccusage@latest)')\n }\n\n if (config.logging) {\n console.log(' šŸ“ Debug logging enabled')\n }\n\n console.log('')\n}","import { StatuslineConfig } from '../cli/prompts.js'\nimport { generateColorBashCode, generateBasicColors } from '../features/colors.js'\nimport { generateGitBashCode, generateGitDisplayCode, generateGitUtilities } from '../features/git.js'\nimport { generateUsageBashCode, generateUsageDisplayCode, generateUsageUtilities } from '../features/usage.js'\n\n// Version will be updated when releasing\nconst VERSION = '1.4.0'\n\nexport function generateBashStatusline(config: StatuslineConfig): string {\n const hasGit = config.features.includes('git')\n const hasUsage = config.features.some(f => ['usage', 'session', 'tokens', 'burnrate'].includes(f))\n const hasDirectory = config.features.includes('directory')\n const hasModel = config.features.includes('model')\n const hasContext = config.features.includes('context')\n\n // Build usage feature config\n const usageConfig = {\n enabled: hasUsage && config.ccusageIntegration,\n showCost: config.features.includes('usage'),\n showTokens: config.features.includes('tokens'),\n showBurnRate: config.features.includes('burnrate'),\n showSession: config.features.includes('session'),\n showProgressBar: config.theme !== 'minimal' && config.features.includes('session')\n }\n\n // Build git feature config\n const gitConfig = {\n enabled: hasGit,\n showBranch: hasGit,\n showChanges: false, // Removed delta changes per user request\n compactMode: config.theme === 'compact'\n }\n\n const timestamp = new Date().toISOString()\n const script = `#!/bin/bash\n# Generated by cc-statusline v${VERSION} (https://www.npmjs.com/package/@chongdashu/cc-statusline)\n# Custom Claude Code statusline - Created: ${timestamp}\n# Theme: ${config.theme} | Colors: ${config.colors} | Features: ${config.features.join(', ')}\nSTATUSLINE_VERSION=\"${VERSION}\"\n\ninput=$(cat)\n\n# ---- check jq availability ----\nHAS_JQ=0\nif command -v jq >/dev/null 2>&1; then\n HAS_JQ=1\nfi\n${config.logging ? generateLoggingCode() : ''}\n${generateColorBashCode({ enabled: config.colors, theme: config.theme })}\n${config.colors ? generateBasicColors() : ''}\n${hasUsage ? generateUsageUtilities() : ''}\n${hasGit ? generateGitUtilities() : ''}\n${generateBasicDataExtraction(hasDirectory, hasModel, hasContext)}\n${hasGit ? generateGitBashCode(gitConfig, config.colors) : ''}\n${hasContext ? generateContextBashCode(config.colors) : ''}\n${hasUsage ? generateUsageBashCode(usageConfig, config.colors) : ''}\n${config.logging ? generateLoggingOutput() : ''}\n${generateDisplaySection(config, gitConfig, usageConfig)}\n`\n\n return script.replace(/\\n\\n\\n+/g, '\\n\\n').trim() + '\\n'\n}\n\nfunction generateLoggingCode(): string {\n return `\n# Get the directory where this statusline script is located\nSCRIPT_DIR=\"$(cd \"$(dirname \"\\${BASH_SOURCE[0]}\")\" && pwd)\"\nLOG_FILE=\"\\${SCRIPT_DIR}/statusline.log\"\nTIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')\n\n# ---- logging ----\n{\n echo \"[$TIMESTAMP] Status line triggered (cc-statusline v\\${STATUSLINE_VERSION})\"\n echo \"[$TIMESTAMP] Input:\"\n if [ \"$HAS_JQ\" -eq 1 ]; then\n echo \"$input\" | jq . 2>/dev/null || echo \"$input\"\n echo \"[$TIMESTAMP] Using jq for JSON parsing\"\n else\n echo \"$input\"\n echo \"[$TIMESTAMP] WARNING: jq not found, using bash fallback for JSON parsing\"\n fi\n echo \"---\"\n} >> \"$LOG_FILE\" 2>/dev/null\n`\n}\n\nfunction generateJsonExtractorCode(): string {\n return `\n# ---- JSON extraction utilities ----\n# Pure bash JSON value extractor (fallback when jq not available)\nextract_json_string() {\n local json=\"$1\"\n local key=\"$2\"\n local default=\"\\${3:-}\"\n \n # For nested keys like workspace.current_dir, get the last part\n local field=\"\\${key##*.}\"\n field=\"\\${field%% *}\" # Remove any jq operators\n \n # Try to extract string value (quoted)\n local value=$(echo \"$json\" | grep -o \"\\\\\"\\\\$\\{field}\\\\\"[[:space:]]*:[[:space:]]*\\\\\"[^\\\\\"]*\\\\\"\" | head -1 | sed 's/.*:[[:space:]]*\"\\\\([^\"]*\\\\)\".*/\\\\1/')\n \n # Convert escaped backslashes to forward slashes for Windows paths\n if [ -n \"$value\" ]; then\n value=$(echo \"$value\" | sed 's/\\\\\\\\\\\\\\\\/\\\\//g')\n fi\n \n # If no string value found, try to extract number value (unquoted)\n if [ -z \"$value\" ] || [ \"$value\" = \"null\" ]; then\n value=$(echo \"$json\" | grep -o \"\\\\\"\\\\$\\{field}\\\\\"[[:space:]]*:[[:space:]]*[0-9.]\\\\+\" | head -1 | sed 's/.*:[[:space:]]*\\\\([0-9.]\\\\+\\\\).*/\\\\1/')\n fi\n \n # Return value or default\n if [ -n \"$value\" ] && [ \"$value\" != \"null\" ]; then\n echo \"$value\"\n else\n echo \"$default\"\n fi\n}\n`\n}\n\nfunction generateBasicDataExtraction(hasDirectory: boolean, hasModel: boolean, hasContext: boolean): string {\n return `\n${generateJsonExtractorCode()}\n# ---- basics ----\nif [ \"$HAS_JQ\" -eq 1 ]; then${hasDirectory ? `\n current_dir=$(echo \"$input\" | jq -r '.workspace.current_dir // .cwd // \"unknown\"' 2>/dev/null | sed \"s|^$HOME|~|g\")` : ''}${hasModel ? `\n model_name=$(echo \"$input\" | jq -r '.model.display_name // \"Claude\"' 2>/dev/null)\n model_version=$(echo \"$input\" | jq -r '.model.version // \"\"' 2>/dev/null)` : ''}${hasContext ? `\n session_id=$(echo \"$input\" | jq -r '.session_id // \"\"' 2>/dev/null)` : ''}\n cc_version=$(echo \"$input\" | jq -r '.version // \"\"' 2>/dev/null)\n output_style=$(echo \"$input\" | jq -r '.output_style.name // \"\"' 2>/dev/null)\nelse${hasDirectory ? `\n # Bash fallback for JSON extraction\n # Extract current_dir from workspace object - look for the pattern workspace\":{\"current_dir\":\"...\"}\n current_dir=$(echo \"$input\" | grep -o '\"workspace\"[[:space:]]*:[[:space:]]*{[^}]*\"current_dir\"[[:space:]]*:[[:space:]]*\"[^\"]*\"' | sed 's/.*\"current_dir\"[[:space:]]*:[[:space:]]*\"\\\\([^\"]*\\\\)\".*/\\\\1/' | sed 's/\\\\\\\\\\\\\\\\/\\\\//g')\n \n # Fall back to cwd if workspace extraction failed\n if [ -z \"$current_dir\" ] || [ \"$current_dir\" = \"null\" ]; then\n current_dir=$(echo \"$input\" | grep -o '\"cwd\"[[:space:]]*:[[:space:]]*\"[^\"]*\"' | sed 's/.*\"cwd\"[[:space:]]*:[[:space:]]*\"\\\\([^\"]*\\\\)\".*/\\\\1/' | sed 's/\\\\\\\\\\\\\\\\/\\\\//g')\n fi\n \n # Fallback to unknown if all extraction failed\n [ -z \"$current_dir\" ] && current_dir=\"unknown\"\n current_dir=$(echo \"$current_dir\" | sed \"s|^$HOME|~|g\")` : ''}${hasModel ? `\n \n # Extract model name from nested model object\n model_name=$(echo \"$input\" | grep -o '\"model\"[[:space:]]*:[[:space:]]*{[^}]*\"display_name\"[[:space:]]*:[[:space:]]*\"[^\"]*\"' | sed 's/.*\"display_name\"[[:space:]]*:[[:space:]]*\"\\\\([^\"]*\\\\)\".*/\\\\1/')\n [ -z \"$model_name\" ] && model_name=\"Claude\"\n # Model version is in the model ID, not a separate field \n model_version=\"\" # Not available in Claude Code JSON` : ''}${hasContext ? `\n session_id=$(extract_json_string \"$input\" \"session_id\" \"\")` : ''}\n # CC version is at the root level\n cc_version=$(echo \"$input\" | grep -o '\"version\"[[:space:]]*:[[:space:]]*\"[^\"]*\"' | head -1 | sed 's/.*\"version\"[[:space:]]*:[[:space:]]*\"\\\\([^\"]*\\\\)\".*/\\\\1/')\n # Output style is nested\n output_style=$(echo \"$input\" | grep -o '\"output_style\"[[:space:]]*:[[:space:]]*{[^}]*\"name\"[[:space:]]*:[[:space:]]*\"[^\"]*\"' | sed 's/.*\"name\"[[:space:]]*:[[:space:]]*\"\\\\([^\"]*\\\\)\".*/\\\\1/')\nfi\n`\n}\n\nfunction generateContextBashCode(colors: boolean): string {\n return `\n# ---- context window calculation (native) ----\ncontext_pct=\"\"\ncontext_remaining_pct=\"\"\ncontext_color() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[1;37m'; fi; } # default white\n\nif [ \"$HAS_JQ\" -eq 1 ]; then\n # Get context window size and current usage from native Claude Code input\n CONTEXT_SIZE=$(echo \"$input\" | jq -r '.context_window.context_window_size // 200000' 2>/dev/null)\n USAGE=$(echo \"$input\" | jq '.context_window.current_usage' 2>/dev/null)\n\n if [ \"$USAGE\" != \"null\" ] && [ -n \"$USAGE\" ]; then\n # Calculate current context from current_usage fields\n # Formula: input_tokens + cache_creation_input_tokens + cache_read_input_tokens\n CURRENT_TOKENS=$(echo \"$USAGE\" | jq '(.input_tokens // 0) + (.cache_creation_input_tokens // 0) + (.cache_read_input_tokens // 0)' 2>/dev/null)\n\n if [ -n \"$CURRENT_TOKENS\" ] && [ \"$CURRENT_TOKENS\" -gt 0 ] 2>/dev/null; then\n context_used_pct=$(( CURRENT_TOKENS * 100 / CONTEXT_SIZE ))\n context_remaining_pct=$(( 100 - context_used_pct ))\n # Clamp to valid range\n (( context_remaining_pct < 0 )) && context_remaining_pct=0\n (( context_remaining_pct > 100 )) && context_remaining_pct=100\n\n # Set color based on remaining percentage\n if [ \"$context_remaining_pct\" -le 20 ]; then\n context_color() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[38;5;203m'; fi; } # coral red\n elif [ \"$context_remaining_pct\" -le 40 ]; then\n context_color() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[38;5;215m'; fi; } # peach\n else\n context_color() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[38;5;158m'; fi; } # mint green\n fi\n\n context_pct=\"\\${context_remaining_pct}%\"\n fi\n fi\nfi\n`\n}\n\nfunction generateLoggingOutput(): string {\n return `\n# ---- log extracted data ----\n{\n echo \"[\\$TIMESTAMP] Extracted: dir=\\${current_dir:-}, model=\\${model_name:-}, version=\\${model_version:-}, git=\\${git_branch:-}, context=\\${context_pct:-}, cost=\\${cost_usd:-}, cost_ph=\\${cost_per_hour:-}, tokens=\\${tot_tokens:-}, tpm=\\${tpm:-}, session_pct=\\${session_pct:-}\"\n if [ \"$HAS_JQ\" -eq 0 ]; then\n echo \"[\\$TIMESTAMP] Note: Context, tokens, and session info require jq for full functionality\"\n fi\n} >> \"$LOG_FILE\" 2>/dev/null\n`\n}\n\nfunction generateDisplaySection(config: StatuslineConfig, gitConfig: any, usageConfig: any): string {\n const emojis = config.colors && !config.customEmojis\n\n return `\n# ---- render statusline ----\n# Line 1: Core info (directory, git, model, claude code version, output style)\n${config.features.includes('directory') ? `printf 'šŸ“ %s%s%s' \"$(dir_color)\" \"$current_dir\" \"$(rst)\"` : ''}${gitConfig.enabled ? `\nif [ -n \"$git_branch\" ]; then\n printf ' 🌿 %s%s%s' \"$(git_color)\" \"$git_branch\" \"$(rst)\"\nfi` : ''}${config.features.includes('model') ? `\nprintf ' šŸ¤– %s%s%s' \"$(model_color)\" \"$model_name\" \"$(rst)\"\nif [ -n \"$model_version\" ] && [ \"$model_version\" != \"null\" ]; then\n printf ' šŸ·ļø %s%s%s' \"$(version_color)\" \"$model_version\" \"$(rst)\"\nfi` : ''}\nif [ -n \"$cc_version\" ] && [ \"$cc_version\" != \"null\" ]; then\n printf ' šŸ“Ÿ %sv%s%s' \"$(cc_version_color)\" \"$cc_version\" \"$(rst)\"\nfi\nif [ -n \"$output_style\" ] && [ \"$output_style\" != \"null\" ]; then\n printf ' šŸŽØ %s%s%s' \"$(style_color)\" \"$output_style\" \"$(rst)\"\nfi\n\n# Line 2: Context and session time\nline2=\"\"${config.features.includes('context') ? `\nif [ -n \"$context_pct\" ]; then\n context_bar=$(progress_bar \"$context_remaining_pct\" 10)\n line2=\"🧠 $(context_color)Context Remaining: \\${context_pct} [\\${context_bar}]$(rst)\"\nfi` : ''}${usageConfig.showSession ? `\nif [ -n \"$session_txt\" ]; then\n if [ -n \"$line2\" ]; then\n line2=\"$line2 āŒ› $(session_color)\\${session_txt}$(rst) $(session_color)[\\${session_bar}]$(rst)\"\n else\n line2=\"āŒ› $(session_color)\\${session_txt}$(rst) $(session_color)[\\${session_bar}]$(rst)\"\n fi\nfi` : ''}${config.features.includes('context') ? `\nif [ -z \"$line2\" ] && [ -z \"$context_pct\" ]; then\n line2=\"🧠 $(context_color)Context Remaining: TBD$(rst)\"\nfi` : ''}\n\n# Line 3: Cost and usage analytics\nline3=\"\"${usageConfig.showCost ? `\nif [ -n \"$cost_usd\" ] && [[ \"$cost_usd\" =~ ^[0-9.]+$ ]]; then${usageConfig.showBurnRate ? `\n if [ -n \"$cost_per_hour\" ] && [[ \"$cost_per_hour\" =~ ^[0-9.]+$ ]]; then\n cost_per_hour_formatted=$(printf '%.2f' \"$cost_per_hour\")\n line3=\"šŸ’° $(cost_color)\\\\$$(printf '%.2f' \"$cost_usd\")$(rst) ($(burn_color)\\\\$\\${cost_per_hour_formatted}/h$(rst))\"\n else\n line3=\"šŸ’° $(cost_color)\\\\$$(printf '%.2f' \"$cost_usd\")$(rst)\"\n fi` : `\n line3=\"šŸ’° $(cost_color)\\\\$$(printf '%.2f' \"$cost_usd\")$(rst)\"`}\nfi` : ''}${usageConfig.showTokens ? `\nif [ -n \"$tot_tokens\" ] && [[ \"$tot_tokens\" =~ ^[0-9]+$ ]]; then${usageConfig.showBurnRate ? `\n if [ -n \"$tpm\" ] && [[ \"$tpm\" =~ ^[0-9.]+$ ]]; then\n tpm_formatted=$(printf '%.0f' \"$tpm\")\n if [ -n \"$line3\" ]; then\n line3=\"$line3 šŸ“Š $(usage_color)\\${tot_tokens} tok (\\${tpm_formatted} tpm)$(rst)\"\n else\n line3=\"šŸ“Š $(usage_color)\\${tot_tokens} tok (\\${tpm_formatted} tpm)$(rst)\"\n fi\n else\n if [ -n \"$line3\" ]; then\n line3=\"$line3 šŸ“Š $(usage_color)\\${tot_tokens} tok$(rst)\"\n else\n line3=\"šŸ“Š $(usage_color)\\${tot_tokens} tok$(rst)\"\n fi\n fi` : `\n if [ -n \"$line3\" ]; then\n line3=\"$line3 šŸ“Š $(usage_color)\\${tot_tokens} tok$(rst)\"\n else\n line3=\"šŸ“Š $(usage_color)\\${tot_tokens} tok$(rst)\"\n fi`}\nfi` : ''}\n\n# Print lines\nif [ -n \"$line2\" ]; then\n printf '\\\\n%s' \"$line2\"\nfi\nif [ -n \"$line3\" ]; then\n printf '\\\\n%s' \"$line3\"\nfi\nprintf '\\\\n'`\n}","export interface ColorConfig {\n enabled: boolean\n theme: 'minimal' | 'detailed' | 'compact'\n}\n\nexport function generateColorBashCode(config: ColorConfig): string {\n if (!config.enabled) {\n return `\n# ---- color helpers (disabled) ----\nuse_color=0\nC() { :; }\nRST() { :; }\n`\n }\n\n return `\n# ---- color helpers (force colors for Claude Code) ----\nuse_color=1\n[ -n \"$NO_COLOR\" ] && use_color=0\n\nC() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[%sm' \"$1\"; fi; }\nRST() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[0m'; fi; }\n`\n}\n\nexport function generateBasicColors(): string {\n return `\n# ---- modern sleek colors ----\ndir_color() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[38;5;117m'; fi; } # sky blue\nmodel_color() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[38;5;147m'; fi; } # light purple \nversion_color() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[38;5;180m'; fi; } # soft yellow\ncc_version_color() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[38;5;249m'; fi; } # light gray\nstyle_color() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[38;5;245m'; fi; } # gray\nrst() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[0m'; fi; }\n`\n}\n\nexport const COLOR_CODES = {\n // Basic colors\n BLACK: '30',\n RED: '31', \n GREEN: '32',\n YELLOW: '33',\n BLUE: '34',\n MAGENTA: '35',\n CYAN: '36',\n WHITE: '37',\n \n // Bright colors (bold)\n BRIGHT_BLACK: '1;30',\n BRIGHT_RED: '1;31',\n BRIGHT_GREEN: '1;32', \n BRIGHT_YELLOW: '1;33',\n BRIGHT_BLUE: '1;34',\n BRIGHT_MAGENTA: '1;35',\n BRIGHT_CYAN: '1;36',\n BRIGHT_WHITE: '1;37',\n \n // Reset\n RESET: '0'\n} as const\n\nexport function getThemeColors(theme: 'minimal' | 'detailed' | 'compact') {\n switch (theme) {\n case 'minimal':\n return {\n directory: COLOR_CODES.CYAN,\n git: COLOR_CODES.GREEN,\n model: COLOR_CODES.MAGENTA,\n usage: COLOR_CODES.YELLOW,\n session: COLOR_CODES.BLUE\n }\n case 'detailed':\n return {\n directory: COLOR_CODES.BRIGHT_CYAN,\n git: COLOR_CODES.BRIGHT_GREEN,\n model: COLOR_CODES.BRIGHT_MAGENTA,\n usage: COLOR_CODES.BRIGHT_YELLOW,\n session: COLOR_CODES.BRIGHT_BLUE\n }\n case 'compact':\n return {\n directory: COLOR_CODES.CYAN,\n git: COLOR_CODES.GREEN,\n model: COLOR_CODES.BLUE,\n usage: COLOR_CODES.YELLOW,\n session: COLOR_CODES.RED\n }\n }\n}","export interface GitFeature {\n enabled: boolean\n showBranch: boolean\n showChanges: boolean\n compactMode: boolean\n}\n\nexport function generateGitBashCode(config: GitFeature, colors: boolean): string {\n if (!config.enabled) return ''\n\n const colorCode = colors ? `\n# ---- git colors ----\ngit_color() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[38;5;150m'; fi; } # soft green\nrst() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[0m'; fi; }\n` : `\ngit_color() { :; }\nrst() { :; }\n`\n\n return `${colorCode}\n# ---- git ----\ngit_branch=\"\"\nif git rev-parse --git-dir >/dev/null 2>&1; then\n git_branch=$(git branch --show-current 2>/dev/null || git rev-parse --short HEAD 2>/dev/null)\nfi`\n}\n\nexport function generateGitDisplayCode(config: GitFeature, colors: boolean, emojis: boolean): string {\n if (!config.enabled) return ''\n\n const branchEmoji = emojis ? '🌿' : 'git:'\n\n let displayCode = `\n# git display\nif [ -n \"$git_branch\" ]; then\n printf ' ${branchEmoji} %s%s%s' \"$(git_color)\" \"$git_branch\" \"$(rst)\"\nfi`\n\n return displayCode\n}\n\nexport function generateGitUtilities(): string {\n return `\n# git utilities\nnum_or_zero() { v=\"$1\"; [[ \"$v\" =~ ^[0-9]+$ ]] && echo \"$v\" || echo 0; }`\n}","export interface UsageFeature {\n enabled: boolean\n showCost: boolean\n showTokens: boolean\n showBurnRate: boolean\n showSession: boolean // This is the only feature requiring ccusage\n showProgressBar: boolean\n}\n\nexport function generateUsageBashCode(config: UsageFeature, colors: boolean): string {\n if (!config.enabled) return ''\n\n const colorCode = colors ? `\n# ---- usage colors ----\nusage_color() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[38;5;189m'; fi; } # lavender\ncost_color() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[38;5;222m'; fi; } # light gold\nburn_color() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[38;5;220m'; fi; } # bright gold\nsession_color() { \n rem_pct=$(( 100 - session_pct ))\n if (( rem_pct <= 10 )); then SCLR='38;5;210' # light pink\n elif (( rem_pct <= 25 )); then SCLR='38;5;228' # light yellow \n else SCLR='38;5;194'; fi # light green\n if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[%sm' \"$SCLR\"; fi\n}\n` : `\nusage_color() { :; }\ncost_color() { :; }\nburn_color() { :; }\nsession_color() { :; }\n`\n\n // Session reset time is the only feature requiring ccusage\n const needsCcusage = config.showSession || config.showProgressBar\n\n return `${colorCode}\n# ---- cost and usage extraction ----\nsession_txt=\"\"; session_pct=0; session_bar=\"\"\ncost_usd=\"\"; cost_per_hour=\"\"; tpm=\"\"; tot_tokens=\"\"\n\n# Extract cost and token data from Claude Code's native input\nif [ \"$HAS_JQ\" -eq 1 ]; then\n # Cost data\n cost_usd=$(echo \"$input\" | jq -r '.cost.total_cost_usd // empty' 2>/dev/null)\n total_duration_ms=$(echo \"$input\" | jq -r '.cost.total_duration_ms // empty' 2>/dev/null)\n\n # Calculate burn rate ($/hour) from cost and duration\n if [ -n \"$cost_usd\" ] && [ -n \"$total_duration_ms\" ] && [ \"$total_duration_ms\" -gt 0 ]; then\n cost_per_hour=$(echo \"$cost_usd $total_duration_ms\" | awk '{printf \"%.2f\", $1 * 3600000 / $2}')\n fi\n${config.showTokens ? `\n # Token data from native context_window (no ccusage needed)\n input_tokens=$(echo \"$input\" | jq -r '.context_window.total_input_tokens // 0' 2>/dev/null)\n output_tokens=$(echo \"$input\" | jq -r '.context_window.total_output_tokens // 0' 2>/dev/null)\n\n if [ \"$input_tokens\" != \"null\" ] && [ \"$output_tokens\" != \"null\" ]; then\n tot_tokens=$(( input_tokens + output_tokens ))\n [ \"$tot_tokens\" -eq 0 ] && tot_tokens=\"\"\n fi` : ''}\n${config.showBurnRate && config.showTokens ? `\n # Calculate tokens per minute from native data\n if [ -n \"$tot_tokens\" ] && [ -n \"$total_duration_ms\" ] && [ \"$total_duration_ms\" -gt 0 ]; then\n # Convert ms to minutes and calculate rate\n tpm=$(echo \"$tot_tokens $total_duration_ms\" | awk '{if ($2 > 0) printf \"%.0f\", $1 * 60000 / $2; else print \"\"}')\n fi` : ''}\nelse\n # Bash fallback for cost extraction\n cost_usd=$(echo \"$input\" | grep -o '\"total_cost_usd\"[[:space:]]*:[[:space:]]*[0-9.]*' | sed 's/.*:[[:space:]]*\\\\([0-9.]*\\\\).*/\\\\1/')\n total_duration_ms=$(echo \"$input\" | grep -o '\"total_duration_ms\"[[:space:]]*:[[:space:]]*[0-9]*' | sed 's/.*:[[:space:]]*\\\\([0-9]*\\\\).*/\\\\1/')\n\n # Calculate burn rate ($/hour) from cost and duration\n if [ -n \"$cost_usd\" ] && [ -n \"$total_duration_ms\" ] && [ \"$total_duration_ms\" -gt 0 ]; then\n cost_per_hour=$(echo \"$cost_usd $total_duration_ms\" | awk '{printf \"%.2f\", $1 * 3600000 / $2}')\n fi\n${config.showTokens ? `\n # Token data from native context_window (bash fallback)\n input_tokens=$(echo \"$input\" | grep -o '\"total_input_tokens\"[[:space:]]*:[[:space:]]*[0-9]*' | sed 's/.*:[[:space:]]*\\\\([0-9]*\\\\).*/\\\\1/')\n output_tokens=$(echo \"$input\" | grep -o '\"total_output_tokens\"[[:space:]]*:[[:space:]]*[0-9]*' | sed 's/.*:[[:space:]]*\\\\([0-9]*\\\\).*/\\\\1/')\n\n if [ -n \"$input_tokens\" ] && [ -n \"$output_tokens\" ]; then\n tot_tokens=$(( input_tokens + output_tokens ))\n [ \"$tot_tokens\" -eq 0 ] && tot_tokens=\"\"\n fi` : ''}\n${config.showBurnRate && config.showTokens ? `\n # Calculate tokens per minute from native data\n if [ -n \"$tot_tokens\" ] && [ -n \"$total_duration_ms\" ] && [ \"$total_duration_ms\" -gt 0 ]; then\n tpm=$(echo \"$tot_tokens $total_duration_ms\" | awk '{if ($2 > 0) printf \"%.0f\", $1 * 60000 / $2; else print \"\"}')\n fi` : ''}\nfi\n${needsCcusage ? `\n# Session reset time requires ccusage (only feature that needs external tool)\nif command -v ccusage >/dev/null 2>&1 && [ \"$HAS_JQ\" -eq 1 ]; then\n blocks_output=\"\"\n\n # Try ccusage with timeout\n if command -v timeout >/dev/null 2>&1; then\n blocks_output=$(timeout 5s ccusage blocks --json 2>/dev/null)\n elif command -v gtimeout >/dev/null 2>&1; then\n blocks_output=$(gtimeout 5s ccusage blocks --json 2>/dev/null)\n else\n blocks_output=$(ccusage blocks --json 2>/dev/null)\n fi\n\n if [ -n \"$blocks_output\" ]; then\n active_block=$(echo \"$blocks_output\" | jq -c '.blocks[] | select(.isActive == true)' 2>/dev/null | head -n1)\n if [ -n \"$active_block\" ]; then\n # Session time calculation from ccusage\n reset_time_str=$(echo \"$active_block\" | jq -r '.usageLimitResetTime // .endTime // empty')\n start_time_str=$(echo \"$active_block\" | jq -r '.startTime // empty')\n\n if [ -n \"$reset_time_str\" ] && [ -n \"$start_time_str\" ]; then\n start_sec=$(to_epoch \"$start_time_str\"); end_sec=$(to_epoch \"$reset_time_str\"); now_sec=$(date +%s)\n total=$(( end_sec - start_sec )); (( total<1 )) && total=1\n elapsed=$(( now_sec - start_sec )); (( elapsed<0 ))&&elapsed=0; (( elapsed>total ))&&elapsed=$total\n session_pct=$(( elapsed * 100 / total ))\n remaining=$(( end_sec - now_sec )); (( remaining<0 )) && remaining=0\n rh=$(( remaining / 3600 )); rm=$(( (remaining % 3600) / 60 ))\n end_hm=$(fmt_time_hm \"$end_sec\")${config.showSession ? `\n session_txt=\"$(printf '%dh %dm until reset at %s (%d%%)' \"$rh\" \"$rm\" \"$end_hm\" \"$session_pct\")\"` : ''}${config.showProgressBar ? `\n session_bar=$(progress_bar \"$session_pct\" 10)` : ''}\n fi\n fi\n fi\nfi` : ''}`\n}\n\nexport function generateUsageUtilities(): string {\n return `\n# ---- time helpers ----\nto_epoch() {\n ts=\"$1\"\n if command -v gdate >/dev/null 2>&1; then gdate -d \"$ts\" +%s 2>/dev/null && return; fi\n date -u -j -f \"%Y-%m-%dT%H:%M:%S%z\" \"\\${ts/Z/+0000}\" +%s 2>/dev/null && return\n python3 - \"$ts\" <<'PY' 2>/dev/null\nimport sys, datetime\ns=sys.argv[1].replace('Z','+00:00')\nprint(int(datetime.datetime.fromisoformat(s).timestamp()))\nPY\n}\n\nfmt_time_hm() {\n epoch=\"$1\"\n if date -r 0 +%s >/dev/null 2>&1; then date -r \"$epoch\" +\"%H:%M\"; else date -d \"@$epoch\" +\"%H:%M\"; fi\n}\n\nprogress_bar() {\n pct=\"\\${1:-0}\"; width=\"\\${2:-10}\"\n [[ \"$pct\" =~ ^[0-9]+$ ]] || pct=0; ((pct<0))&&pct=0; ((pct>100))&&pct=100\n filled=$(( pct * width / 100 )); empty=$(( width - filled ))\n printf '%*s' \"$filled\" '' | tr ' ' '='\n printf '%*s' \"$empty\" '' | tr ' ' '-'\n}`\n}\n\nexport function generateUsageDisplayCode(config: UsageFeature, colors: boolean, emojis: boolean): string {\n if (!config.enabled) return ''\n\n let displayCode = ''\n\n if (config.showSession) {\n const sessionEmoji = emojis ? 'āŒ›' : 'session:'\n displayCode += `\n# session time\nif [ -n \"$session_txt\" ]; then\n printf ' ${sessionEmoji} %s%s%s' \"$(session_color)\" \"$session_txt\" \"$(rst)\"${config.showProgressBar ? `\n printf ' %s[%s]%s' \"$(session_color)\" \"$session_bar\" \"$(rst)\"` : ''}\nfi`\n }\n\n if (config.showCost) {\n const costEmoji = emojis ? 'šŸ’µ' : '$'\n displayCode += `\n# cost\nif [ -n \"$cost_usd\" ] && [[ \"$cost_usd\" =~ ^[0-9.]+$ ]]; then\n if [ -n \"$cost_per_hour\" ] && [[ \"$cost_per_hour\" =~ ^[0-9.]+$ ]]; then\n printf ' ${costEmoji} %s$%.2f ($%.2f/h)%s' \"$(cost_color)\" \"$cost_usd\" \"$cost_per_hour\" \"$(rst)\"\n else\n printf ' ${costEmoji} %s$%.2f%s' \"$(cost_color)\" \"$cost_usd\" \"$(rst)\"\n fi\nfi`\n }\n\n if (config.showTokens) {\n const tokenEmoji = emojis ? 'šŸ“Š' : 'tok:'\n displayCode += `\n# tokens\nif [ -n \"$tot_tokens\" ] && [[ \"$tot_tokens\" =~ ^[0-9]+$ ]]; then\n if [ -n \"$tpm\" ] && [[ \"$tpm\" =~ ^[0-9.]+$ ]] && ${config.showBurnRate ? 'true' : 'false'}; then\n printf ' ${tokenEmoji} %s%s tok (%.0f tpm)%s' \"$(usage_color)\" \"$tot_tokens\" \"$tpm\" \"$(rst)\"\n else\n printf ' ${tokenEmoji} %s%s tok%s' \"$(usage_color)\" \"$tot_tokens\" \"$(rst)\"\n fi\nfi`\n }\n\n return displayCode\n}","import { StatuslineConfig } from '../cli/prompts.js'\n\nexport interface ValidationResult {\n isValid: boolean\n errors: string[]\n warnings: string[]\n}\n\nexport function validateConfig(config: StatuslineConfig): ValidationResult {\n const errors: string[] = []\n const warnings: string[] = []\n\n // Validate features\n if (!config.features || config.features.length === 0) {\n errors.push('At least one display feature must be selected')\n }\n\n // Validate runtime\n if (!['bash', 'python', 'node'].includes(config.runtime)) {\n errors.push(`Invalid runtime: ${config.runtime}`)\n }\n\n // Validate theme\n if (!['minimal', 'detailed', 'compact'].includes(config.theme)) {\n errors.push(`Invalid theme: ${config.theme}`)\n }\n\n // Check for usage features without ccusage integration\n const usageFeatures = ['usage', 'session', 'tokens', 'burnrate']\n const hasUsageFeatures = config.features.some(f => usageFeatures.includes(f))\n \n if (hasUsageFeatures && !config.ccusageIntegration) {\n warnings.push('Usage features selected but ccusage integration is disabled. Some features may not work properly.')\n }\n\n // Warn about performance with many features\n if (config.features.length > 5) {\n warnings.push('Many features selected. This may impact statusline performance.')\n }\n\n // Validate color/emoji consistency\n if (config.customEmojis && !config.colors) {\n warnings.push('Custom emojis enabled but colors disabled. Visual distinction may be limited.')\n }\n\n return {\n isValid: errors.length === 0,\n errors,\n warnings\n }\n}\n\nexport function validateDependencies(): {\n jq: boolean\n git: boolean\n ccusage: boolean\n python?: boolean\n node?: boolean\n} {\n // This would check system dependencies\n // For now, return placeholder\n return {\n jq: true, // Would check: command -v jq >/dev/null 2>&1\n git: true, // Would check: command -v git >/dev/null 2>&1\n ccusage: false, // Would check: command -v ccusage >/dev/null 2>&1\n python: true, // Would check: command -v python3 >/dev/null 2>&1\n node: true // Would check: command -v node >/dev/null 2>&1\n }\n}","import { StatuslineConfig } from '../cli/prompts.js'\nimport { promises as fs } from 'fs'\nimport path from 'path'\nimport os from 'os'\nimport inquirer from 'inquirer'\n\nexport async function installStatusline(\n script: string,\n outputPath: string,\n config: StatuslineConfig\n): Promise<void> {\n try {\n // Determine the target directory based on install location\n const isGlobal = config.installLocation === 'global'\n const claudeDir = isGlobal ? path.join(os.homedir(), '.claude') : './.claude'\n const scriptPath = path.join(claudeDir, 'statusline.sh')\n \n // Ensure the directory exists\n await fs.mkdir(claudeDir, { recursive: true })\n\n // Check if statusline.sh already exists\n let shouldWrite = true\n try {\n await fs.access(scriptPath)\n // File exists, ask for confirmation\n const { confirmOverwrite } = await inquirer.prompt([{\n type: 'confirm',\n name: 'confirmOverwrite',\n message: `āš ļø ${isGlobal ? 'Global' : 'Project'} statusline.sh already exists. Overwrite?`,\n default: false\n }])\n shouldWrite = confirmOverwrite\n } catch {\n // File doesn't exist, proceed\n }\n\n if (shouldWrite) {\n // Write the script\n await fs.writeFile(scriptPath, script, { mode: 0o755 })\n } else {\n throw new Error('USER_CANCELLED_OVERWRITE')\n }\n\n // Update settings.json safely\n await updateSettingsJson(claudeDir, 'statusline.sh', isGlobal)\n\n // Note: statusline-config.json removed per user feedback - not needed\n // The statusline script contains all necessary configuration info\n\n } catch (error) {\n throw new Error(`Failed to install statusline: ${error instanceof Error ? error.message : String(error)}`)\n }\n}\n\nasync function updateSettingsJson(claudeDir: string, scriptName: string, isGlobal: boolean): Promise<void> {\n const settingsPath = path.join(claudeDir, 'settings.json')\n \n try {\n let settings: any = {}\n let existingStatusLine: any = null\n \n // Try to read existing settings\n try {\n const settingsContent = await fs.readFile(settingsPath, 'utf-8')\n settings = JSON.parse(settingsContent)\n existingStatusLine = settings.statusLine\n } catch {\n // File doesn't exist or invalid JSON, start fresh\n }\n\n // Check if statusLine already exists\n if (existingStatusLine && existingStatusLine.command) {\n // Only update if it's a statusline.sh command or user confirms\n const isOurStatusline = existingStatusLine.command?.includes('statusline.sh')\n \n if (!isOurStatusline) {\n // There's a different statusline configured, ask user\n const { confirmReplace } = await inquirer.prompt([{\n type: 'confirm',\n name: 'confirmReplace',\n message: `āš ļø ${isGlobal ? 'Global' : 'Project'} settings.json already has a statusLine configured (${existingStatusLine.command}). Replace it?`,\n default: false\n }])\n \n if (!confirmReplace) {\n console.warn('\\nāš ļø Statusline script was saved but settings.json was not updated.')\n console.warn(' Your existing statusLine configuration was preserved.')\n return\n }\n }\n }\n\n // Update statusLine configuration - Windows needs explicit bash command\n const commandPath = process.platform === 'win32'\n ? `bash ${isGlobal ? '.claude' : '.claude'}/${scriptName}`\n : (isGlobal ? `~/.claude/${scriptName}` : `.claude/${scriptName}`)\n \n settings.statusLine = {\n type: 'command',\n command: commandPath,\n padding: 0\n }\n\n // Write updated settings\n await fs.writeFile(settingsPath, JSON.stringify(settings, null, 2))\n \n } catch (error) {\n // Settings update failed, but don't fail the entire installation\n console.warn(`Warning: Could not update settings.json: ${error instanceof Error ? error.message : String(error)}`)\n throw new Error('SETTINGS_UPDATE_FAILED') // Signal that manual config is needed\n }\n}\n\nexport async function checkClaudeCodeSetup(): Promise<{\n hasClaudeDir: boolean\n hasSettings: boolean\n currentStatusline?: string\n}> {\n const claudeDir = './.claude'\n const settingsPath = path.join(claudeDir, 'settings.json')\n \n try {\n const dirExists = await fs.access(claudeDir).then(() => true).catch(() => false)\n const settingsExists = await fs.access(settingsPath).then(() => true).catch(() => false)\n \n let currentStatusline: string | undefined\n \n if (settingsExists) {\n try {\n const settings = JSON.parse(await fs.readFile(settingsPath, 'utf-8'))\n currentStatusline = settings.statusLine?.command\n } catch {\n // Ignore JSON parse errors\n }\n }\n \n return {\n hasClaudeDir: dirExists,\n hasSettings: settingsExists,\n currentStatusline\n }\n } catch {\n return {\n hasClaudeDir: false,\n hasSettings: false\n }\n }\n}"],"mappings":"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","names":["fs","path","process","fs","chalk","ora","path","inquirer","path","os","inquirer","testStatuslineScript","generateMockClaudeInput","chalk","VERSION","previewCommand"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chongdashu/cc-statusline",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "description": "Interactive CLI tool for generating custom Claude Code statuslines",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",