@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 +57 -0
- package/CLAUDE.md +15 -0
- package/README.md +76 -25
- package/dist/index.js +272 -76
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
###
|
|
32
|
-
-
|
|
33
|
-
-
|
|
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**:
|
|
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:
|
|
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
|
|
450
|
-
#
|
|
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
|
-
|
|
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
|
-
|
|
462
|
-
|
|
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
|
|
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
|
|
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.
|
|
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
|
|
584
|
-
|
|
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
|
|
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
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
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
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
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
|
-
|
|
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.
|
|
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":";;;;;;;;;;;;AACA,OAAO,UAAU;AACjB,SAAS,qBAAqB;AAF9B;AAAA;AAAA;AAAA;AAAA;;;ACAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,SAAS,aAAa;AACtB,SAAS,YAAYA,WAAU;AAC/B,OAAOC,WAAU;AASjB,eAAsB,qBAAqB,QAAgB,UAAqC;AAC9F,QAAM,YAAY,KAAK,IAAI;AAE3B,MAAI;AAEF,UAAM,UAAU;AAChB,UAAM,aAAaA,MAAK,KAAK,SAAS,mBAAmB,KAAK,IAAI,CAAC,KAAK;AAExE,UAAMD,IAAG,UAAU,YAAY,QAAQ,EAAE,MAAM,IAAM,CAAC;AAGtD,UAAM,QAAQ,YAAY,wBAAwB;AAGlD,UAAM,SAAS,MAAM,cAAc,YAAY,KAAK,UAAU,KAAK,CAAC;AAGpE,UAAMA,IAAG,OAAO,UAAU,EAAE,MAAM,MAAM;AAAA,IAAC,CAAC;AAE1C,UAAM,gBAAgB,KAAK,IAAI,IAAI;AAEnC,WAAO;AAAA,MACL,SAAS,OAAO;AAAA,MAChB,QAAQ,OAAO;AAAA,MACf,OAAO,OAAO;AAAA,MACd;AAAA,IACF;AAAA,EAEF,SAAS,OAAO;AACd,WAAO;AAAA,MACL,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,MAC5D,eAAe,KAAK,IAAI,IAAI;AAAA,IAC9B;AAAA,EACF;AACF;AAEO,SAAS,wBAAwB,QAAyC;AAC/E,SAAO;AAAA,IACL,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,KAAK;AAAA,IACL,WAAW;AAAA,MACT,aAAa;AAAA,MACb,aAAa;AAAA,IACf;AAAA,IACA,OAAO;AAAA,MACL,IAAI;AAAA,MACJ,cAAc;AAAA,MACd,SAAS;AAAA,IACX;AAAA,IACA,SAAS;AAAA,IACT,cAAc;AAAA,MACZ,MAAM;AAAA,IACR;AAAA,IACA,MAAM;AAAA,MACJ,gBAAgB;AAAA,MAChB,mBAAmB;AAAA;AAAA,MACnB,uBAAuB;AAAA,MACvB,mBAAmB;AAAA,MACnB,qBAAqB;AAAA,IACvB;AAAA,IACA,gBAAgB;AAAA,MACd,oBAAoB;AAAA,MACpB,qBAAqB;AAAA,MACrB,qBAAqB;AAAA,MACrB,eAAe;AAAA,QACb,cAAc;AAAA,QACd,eAAe;AAAA,QACf,6BAA6B;AAAA,QAC7B,yBAAyB;AAAA,MAC3B;AAAA,IACF;AAAA,EACF;AACF;AAEO,SAAS,4BAAiC;AAC/C,SAAO;AAAA,IACL,QAAQ;AAAA,MACN;AAAA,QACE,IAAI;AAAA,QACJ,WAAW;AAAA,QACX,SAAS;AAAA,QACT,qBAAqB;AAAA,QACrB,eAAe;AAAA,QACf,UAAU;AAAA,QACV,OAAO;AAAA,QACP,SAAS;AAAA,QACT,aAAa;AAAA,UACX,aAAa;AAAA,UACb,cAAc;AAAA,UACd,0BAA0B;AAAA,UAC1B,sBAAsB;AAAA,QACxB;AAAA,QACA,aAAa;AAAA,QACb,SAAS;AAAA,QACT,QAAQ,CAAC,0BAA0B;AAAA,QACnC,UAAU;AAAA,UACR,iBAAiB;AAAA,UACjB,6BAA6B;AAAA,UAC7B,aAAa;AAAA,QACf;AAAA,QACA,YAAY;AAAA,UACV,aAAa;AAAA,UACb,WAAW;AAAA,UACX,kBAAkB;AAAA,QACpB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEA,eAAe,cAAc,YAAoB,OAA8E;AAC7H,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,UAAME,WAAU,MAAM,QAAQ,CAAC,UAAU,GAAG;AAAA,MAC1C,OAAO,CAAC,QAAQ,QAAQ,MAAM;AAAA,IAChC,CAAC;AAED,QAAI,SAAS;AACb,QAAI,SAAS;AAEb,IAAAA,SAAQ,OAAO,GAAG,QAAQ,CAAC,SAAS;AAClC,gBAAU,KAAK,SAAS;AAAA,IAC1B,CAAC;AAED,IAAAA,SAAQ,OAAO,GAAG,QAAQ,CAAC,SAAS;AAClC,gBAAU,KAAK,SAAS;AAAA,IAC1B,CAAC;AAED,IAAAA,SAAQ,GAAG,SAAS,CAAC,SAAS;AAC5B,cAAQ;AAAA,QACN,SAAS,SAAS;AAAA,QAClB,QAAQ,OAAO,KAAK;AAAA,QACpB,OAAO,OAAO,KAAK,KAAK;AAAA,MAC1B,CAAC;AAAA,IACH,CAAC;AAED,IAAAA,SAAQ,GAAG,SAAS,CAAC,QAAQ;AAC3B,cAAQ;AAAA,QACN,SAAS;AAAA,QACT,QAAQ;AAAA,QACR,OAAO,IAAI;AAAA,MACb,CAAC;AAAA,IACH,CAAC;AAGD,IAAAA,SAAQ,MAAM,MAAM,KAAK;AACzB,IAAAA,SAAQ,MAAM,IAAI;AAGlB,eAAW,MAAM;AACf,MAAAA,SAAQ,KAAK;AACb,cAAQ;AAAA,QACN,SAAS;AAAA,QACT,QAAQ;AAAA,QACR,OAAO;AAAA,MACT,CAAC;AAAA,IACH,GAAG,GAAI;AAAA,EACT,CAAC;AACH;AAEO,SAAS,kBAAkB,QAAoB,QAKpD;AACA,QAAM,SAAmB,CAAC;AAC1B,QAAM,cAAwB,CAAC;AAG/B,MAAI;AACJ,MAAI,OAAO,gBAAgB,KAAM;AAC/B,kBAAc;AACd,WAAO,KAAK,qCAAqC;AAAA,EACnD,WAAW,OAAO,gBAAgB,KAAK;AACrC,kBAAc;AACd,WAAO,KAAK,mCAAmC;AAAA,EACjD,WAAW,OAAO,gBAAgB,KAAK;AACrC,kBAAc;AAAA,EAChB,OAAO;AACL,kBAAc;AAAA,EAChB;AAGA,MAAI,sBAAsB;AAE1B,MAAI,OAAO,SAAS,SAAS,WAAW,KAAK,CAAC,OAAO,OAAO,SAAS,UAAU,GAAG;AAChF,0BAAsB;AACtB,WAAO,KAAK,wCAAwC;AAAA,EACtD;AAEA,MAAI,OAAO,SAAS,SAAS,OAAO,KAAK,CAAC,OAAO,OAAO,SAAS,MAAM,GAAG;AACxE,0BAAsB;AACtB,WAAO,KAAK,oCAAoC;AAAA,EAClD;AAEA,MAAI,OAAO,SAAS,SAAS,KAAK,KAAK,OAAO,sBAAsB,CAAC,OAAO,OAAO,SAAS,KAAK,GAAG;AAClG,gBAAY,KAAK,mDAAmD;AAAA,EACtE;AAGA,MAAI,OAAO,OAAO;AAChB,WAAO,KAAK,kBAAkB,OAAO,KAAK,EAAE;AAAA,EAC9C;AAEA,MAAI,CAAC,OAAO,SAAS;AACnB,WAAO,KAAK,uCAAuC;AAAA,EACrD;AAGA,MAAI,OAAO,SAAS,SAAS,GAAG;AAC9B,gBAAY,KAAK,6DAA6D;AAAA,EAChF;AAEA,MAAI,OAAO,sBAAsB,OAAO,gBAAgB,KAAK;AAC3D,gBAAY,KAAK,iEAAiE;AAAA,EACpF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AA9OA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA;AAAA;AAAA;AAAA;AAGA,SAAS,YAAYC,WAAU;AAC/B,OAAOC,YAAW;AAClB,OAAOC,UAAS;AAEhB,eAAsB,eAAe,YAAmC;AACtE,UAAQ,IAAID,OAAM,KAAK,qCAA8B,CAAC;AAEtD,MAAI;AAGJ,MAAI;AACF,UAAM,UAAUC,KAAI,kCAAkC,UAAU,KAAK,EAAE,MAAM;AAC7E,aAAS,MAAMF,IAAG,SAAS,YAAY,OAAO;AAC9C,YAAQ,QAAQ,gBAAgB;AAGhC,UAAM,cAAc,OAAO,MAAM,wDAAwD;AACzF,QAAI,aAAa;AACf,cAAQ,IAAIC,OAAM,OAAO,yBAAyB,CAAC;AACnD,cAAQ,IAAI,aAAa,YAAY,CAAC,CAAC,EAAE;AACzC,cAAQ,IAAI,cAAc,YAAY,CAAC,CAAC,EAAE;AAC1C,cAAQ,IAAI,gBAAgB,YAAY,CAAC,CAAC;AAAA,CAAI;AAAA,IAChD;AAGA,UAAM,kBAAkB,OAAO,MAAM,sFAAsF;AAC3H,QAAI,iBAAiB;AACnB,cAAQ,IAAIA,OAAM,KAAK,cAAc,gBAAgB,CAAC,CAAC;AAAA,CAAI,CAAC;AAAA,IAC9D;AAAA,EAEF,SAAS,OAAO;AACd,YAAQ,MAAMA,OAAM,IAAI,iCAA4B,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,EAAE,CAAC;AAC7G;AAAA,EACF;AAGA,QAAM,cAAcC,KAAI,sCAAsC,EAAE,MAAM;AACtE,QAAM,YAAY,wBAAwB;AAE1C,UAAQ,IAAID,OAAM,KAAK,2BAA2B,CAAC;AACnD,UAAQ,IAAIA,OAAM,KAAK,KAAK,UAAU,WAAW,MAAM,CAAC,CAAC,CAAC;AAE1D,QAAM,aAAa,MAAM,qBAAqB,QAAQ,SAAS;AAE/D,MAAI,WAAW,SAAS;AACtB,gBAAY,QAAQ,qBAAqB,WAAW,aAAa,IAAI;AAErE,YAAQ,IAAIA,OAAM,MAAM,6BAAwB,CAAC;AACjD,YAAQ,IAAIA,OAAM,MAAM,SAAI,OAAO,EAAE,CAAC,CAAC;AACvC,YAAQ,IAAI,WAAW,MAAM;AAC7B,YAAQ,IAAIA,OAAM,MAAM,SAAI,OAAO,EAAE,CAAC,CAAC;AAGvC,YAAQ,IAAIA,OAAM,KAAK;AAAA,yBAAqB,oBAAoB,oBAAoB,WAAW,aAAa,CAAC,CAAC,IAAI,oBAAoB,WAAW,aAAa,CAAC,KAAK,WAAW,aAAa,KAAK,CAAC;AAGlM,QAAI,WAAW,OAAO,SAAS,WAAI,KAAK,WAAW,OAAO,SAAS,WAAI,KAAK,WAAW,OAAO,SAAS,WAAI,GAAG;AAC5G,cAAQ,IAAIA,OAAM,MAAM,iDAA4C,CAAC;AAAA,IACvE,OAAO;AACL,cAAQ,IAAIA,OAAM,OAAO,8DAAoD,CAAC;AAAA,IAChF;AAAA,EAEF,OAAO;AACL,gBAAY,KAAK,aAAa;AAC9B,YAAQ,MAAMA,OAAM,IAAI;AAAA,gBAAc,WAAW,KAAK,EAAE,CAAC;AACzD,QAAI,WAAW,QAAQ;AACrB,cAAQ,IAAIA,OAAM,KAAK,mBAAmB,CAAC;AAC3C,cAAQ,IAAI,WAAW,MAAM;AAAA,IAC/B;AAAA,EACF;AAEA,UAAQ,IAAIA,OAAM,MAAM,mFAA8E,CAAC;AACzG;AAEA,SAAS,oBAAoB,aAA6B;AACxD,UAAQ,aAAa;AAAA,IACnB,KAAK;AAAa,aAAO;AAAA,IACzB,KAAK;AAAQ,aAAO;AAAA,IACpB,KAAK;AAAQ,aAAO;AAAA,IACpB,KAAK;AAAW,aAAO;AAAA,IACvB;AAAS,aAAO;AAAA,EAClB;AACF;AAEA,SAAS,oBAAoB,eAA+B;AAC1D,MAAI,gBAAgB,IAAM,QAAO;AACjC,MAAI,gBAAgB,IAAK,QAAO;AAChC,MAAI,gBAAgB,IAAK,QAAO;AAChC,SAAO;AACT;AA5FA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;;;ACFA;AAAA,SAAS,eAAe;;;ACAxB;;;ACAA;AAAA,OAAO,cAAc;AAarB,eAAsB,uBAAkD;AACtE,UAAQ,IAAI,wFAAkF;AAC9F,UAAQ,IAAI,yHAA0G;AAEtH,QAAM,SAAS,MAAM,SAAS,OAAO;AAAA,IACnC;AAAA,MACE,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS;AAAA,MACT,SAAS;AAAA,QACP,EAAE,MAAM,+BAAwB,OAAO,aAAa,SAAS,KAAK;AAAA,QAClE,EAAE,MAAM,wBAAiB,OAAO,OAAO,SAAS,KAAK;AAAA,QACrD,EAAE,MAAM,kCAA2B,OAAO,SAAS,SAAS,KAAK;AAAA,QACjE,EAAE,MAAM,+BAAwB,OAAO,WAAW,SAAS,KAAK;AAAA,QAChE,EAAE,MAAM,0BAAmB,OAAO,SAAS,SAAS,KAAK;AAAA,QACzD,EAAE,MAAM,8BAAuB,OAAO,UAAU,SAAS,KAAK;AAAA,QAC9D,EAAE,MAAM,wCAAmC,OAAO,YAAY,SAAS,KAAK;AAAA,QAC5E,EAAE,MAAM,gDAA2C,OAAO,WAAW,SAAS,MAAM;AAAA,MACtF;AAAA,MACA,UAAU,CAAC,WAAqB;AAC9B,YAAI,OAAO,SAAS,GAAG;AACrB,iBAAO;AAAA,QACT;AACA,eAAO;AAAA,MACT;AAAA,MACA,UAAU;AAAA,IACZ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS;AAAA,MACT,SAAS;AAAA,IACX;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS;AAAA,MACT,SAAS;AAAA,IACX;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS;AAAA,MACT,SAAS;AAAA,QACP,EAAE,MAAM,0DAAmD,OAAO,SAAS;AAAA,QAC3E,EAAE,MAAM,yDAAkD,OAAO,UAAU;AAAA,MAC7E;AAAA,MACA,SAAS;AAAA,IACX;AAAA,EACF,CAAC;AAID,QAAM,eAAe,OAAO,SAAS,SAAS,SAAS;AAEvD,SAAO;AAAA,IACL,UAAU,OAAO;AAAA,IACjB,SAAS;AAAA,IACT,QAAQ,OAAO;AAAA,IACf,OAAO;AAAA,IACP,oBAAoB;AAAA,IACpB,SAAS,OAAO;AAAA,IAChB,cAAc;AAAA,IACd,iBAAiB,OAAO;AAAA,EAC1B;AACF;;;AC9EA;;;ACAA;AAKO,SAAS,sBAAsB,QAA6B;AACjE,MAAI,CAAC,OAAO,SAAS;AACnB,WAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMT;AAEA,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQT;AAEO,SAAS,sBAA8B;AAC5C,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAST;;;ACnCA;AAOO,SAAS,oBAAoB,QAAoB,QAAyB;AAC/E,MAAI,CAAC,OAAO,QAAS,QAAO;AAE5B,QAAM,YAAY,SAAS;AAAA;AAAA;AAAA;AAAA,IAIzB;AAAA;AAAA;AAAA;AAKF,SAAO,GAAG,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAMrB;AAgBO,SAAS,uBAA+B;AAC7C,SAAO;AAAA;AAAA;AAGT;;;AC7CA;AASO,SAAS,sBAAsB,QAAsB,QAAyB;AACnF,MAAI,CAAC,OAAO,QAAS,QAAO;AAE5B,QAAM,YAAY,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAYzB;AAAA;AAAA;AAAA;AAAA;AAAA;AAQF,QAAM,eAAe,OAAO,eAAe,OAAO;AAElD,SAAO,GAAG,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAenB,OAAO,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAQd,EAAE;AAAA,EACR,OAAO,gBAAgB,OAAO,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA,QAKrC,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUR,OAAO,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAQd,EAAE;AAAA,EACR,OAAO,gBAAgB,OAAO,aAAa;AAAA;AAAA;AAAA;AAAA,QAIrC,EAAE;AAAA;AAAA,EAER,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,0CA4ByB,OAAO,cAAc;AAAA,2GAC4C,EAAE,GAAG,OAAO,kBAAkB;AAAA,yDAChF,EAAE;AAAA;AAAA;AAAA;AAAA,MAIrD,EAAE;AACR;AAEO,SAAS,yBAAiC;AAC/C,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAyBT;;;AHjJA,IAAM,UAAU;AAET,SAAS,uBAAuB,QAAkC;AACvE,QAAM,SAAS,OAAO,SAAS,SAAS,KAAK;AAC7C,QAAM,WAAW,OAAO,SAAS,KAAK,OAAK,CAAC,SAAS,WAAW,UAAU,UAAU,EAAE,SAAS,CAAC,CAAC;AACjG,QAAM,eAAe,OAAO,SAAS,SAAS,WAAW;AACzD,QAAM,WAAW,OAAO,SAAS,SAAS,OAAO;AACjD,QAAM,aAAa,OAAO,SAAS,SAAS,SAAS;AAGrD,QAAM,cAAc;AAAA,IAClB,SAAS,YAAY,OAAO;AAAA,IAC5B,UAAU,OAAO,SAAS,SAAS,OAAO;AAAA,IAC1C,YAAY,OAAO,SAAS,SAAS,QAAQ;AAAA,IAC7C,cAAc,OAAO,SAAS,SAAS,UAAU;AAAA,IACjD,aAAa,OAAO,SAAS,SAAS,SAAS;AAAA,IAC/C,iBAAiB,OAAO,UAAU,aAAa,OAAO,SAAS,SAAS,SAAS;AAAA,EACnF;AAGA,QAAM,YAAY;AAAA,IAChB,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,aAAa;AAAA;AAAA,IACb,aAAa,OAAO,UAAU;AAAA,EAChC;AAEA,QAAM,aAAY,oBAAI,KAAK,GAAE,YAAY;AACzC,QAAM,SAAS;AAAA,gCACe,OAAO;AAAA,6CACM,SAAS;AAAA,WAC3C,OAAO,KAAK,cAAc,OAAO,MAAM,gBAAgB,OAAO,SAAS,KAAK,IAAI,CAAC;AAAA,sBACtE,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAS3B,OAAO,UAAU,oBAAoB,IAAI,EAAE;AAAA,EAC3C,sBAAsB,EAAE,SAAS,OAAO,QAAQ,OAAO,OAAO,MAAM,CAAC,CAAC;AAAA,EACtE,OAAO,SAAS,oBAAoB,IAAI,EAAE;AAAA,EAC1C,WAAW,uBAAuB,IAAI,EAAE;AAAA,EACxC,SAAS,qBAAqB,IAAI,EAAE;AAAA,EACpC,4BAA4B,cAAc,UAAU,UAAU,CAAC;AAAA,EAC/D,SAAS,oBAAoB,WAAW,OAAO,MAAM,IAAI,EAAE;AAAA,EAC3D,aAAa,wBAAwB,OAAO,MAAM,IAAI,EAAE;AAAA,EACxD,WAAW,sBAAsB,aAAa,OAAO,MAAM,IAAI,EAAE;AAAA,EACjE,OAAO,UAAU,sBAAsB,IAAI,EAAE;AAAA,EAC7C,uBAAuB,QAAQ,WAAW,WAAW,CAAC;AAAA;AAGtD,SAAO,OAAO,QAAQ,YAAY,MAAM,EAAE,KAAK,IAAI;AACrD;AAEA,SAAS,sBAA8B;AACrC,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAoBT;AAEA,SAAS,4BAAoC;AAC3C,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiCT;AAEA,SAAS,4BAA4B,cAAuB,UAAmB,YAA6B;AAC1G,SAAO;AAAA,EACP,0BAA0B,CAAC;AAAA;AAAA,8BAEC,eAAe;AAAA,yHAC4E,EAAE,GAAG,WAAW;AAAA;AAAA,+EAE1D,EAAE,GAAG,aAAa;AAAA,yEACxB,EAAE;AAAA;AAAA;AAAA,MAGrE,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,6DAYwC,EAAE,GAAG,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,2DAMlB,EAAE,GAAG,aAAa;AAAA,gEACb,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOlE;AAEA,SAAS,wBAAwB,QAAyB;AACxD,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAqCT;AAEA,SAAS,wBAAgC;AACvC,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAST;AAEA,SAAS,uBAAuB,QAA0B,WAAgB,aAA0B;AAClG,QAAM,SAAS,OAAO,UAAU,CAAC,OAAO;AAExC,SAAO;AAAA;AAAA;AAAA,EAGP,OAAO,SAAS,SAAS,WAAW,IAAI,qEAA8D,EAAE,GAAG,UAAU,UAAU;AAAA;AAAA;AAAA,MAG3H,EAAE,GAAG,OAAO,SAAS,SAAS,OAAO,IAAI;AAAA;AAAA;AAAA;AAAA,MAIzC,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,UASE,OAAO,SAAS,SAAS,SAAS,IAAI;AAAA;AAAA;AAAA;AAAA,MAI1C,EAAE,GAAG,YAAY,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAO/B,EAAE,GAAG,OAAO,SAAS,SAAS,SAAS,IAAI;AAAA;AAAA;AAAA,MAG3C,EAAE;AAAA;AAAA;AAAA,UAGE,YAAY,WAAW;AAAA,+DAC8B,YAAY,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAMlF;AAAA,uEACwD;AAAA,MAC1D,EAAE,GAAG,YAAY,aAAa;AAAA,kEAC8B,YAAY,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAcrF;AAAA;AAAA;AAAA;AAAA;AAAA,KAKH;AAAA,MACC,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUR;;;AIpSA;AAQO,SAAS,eAAe,QAA4C;AACzE,QAAM,SAAmB,CAAC;AAC1B,QAAM,WAAqB,CAAC;AAG5B,MAAI,CAAC,OAAO,YAAY,OAAO,SAAS,WAAW,GAAG;AACpD,WAAO,KAAK,+CAA+C;AAAA,EAC7D;AAGA,MAAI,CAAC,CAAC,QAAQ,UAAU,MAAM,EAAE,SAAS,OAAO,OAAO,GAAG;AACxD,WAAO,KAAK,oBAAoB,OAAO,OAAO,EAAE;AAAA,EAClD;AAGA,MAAI,CAAC,CAAC,WAAW,YAAY,SAAS,EAAE,SAAS,OAAO,KAAK,GAAG;AAC9D,WAAO,KAAK,kBAAkB,OAAO,KAAK,EAAE;AAAA,EAC9C;AAGA,QAAM,gBAAgB,CAAC,SAAS,WAAW,UAAU,UAAU;AAC/D,QAAM,mBAAmB,OAAO,SAAS,KAAK,OAAK,cAAc,SAAS,CAAC,CAAC;AAE5E,MAAI,oBAAoB,CAAC,OAAO,oBAAoB;AAClD,aAAS,KAAK,mGAAmG;AAAA,EACnH;AAGA,MAAI,OAAO,SAAS,SAAS,GAAG;AAC9B,aAAS,KAAK,iEAAiE;AAAA,EACjF;AAGA,MAAI,OAAO,gBAAgB,CAAC,OAAO,QAAQ;AACzC,aAAS,KAAK,+EAA+E;AAAA,EAC/F;AAEA,SAAO;AAAA,IACL,SAAS,OAAO,WAAW;AAAA,IAC3B;AAAA,IACA;AAAA,EACF;AACF;;;AClDA;AACA,SAAS,YAAY,UAAU;AAC/B,OAAOE,WAAU;AACjB,OAAO,QAAQ;AACf,OAAOC,eAAc;AAErB,eAAsB,kBACpB,QACA,YACA,QACe;AACf,MAAI;AAEF,UAAM,WAAW,OAAO,oBAAoB;AAC5C,UAAM,YAAY,WAAWD,MAAK,KAAK,GAAG,QAAQ,GAAG,SAAS,IAAI;AAClE,UAAM,aAAaA,MAAK,KAAK,WAAW,eAAe;AAGvD,UAAM,GAAG,MAAM,WAAW,EAAE,WAAW,KAAK,CAAC;AAG7C,QAAI,cAAc;AAClB,QAAI;AACF,YAAM,GAAG,OAAO,UAAU;AAE1B,YAAM,EAAE,iBAAiB,IAAI,MAAMC,UAAS,OAAO,CAAC;AAAA,QAClD,MAAM;AAAA,QACN,MAAM;AAAA,QACN,SAAS,iBAAO,WAAW,WAAW,SAAS;AAAA,QAC/C,SAAS;AAAA,MACX,CAAC,CAAC;AACF,oBAAc;AAAA,IAChB,QAAQ;AAAA,IAER;AAEA,QAAI,aAAa;AAEf,YAAM,GAAG,UAAU,YAAY,QAAQ,EAAE,MAAM,IAAM,CAAC;AAAA,IACxD,OAAO;AACL,YAAM,IAAI,MAAM,0BAA0B;AAAA,IAC5C;AAGA,UAAM,mBAAmB,WAAW,iBAAiB,QAAQ;AAAA,EAK/D,SAAS,OAAO;AACd,UAAM,IAAI,MAAM,iCAAiC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,EAAE;AAAA,EAC3G;AACF;AAEA,eAAe,mBAAmB,WAAmB,YAAoB,UAAkC;AAtD3G;AAuDE,QAAM,eAAeD,MAAK,KAAK,WAAW,eAAe;AAEzD,MAAI;AACF,QAAI,WAAgB,CAAC;AACrB,QAAI,qBAA0B;AAG9B,QAAI;AACF,YAAM,kBAAkB,MAAM,GAAG,SAAS,cAAc,OAAO;AAC/D,iBAAW,KAAK,MAAM,eAAe;AACrC,2BAAqB,SAAS;AAAA,IAChC,QAAQ;AAAA,IAER;AAGA,QAAI,sBAAsB,mBAAmB,SAAS;AAEpD,YAAM,mBAAkB,wBAAmB,YAAnB,mBAA4B,SAAS;AAE7D,UAAI,CAAC,iBAAiB;AAEpB,cAAM,EAAE,eAAe,IAAI,MAAMC,UAAS,OAAO,CAAC;AAAA,UAChD,MAAM;AAAA,UACN,MAAM;AAAA,UACN,SAAS,iBAAO,WAAW,WAAW,SAAS,uDAAuD,mBAAmB,OAAO;AAAA,UAChI,SAAS;AAAA,QACX,CAAC,CAAC;AAEF,YAAI,CAAC,gBAAgB;AACnB,kBAAQ,KAAK,gFAAsE;AACnF,kBAAQ,KAAK,0DAA0D;AACvE;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAGA,UAAM,cAAc,QAAQ,aAAa,UACrC,QAAQ,WAAW,YAAY,SAAS,IAAI,UAAU,KACrD,WAAW,aAAa,UAAU,KAAK,WAAW,UAAU;AAEjE,aAAS,aAAa;AAAA,MACpB,MAAM;AAAA,MACN,SAAS;AAAA,MACT,SAAS;AAAA,IACX;AAGA,UAAM,GAAG,UAAU,cAAc,KAAK,UAAU,UAAU,MAAM,CAAC,CAAC;AAAA,EAEpE,SAAS,OAAO;AAEd,YAAQ,KAAK,4CAA4C,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,EAAE;AACjH,UAAM,IAAI,MAAM,wBAAwB;AAAA,EAC1C;AACF;;;AP3GA,OAAO,WAAW;AAClB,OAAO,SAAS;AAChB,OAAOC,WAAU;AACjB,OAAOC,SAAQ;AACf,SAAS,gBAAgB;AAOzB,SAAS,sBAA+B;AACtC,MAAI;AACF,aAAS,iBAAiB,EAAE,OAAO,SAAS,CAAC;AAC7C,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,2BAAmC;AAC1C,QAAM,WAAW,QAAQ;AAEzB,MAAI,aAAa,UAAU;AACzB,WAAO;AAAA,EACT,MAAM,KAAK,8DAAuD,CAAC;AAAA;AAAA,EAEnE,MAAM,MAAM,+BAA+B,CAAC;AAAA;AAAA;AAAA,EAG5C,MAAM,MAAM,iBAAiB,CAAC;AAAA;AAAA;AAAA,EAG9B,MAAM,MAAM,uBAAuB,CAAC;AAAA;AAAA;AAAA,EAGpC,WAAW,aAAa,SAAS;AAC/B,WAAO;AAAA,EACT,MAAM,KAAK,8DAAuD,CAAC;AAAA;AAAA,EAEnE,MAAM,MAAM,gBAAgB,CAAC;AAAA;AAAA;AAAA,EAG7B,MAAM,MAAM,qBAAqB,CAAC;AAAA;AAAA;AAAA,EAGlC,MAAM,MAAM,aAAa,CAAC;AAAA;AAAA;AAAA,EAG1B,MAAM,MAAM,uBAAuB,CAAC;AAAA;AAAA;AAAA,EAGpC,WAAW,aAAa,SAAS;AAC/B,WAAO;AAAA,EACT,MAAM,KAAK,8DAAuD,CAAC;AAAA;AAAA,EAEnE,MAAM,MAAM,iCAAiC,CAAC;AAAA,IAC5C,MAAM,IAAI,aAAa,CAAC;AAAA,IACxB,MAAM,IAAI,QAAQ,CAAC;AAAA;AAAA,EAErB,MAAM,MAAM,2BAA2B,CAAC;AAAA;AAAA;AAAA,OAGnC,MAAM,IAAI,wBAAmB,CAAC;AAAA,OAC9B,MAAM,IAAI,wBAAmB,CAAC;AAAA;AAAA,wCAEG,MAAM,IAAI,kBAAkB,CAAC;AAAA;AAAA;AAAA,EAGnE,OAAO;AACL,WAAO;AAAA,EACT,MAAM,KAAK,8DAAuD,CAAC;AAAA;AAAA,EAEnE,MAAM,MAAM,6BAA6B,CAAC;AAAA;AAAA;AAAA,EAG1C;AACF;AAEA,eAAsB,YAAY,SAAqC;AACrE,MAAI;AACF,UAAM,UAAU,IAAI,sCAAsC,EAAE,MAAM;AAClE,UAAM,IAAI,QAAQ,aAAW,WAAW,SAAS,GAAG,CAAC;AACrD,YAAQ,KAAK;AAGb,UAAM,QAAQ,oBAAoB;AAClC,QAAI,CAAC,OAAO;AACV,cAAQ,IAAI,MAAM,OAAO,qCAA2B,CAAC;AACrD,cAAQ,IAAI,MAAM,IAAI,uEAAuE,CAAC;AAC9F,cAAQ,IAAI,MAAM,IAAI,0DAAsD,CAAC;AAC7E,cAAQ,IAAI,MAAM,IAAI,wCAAmC,CAAC;AAC1D,cAAQ,IAAI,MAAM,IAAI,qCAAgC,CAAC;AACvD,cAAQ,IAAI,yBAAyB,CAAC;AAGtC,YAAMC,aAAY,MAAM,OAAO,UAAU,GAAG;AAC5C,YAAM,EAAE,kBAAkB,IAAI,MAAMA,UAAS,OAAO,CAAC;AAAA,QACnD,MAAM;AAAA,QACN,MAAM;AAAA,QACN,SAAS;AAAA,QACT,SAAS;AAAA,MACX,CAAC,CAAC;AAEF,UAAI,CAAC,mBAAmB;AACtB,gBAAQ,IAAI,MAAM,KAAK,mDAA4C,CAAC;AACpE,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAAA,IACF;AAGA,UAAM,SAAS,MAAM,qBAAqB;AAG1C,UAAM,aAAa,eAAe,MAAM;AACxC,QAAI,CAAC,WAAW,SAAS;AACvB,cAAQ,MAAM,MAAM,IAAI,yCAAoC,CAAC;AAC7D,iBAAW,OAAO,QAAQ,WAAS,QAAQ,MAAM,MAAM,IAAI,aAAQ,KAAK,EAAE,CAAC,CAAC;AAC5E,cAAQ,KAAK,CAAC;AAAA,IAChB;AAGA,UAAM,oBAAoB,IAAI,iCAAiC,EAAE,MAAM;AAEvE,UAAM,SAAS,uBAAuB,MAAM;AAC5C,UAAM,WAAW;AAEjB,sBAAkB,QAAQ,8BAA8B;AAGxD,YAAQ,IAAI,MAAM,KAAK,0CAAqC,CAAC;AAC7D,YAAQ,IAAI,MAAM,MAAM,SAAI,OAAO,EAAE,CAAC,CAAC;AAGvC,UAAM,EAAE,sBAAAC,uBAAsB,yBAAAC,yBAAwB,IAAI,MAAM;AAChE,UAAM,YAAYA,yBAAwB;AAC1C,UAAM,aAAa,MAAMD,sBAAqB,QAAQ,SAAS;AAE/D,QAAI,WAAW,SAAS;AACtB,cAAQ,IAAI,WAAW,MAAM;AAAA,IAC/B,OAAO;AACL,cAAQ,IAAI,MAAM,KAAK,2FAA+D,CAAC;AACvF,cAAQ,IAAI,MAAM,KAAK,4DAA4D,CAAC;AAAA,IACtF;AAEA,YAAQ,IAAI,MAAM,MAAM,SAAI,OAAO,EAAE,CAAC,CAAC;AAGvC,UAAM,WAAW,OAAO,oBAAoB;AAC5C,UAAM,UAAU,WAAWF,IAAG,QAAQ,IAAI;AAC1C,UAAM,aAAa,QAAQ,UAAUD,MAAK,KAAK,SAAS,WAAW,QAAQ;AAC3E,UAAM,eAAeA,MAAK,QAAQ,UAAU;AAG5C,QAAI,QAAQ,YAAY,OAAO;AAC7B,cAAQ,IAAI,MAAM,KAAK,sCAA+B,CAAC;AAEvD,UAAI;AACF,cAAM,kBAAkB,QAAQ,cAAc,MAAM;AAEpD,gBAAQ,IAAI,MAAM,MAAM,gCAA2B,CAAC;AACpD,gBAAQ,IAAI,MAAM,MAAM,uDAAgD,CAAC;AACzE,gBAAQ,IAAI,MAAM,KAAK;AAAA,YAAQ,WAAW,WAAW,SAAS,2BAA2B,MAAM,MAAM,YAAY,CAAC,EAAE,CAAC;AACrH,gBAAQ,IAAI,MAAM,KAAK,eAAe,CAAC;AACvC,gBAAQ,IAAI,MAAM,MAAM,sDAAsD,CAAC;AAC/E,YAAI,OAAO,SAAS,SAAS,SAAS,GAAG;AACvC,kBAAQ,IAAI,MAAM,MAAM,+DAA+D,CAAC;AAAA,QAC1F;AAAA,MAEF,SAAS,OAAO;AACd,gBAAQ,IAAI,MAAM,IAAI,uCAAkC,CAAC;AAEzD,YAAI,iBAAiB,SAAS,MAAM,YAAY,4BAA4B;AAC1E,kBAAQ,IAAI,MAAM,OAAO,qFAA2E,CAAC;AAAA,QACvG,WAAW,iBAAiB,SAAS,MAAM,YAAY,0BAA0B;AAC/E,gBAAM,cAAc,WAAW,4BAA4B;AAC3D,kBAAQ,IAAI,MAAM,OAAO,mEAAyD,CAAC;AACnF,kBAAQ,IAAI,MAAM,KAAK,kCAAkC,CAAC;AAC1D,kBAAQ,IAAI,MAAM,MAAM,oBAAoB,WAAW,cAAc,SAAS,sBAAsB,CAAC;AACrG,kBAAQ,IAAI,MAAM,KAAK,KAAK,CAAC;AAC7B,kBAAQ,IAAI,MAAM,KAAK,mBAAmB,CAAC;AAC3C,kBAAQ,IAAI,MAAM,KAAK,wBAAwB,CAAC;AAChD,kBAAQ,IAAI,MAAM,KAAK,mBAAmB,WAAW,IAAI,CAAC;AAC1D,kBAAQ,IAAI,MAAM,KAAK,kBAAkB,CAAC;AAC1C,kBAAQ,IAAI,MAAM,KAAK,KAAK,CAAC;AAC7B,kBAAQ,IAAI,MAAM,KAAK,GAAG,CAAC;AAC3B,kBAAQ,IAAI,MAAM,KAAK;AAAA,wCAAoC,MAAM,MAAM,YAAY,CAAC,EAAE,CAAC;AAAA,QACzF,OAAO;AACL,kBAAQ,MAAM,MAAM,IAAI,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,EAAE,CAAC;AAC3F,kBAAQ,IAAI,MAAM,KAAK;AAAA,iDAA6C,MAAM,MAAM,YAAY,CAAC,EAAE,CAAC;AAAA,QAClG;AAAA,MACF;AAAA,IACF,OAAO;AAEL,cAAQ,IAAI,MAAM,MAAM,6CAAwC,CAAC;AACjE,cAAQ,IAAI,MAAM,KAAK;AAAA,iCAA6B,MAAM,MAAM,YAAY,CAAC,EAAE,CAAC;AAChF,cAAQ,IAAI,MAAM,KAAK,wDAAwD,CAAC;AAAA,IAClF;AAAA,EAEF,SAAS,OAAO;AACd,YAAQ,MAAM,MAAM,IAAI,2BAAsB,CAAC;AAC/C,YAAQ,MAAM,MAAM,IAAI,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,CAAC;AAC/E,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;;;AD9MA,OAAOK,YAAW;AAGlB,IAAMC,WAAU;AAEhB,IAAM,UAAU,IAAI,QAAQ;AAE5B,QACG,KAAK,eAAe,EACpB,YAAY,oEAAoE,EAChF,QAAQA,QAAO;AAElB,QACG,QAAQ,MAAM,EACd,YAAY,qDAAqD,EACjE,OAAO,uBAAuB,iCAAiC,yBAAyB,EACxF,OAAO,gBAAgB,sDAAuD,EAC9E,OAAO,WAAW;AAErB,QACG,QAAQ,SAAS,EACjB,YAAY,+CAA+C,EAC3D,SAAS,iBAAiB,uCAAuC,EACjE,OAAO,OAAO,eAAe;AAC5B,QAAM,EAAE,gBAAAC,gBAAe,IAAI,MAAM;AACjC,QAAMA,gBAAe,UAAU;AACjC,CAAC;AAEH,QACG,QAAQ,MAAM,EACd,YAAY,kDAAkD,EAC9D,OAAO,uBAAuB,4BAA4B,EAC1D,OAAO,MAAM;AACZ,UAAQ,IAAIF,OAAM,OAAO,2BAA2B,CAAC;AACvD,CAAC;AAGH,IAAI,CAAC,QAAQ,KAAK,MAAM,CAAC,EAAE,QAAQ;AACjC,UAAQ,WAAW;AACrB;AAEA,QAAQ,MAAM,QAAQ,IAAI;","names":["fs","path","process","fs","chalk","ora","path","inquirer","path","os","inquirer","testStatuslineScript","generateMockClaudeInput","chalk","VERSION","previewCommand"]}
|