@chongdashu/cc-statusline 1.0.1 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,31 @@ 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.1.0] - 2025-08-19
9
+
10
+ ### Added
11
+ - 🧠 **Context Window Tracking** - Dynamic model-aware context window monitoring with progress bars
12
+ - šŸ“± **Multi-line Layout** - Clean separation of core info (line 1) and usage analytics (line 2)
13
+ - šŸŽÆ **TBD Fallback Display** - Shows "Context Left: TBD" when context information unavailable
14
+ - šŸŽØ **Enhanced Color Schemes** - Distinct colors for context (green/yellow/red) vs session time (blue/cyan)
15
+ - šŸ“Š **Intelligent Progress Bars** - Visual context depletion bars showing remaining vs used tokens
16
+ - šŸ¤– **Dynamic Model Detection** - Automatic context limits: 200K (modern), 100K (legacy Claude 3 Haiku)
17
+
18
+ ### Changed
19
+ - **Core Features**: Context window tracking now included as default core feature
20
+ - **Display Format**: More intuitive "Context Left: X%" instead of token fractions
21
+ - **Progress Bar Logic**: Bars now show depletion (filled = remaining) instead of usage
22
+ - **Layout Organization**: Usage analytics moved to dedicated second line for better readability
23
+ - **CLI Prompts**: Enhanced feature selection with context window prominently featured
24
+ - **Logging**: Debug logging now off by default, configurable during setup
25
+
26
+ ### Technical Improvements
27
+ - Enhanced `generateUsageLineContent()` function for organized analytics display
28
+ - Improved bash script generation with model-aware context calculation
29
+ - Updated README with multi-line examples and comprehensive feature documentation
30
+ - Added `get_max_context()` function with pattern matching for all Claude model variants
31
+ - Refined color management with context-aware schemes
32
+
8
33
  ## [1.0.1] - 2025-08-13
9
34
 
10
35
  ### Added
package/README.md CHANGED
@@ -1,135 +1,156 @@
1
1
  # cc-statusline
2
2
 
3
- šŸš€ **Dead simple statusline generator for Claude Code**
3
+ <div align="center">
4
4
 
5
- Transform your Claude Code experience with a beautiful, informative statusline showing directory, git branch, model info, usage stats, and more.
5
+ šŸš€ **Transform your Claude Code experience with a beautiful, informative statusline**
6
6
 
7
- ## ⚔ Super Quick Start
7
+ <img src="docs/images/cc-statusline-running.gif" alt="cc-statusline in action" width="600">
8
8
 
9
- **Just run this one command:**
9
+ *Real-time directory, git branch, model info, costs, and session time tracking*
10
10
 
11
- ```bash
12
- npx @chongdashu/cc-statusline init
13
- ```
11
+ [![npm version](https://badge.fury.io/js/@chongdashu%2Fcc-statusline.svg)](https://www.npmjs.com/package/@chongdashu/cc-statusline)
12
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
13
+ [![Node.js](https://img.shields.io/badge/Node.js-16%2B-green.svg)](https://nodejs.org/)
14
14
 
15
- That's it! Answer 2 simple questions and restart Claude Code. Done! šŸŽ‰
15
+ </div>
16
16
 
17
- ### What you get:
18
- - šŸ“ Current directory
19
- - 🌿 Git branch
20
- - šŸ¤– Claude model info
21
- - šŸ’µ Real-time costs
22
- - āŒ› Session time remaining
23
- - Plus optional token stats and burn rate
17
+ ## ⚔ Quick Start
24
18
 
25
- ### Sample result:
26
- ```
27
- šŸ“ ~/my-project 🌿 main šŸ¤– Opus 4.1 šŸ’µ $2.48 ($12.50/h) āŒ› 2h 15m until reset (68%)
28
- ```
29
-
30
- ## šŸŽÆ More Options
19
+ **One command. Two questions. Beautiful statusline. ✨**
31
20
 
32
21
  ```bash
33
- # Preview an existing statusline.sh with mock data
34
- cc-statusline preview .claude/statusline.sh
35
-
36
- # Generate to custom location
37
- cc-statusline init --output ./my-statusline.sh
38
-
39
- # Skip auto-installation
40
- cc-statusline init --no-install
22
+ npx @chongdashu/cc-statusline init
41
23
  ```
42
24
 
43
- **How preview works:**
44
- The `preview` command takes a path to an existing `statusline.sh` file and:
45
- 1. **Loads** your actual statusline script
46
- 2. **Runs** it with fake Claude Code data (directory: `/home/user/projects/my-project`, model: `Opus 4.1`, mock usage stats)
47
- 3. **Shows** you exactly what the output looks like
48
- 4. **Reports** performance and basic functionality
49
-
50
- Perfect for testing your statusline changes before restarting Claude Code.
25
+ That's it! Answer 2 simple questions, restart Claude Code, and enjoy your new statusline.
51
26
 
52
- ### Global Installation
53
- ```bash
54
- # If you prefer global install
55
- npm install -g @chongdashu/cc-statusline
56
- cc-statusline init
57
- ```
27
+ ## šŸŽÆ Setup with just 1 command
58
28
 
59
- ## šŸŽ›ļø Available Features
29
+ <img src="docs/images/cc-statusline-init.gif" alt="Demo of cc-statusline setup" width="500">
60
30
 
61
- **Default features (pre-selected):**
62
- - šŸ“ **Working Directory** - Current folder with `~` shorthand
63
- - 🌿 **Git Branch** - Current branch name
64
- - šŸ¤– **Model Name** - Which Claude model you're using
65
- - šŸ’µ **Usage & Cost** - Real-time cost tracking (requires ccusage)
66
- - āŒ› **Session Time** - Time until usage limit resets
31
+ ## ✨ What You Get
67
32
 
68
- **Optional features:**
69
- - šŸ“Š **Token Statistics** - Total tokens used this session
70
- - ⚔ **Burn Rate** - Tokens consumed per minute
33
+ Transform your bland Claude Code terminal into an information-rich powerhouse:
71
34
 
72
- ## āš™ļø How It Works
35
+ - **šŸ“ Smart Directory Display** - Current folder with `~` abbreviation
36
+ - **🌿 Git Integration** - Current branch name with clean styling
37
+ - **šŸ¤– Model Intelligence** - Shows which Claude model you're using
38
+ - **🧠 Context Window Tracking** - Dynamic model-aware context tracking with progress bar
39
+ - **šŸ’µ Real-Time Cost Tracking** - Live cost monitoring via ccusage integration
40
+ - **āŒ› Session Management** - Time remaining until usage limit resets with progress bars
41
+ - **šŸ“Š Advanced Analytics** - Optional token consumption and burn rate metrics
42
+ - **šŸŽØ Distinct Color Schemes** - Context (green/yellow/red) vs Session (blue/cyan) colors
43
+ - **šŸ“ Optional Debug Logging** - Detailed logging to .claude/statusline.log (off by default)
44
+ - **⚔ Lightning Fast** - Optimized bash script with <100ms execution time
73
45
 
74
- **Two simple questions:**
75
- 1. **What to show** - Pick features from a checklist (directory, git, model, costs, etc.)
76
- 2. **Colors & emojis** - Enable/disable colors and emoji icons
46
+ ## šŸŽ›ļø Features Overview
77
47
 
78
- **Then it:**
79
- - Generates a bash script optimized for speed
80
- - Auto-installs to `.claude/statusline.sh`
81
- - Updates your `.claude/settings.json`
82
- - Shows you a preview of what it looks like
48
+ ### šŸ”„ Default Features (Pre-selected)
49
+ | Feature | Description | Example |
50
+ |---------|-------------|---------|
51
+ | šŸ“ **Directory** | Current working directory | `~/my-project` |
52
+ | 🌿 **Git Branch** | Active git branch | `main` |
53
+ | šŸ¤– **Model** | Claude model name & version | `Opus 4.1` |
54
+ | 🧠 **Context Window** | Model-aware context tracking with progress bar | `Context Left: 58% [■■■■■■▔▔▔▔]` |
55
+ | šŸ’µ **Usage & Cost** | Real-time costs with hourly rate | `$2.48 ($12.50/h)` |
56
+ | āŒ› **Session Time** | Time until reset with progress | `2h 15m until reset (68%)` |
83
57
 
84
- **Requirements:**
85
- - Claude Code (obviously! šŸ˜„)
86
- - `jq` command (usually pre-installed)
87
- - `ccusage` for usage stats (works via `npx ccusage@latest` - no install needed)
58
+ ### šŸš€ Optional Power Features
59
+ | Feature | Description | Example |
60
+ |---------|-------------|---------|
61
+ | šŸ“Š **Token Stats** | Total tokens consumed | `45,230 tok` |
62
+ | ⚔ **Burn Rate** | Tokens per minute | `847 tpm` |
88
63
 
89
- ## šŸŽØ Example Outputs
64
+ ### šŸŽØ Example Outputs
90
65
 
91
- **Minimal setup:**
66
+ **Minimal Setup:**
92
67
  ```
93
68
  šŸ“ ~/my-app 🌿 main šŸ¤– Claude Sonnet
94
69
  ```
95
70
 
96
- **With usage tracking:**
71
+ **With Context Tracking:**
97
72
  ```
98
- šŸ“ ~/my-app 🌿 main šŸ¤– Opus 4.1 šŸ’µ $2.48 ($12.50/h)
73
+ šŸ“ ~/my-app 🌿 main šŸ¤– Sonnet 4 🧠 Context Left: 58% [■■■■■■▔▔▔▔]
99
74
  ```
100
75
 
101
- **Full features:**
76
+ **Full Power Mode (Multi-line):**
77
+ ```
78
+ šŸ“ ~/projects/ai-tools 🌿 feature/statusline šŸ¤– Opus 4.1 🧠 Context Left: 51% [■■■■■▔▔▔▔▔]
79
+ āŒ› 2h 15m until reset (68%) [======----] šŸ’µ $16.40 ($7.41/h) šŸ“Š 64,080 tok (850 tpm)
80
+ ```
81
+
82
+ ## šŸ› ļø Advanced Usage
83
+
84
+ ### Preview Your Statusline
85
+ Test your statusline before restarting Claude Code:
86
+
87
+ ```bash
88
+ cc-statusline preview .claude/statusline.sh
102
89
  ```
103
- šŸ“ ~/projects/my-app 🌿 main šŸ¤– Opus 4.1 āŒ› 2h 15m until reset (68%) [======----] šŸ’µ $2.48 ($12.50/h)
90
+
91
+ **What preview does:**
92
+ 1. šŸ“„ **Loads** your actual statusline script
93
+ 2. 🧪 **Runs** it with realistic mock data
94
+ 3. šŸ“Š **Shows** exactly what the output will look like
95
+ 4. ⚔ **Reports** performance metrics and functionality
96
+
97
+ ### Custom Installation
98
+ ```bash
99
+ # Generate to custom location
100
+ cc-statusline init --output ./my-statusline.sh
101
+
102
+ # Skip auto-installation (manual setup)
103
+ cc-statusline init --no-install
104
+
105
+ # Global installation for convenience
106
+ npm install -g @chongdashu/cc-statusline
104
107
  ```
105
108
 
106
- ## šŸ“‹ Dependencies
109
+ ## šŸ”§ How It Works
110
+
111
+ ### The Magic Behind The Scenes
112
+
113
+ 1. **šŸŽÆ Smart Configuration** - Two intuitive questions configure everything
114
+ 2. **šŸ—ļø Intelligent Generation** - Creates optimized bash script tailored to your needs
115
+ 3. **āš™ļø Auto-Installation** - Seamlessly integrates with Claude Code settings
116
+ 4. **šŸ”„ Real-Time Updates** - Connects to ccusage for live usage statistics
107
117
 
108
- **Required:**
109
- - Claude Code (the tool you're already using!)
110
- - `jq` for JSON processing (pre-installed on most systems)
118
+ ### Technical Architecture
111
119
 
112
- **Optional:**
113
- - `git` for branch display
114
- - `ccusage` for usage stats (auto-installs via npx when needed)
120
+ - **⚔ Bash-First** - Native shell execution for maximum speed
121
+ - **šŸŽØ TTY-Aware** - Automatically detects terminal capabilities
122
+ - **šŸŒ Environment Respect** - Honors `NO_COLOR` and other conventions
123
+ - **šŸ“¦ Zero Dependencies** - Self-contained script with graceful fallbacks
124
+ - **šŸ”’ Secure** - No network requests except ccusage integration
115
125
 
116
- **Check if you're ready:**
126
+ ## šŸ“‹ Requirements
127
+
128
+ ### āœ… Required (You Already Have These!)
129
+ - **Claude Code** - The tool you're already using
130
+ - **jq** - JSON processing (pre-installed on most systems)
131
+
132
+ ### šŸŽ Optional Enhancements
133
+ - **git** - For branch display (you probably have this)
134
+ - **ccusage** - For usage stats (works via `npx` - no install needed)
135
+
136
+ ### Quick Compatibility Check
117
137
  ```bash
118
138
  command -v jq && echo "āœ… Ready to go!"
119
139
  ```
120
140
 
121
- ## šŸ“‚ What Gets Created
141
+ ## šŸ“‚ File Structure
122
142
 
123
- After running `cc-statusline init`, you'll have:
143
+ After installation, you'll have a clean setup:
124
144
 
125
145
  ```
126
146
  .claude/
127
- ā”œā”€ā”€ statusline.sh # Your custom statusline script
128
- └── settings.json # Auto-updated with statusline config
147
+ ā”œā”€ā”€ statusline.sh # šŸŽÆ Your generated statusline script
148
+ └── settings.json # āš™ļø Auto-updated Claude Code configuration
129
149
  ```
130
150
 
131
- **Manual Setup (if auto-config fails):**
132
- If the tool can't update your settings.json automatically, just add this:
151
+ ### Manual Configuration (Backup Plan)
152
+
153
+ If auto-configuration fails, simply add this to `.claude/settings.json`:
133
154
 
134
155
  ```json
135
156
  {
@@ -141,72 +162,80 @@ If the tool can't update your settings.json automatically, just add this:
141
162
  }
142
163
  ```
143
164
 
144
- ## Troubleshooting
145
-
146
- ### Statusline not showing
147
- 1. Restart Claude Code after installation
148
- 2. Verify `.claude/settings.json` contains:
149
- ```json
150
- {
151
- "statusLine": {
152
- "type": "command",
153
- "command": ".claude/statusline.sh",
154
- "padding": 0
155
- }
156
- }
157
- ```
158
-
159
- ### Performance Issues
160
- - Use `cc-statusline preview` to check execution time
161
- - Reduce number of features if >500ms execution time
162
- - Disable ccusage integration if not needed
163
-
164
- ### Missing Features
165
- - Ensure `jq` is installed: `brew install jq` (macOS) or `apt install jq` (Ubuntu)
166
- - Usage stats require ccusage (works automatically via `npx ccusage@latest`)
167
- - Check script permissions: `chmod +x .claude/statusline.sh`
168
-
169
- ## Development
165
+ ## šŸ”§ Troubleshooting
170
166
 
171
- ```bash
172
- # Clone repository
173
- git clone https://github.com/chongdashu/cc-statusline
174
- cd cc-statusline
167
+ ### 🚫 Statusline Not Showing
168
+ 1. **Restart Claude Code** after installation
169
+ 2. **Verify settings** - Check `.claude/settings.json` contains the configuration above
170
+ 3. **Check permissions** - Ensure script is executable: `chmod +x .claude/statusline.sh`
175
171
 
176
- # Install dependencies
177
- npm install
172
+ ### 🐌 Performance Issues
173
+ - **Test performance**: `cc-statusline preview .claude/statusline.sh`
174
+ - **Optimize features**: Disable heavy features if execution > 500ms
175
+ - **Disable ccusage**: Remove usage tracking if not needed
178
176
 
179
- # Build project
180
- npm run build
177
+ ### 🧩 Missing Features
178
+ - **Install jq**: `brew install jq` (macOS) or `apt install jq` (Ubuntu)
179
+ - **ccusage setup**: Works automatically via `npx ccusage@latest`
180
+ - **Git not found**: Install git for branch display
181
181
 
182
- # Test locally
183
- npm run dev
182
+ ## šŸš€ Performance
183
+
184
+ | Metric | Target | Typical |
185
+ |--------|--------|---------|
186
+ | **Execution Time** | <100ms | 45-80ms |
187
+ | **Memory Usage** | <5MB | ~2MB |
188
+ | **CPU Impact** | Negligible | <1% |
189
+ | **Dependencies** | Minimal | jq only |
190
+
191
+ *Benchmarked on macOS with all features enabled*
192
+
193
+ ## šŸ¤ Contributing
194
+
195
+ We love contributions! šŸŽ‰
196
+
197
+ **Quick Start:**
198
+ ```bash
199
+ git clone https://github.com/chongdashu/cc-statusline
200
+ cd cc-statusline
201
+ npm install && npm run build
184
202
  ```
185
203
 
186
- ## Contributing
204
+ **Contribution Areas:**
205
+ - šŸ› **Bug Fixes** - Help make it more robust
206
+ - ✨ **New Features** - Add support for more runtimes/features
207
+ - šŸ“š **Documentation** - Improve guides and examples
208
+ - 🧪 **Testing** - Add test coverage and edge cases
187
209
 
188
- Contributions welcome! Please read our [Contributing Guide](CONTRIBUTING.md) for detailed information on:
210
+ See our [Contributing Guide](CONTRIBUTING.md) for detailed information.
189
211
 
190
- - Setting up the development environment
191
- - Code standards and conventions
192
- - Testing your changes
193
- - Submitting pull requests
212
+ ## šŸ“Š Stats
194
213
 
195
- Quick start: Fork → Clone → `npm install` → Make changes → Test → Submit PR
214
+ <div align="center">
196
215
 
197
- ## License
216
+ ![GitHub stars](https://img.shields.io/github/stars/chongdashu/cc-statusline?style=social)
217
+ ![GitHub forks](https://img.shields.io/github/forks/chongdashu/cc-statusline?style=social)
218
+ ![npm downloads](https://img.shields.io/npm/dm/@chongdashu/cc-statusline)
198
219
 
199
- MIT License - see [LICENSE](LICENSE) file for details.
220
+ </div>
200
221
 
201
- ## Related Projects
222
+ ## šŸ”— Related Projects
202
223
 
203
- - [ccusage](https://github.com/ryoppippi/ccusage) - Claude Code usage analytics
204
- - [Claude Code](https://docs.anthropic.com/en/docs/claude-code) - Official documentation
224
+ - **[ccusage](https://github.com/ryoppippi/ccusage)** - Claude Code usage analytics (would not be possible with it!)
225
+ - **[Claude Code](https://docs.anthropic.com/en/docs/claude-code)** - Official documentation
205
226
 
206
- ## Changelog
227
+ ## šŸ“ Changelog
207
228
 
208
229
  See [CHANGELOG.md](CHANGELOG.md) for detailed release history.
209
230
 
231
+ ## šŸ“„ License
232
+
233
+ MIT License - see [LICENSE](LICENSE) file for details.
234
+
210
235
  ---
211
236
 
212
- **Made by [Chong-U](https://github.com/chongdashu) @ [AIOriented](https://aioriented.dev)**
237
+ <div align="center">
238
+
239
+ **Made by [Chong-U](https://github.com/chongdashu) @ [AIOriented](https://aioriented.dev)**
240
+
241
+ </div>
package/dist/index.js CHANGED
@@ -298,42 +298,72 @@ init_esm_shims();
298
298
  import inquirer from "inquirer";
299
299
  async function collectConfiguration() {
300
300
  console.log("\u{1F680} Welcome to cc-statusline! Let's create your custom Claude Code statusline.\n");
301
- const config = await inquirer.prompt([
301
+ const coreConfig = await inquirer.prompt([
302
302
  {
303
303
  type: "checkbox",
304
- name: "features",
305
- message: "What would you like to display in your statusline?",
304
+ name: "coreFeatures",
305
+ message: "\u{1F4CB} Select core features for your statusline:",
306
306
  choices: [
307
307
  { name: "\u{1F4C1} Working Directory", value: "directory", checked: true },
308
308
  { name: "\u{1F33F} Git Branch", value: "git", checked: true },
309
- { name: "\u{1F916} Model Name & Version", value: "model", checked: true },
310
- { name: "\u{1F4B5} Usage & Cost", value: "usage", checked: true },
311
- { name: "\u231B Session Time Remaining", value: "session", checked: true },
312
- { name: "\u{1F4CA} Token Statistics", value: "tokens", checked: false },
313
- { name: "\u26A1 Burn Rate (tokens/min)", value: "burnrate", checked: false }
309
+ { name: "\u{1F916} Model Name", value: "model", checked: true },
310
+ { name: "\u{1F9E0} Context Window (remaining %)", value: "context", checked: true }
314
311
  ],
315
312
  validate: (answer) => {
316
313
  if (answer.length < 1) {
317
- return "You must choose at least one feature.";
314
+ return "You must choose at least one core feature.";
318
315
  }
319
316
  return true;
320
317
  }
321
- },
318
+ }
319
+ ]);
320
+ const usageConfig = await inquirer.prompt([
321
+ {
322
+ type: "confirm",
323
+ name: "enableUsage",
324
+ message: "\u{1F4B0} Enable cost and session tracking? (requires ccusage)",
325
+ default: true
326
+ }
327
+ ]);
328
+ let usageFeatures = [];
329
+ if (usageConfig.enableUsage) {
330
+ const usageDetails = await inquirer.prompt([
331
+ {
332
+ type: "checkbox",
333
+ name: "usageFeatures",
334
+ message: "\u{1F4CA} Which usage features would you like?",
335
+ choices: [
336
+ { name: "\u{1F4B5} Cost & Hourly Rate", value: "usage", checked: true },
337
+ { name: "\u231B Session Time Remaining", value: "session", checked: true },
338
+ { name: "\u{1F4CA} Token Statistics", value: "tokens", checked: false },
339
+ { name: "\u26A1 Burn Rate (tokens/min)", value: "burnrate", checked: false }
340
+ ]
341
+ }
342
+ ]);
343
+ usageFeatures = usageDetails.usageFeatures;
344
+ }
345
+ const displayConfig = await inquirer.prompt([
322
346
  {
323
347
  type: "confirm",
324
348
  name: "colors",
325
- message: "Enable colors and emojis?",
349
+ message: "\u{1F3A8} Enable colors and emojis?",
326
350
  default: true
351
+ },
352
+ {
353
+ type: "confirm",
354
+ name: "logging",
355
+ message: "\u{1F4DD} Enable debug logging? (for troubleshooting)",
356
+ default: false
327
357
  }
328
358
  ]);
359
+ const allFeatures = [...coreConfig.coreFeatures, ...usageFeatures];
329
360
  return {
330
- features: config.features,
361
+ features: allFeatures,
331
362
  runtime: "bash",
332
- colors: config.colors,
363
+ colors: displayConfig.colors,
333
364
  theme: "detailed",
334
- ccusageIntegration: true,
335
- // Always enabled since npx works
336
- logging: false,
365
+ ccusageIntegration: usageConfig.enableUsage,
366
+ logging: displayConfig.logging,
337
367
  customEmojis: false
338
368
  };
339
369
  }
@@ -353,9 +383,10 @@ RST() { :; }
353
383
  `;
354
384
  }
355
385
  return `
356
- # ---- color helpers (TTY-aware, respect NO_COLOR) ----
386
+ # ---- color helpers (force colors for Claude Code) ----
387
+ # Force colors for Claude Code statusline (Claude Code doesn't pass TTY)
357
388
  use_color=1
358
- [ -t 1 ] || use_color=0
389
+ # Only disable if NO_COLOR is explicitly set
359
390
  [ -n "$NO_COLOR" ] && use_color=0
360
391
 
361
392
  C() { if [ "$use_color" -eq 1 ]; then printf '\\033[%sm' "$1"; fi; }
@@ -365,9 +396,9 @@ RST() { if [ "$use_color" -eq 1 ]; then printf '\\033[0m'; fi; }
365
396
  function generateBasicColors() {
366
397
  return `
367
398
  # ---- basic colors ----
368
- dir_color() { if [ "$use_color" -eq 1 ]; then printf '\\033[1;36m'; fi; } # cyan
369
- model_color() { if [ "$use_color" -eq 1 ]; then printf '\\033[1;35m'; fi; } # magenta
370
- version_color() { if [ "$use_color" -eq 1 ]; then printf '\\033[1;33m'; fi; } # yellow
399
+ dir_color() { if [ "$use_color" -eq 1 ]; then printf '\\033[1;36m'; fi; } # bold cyan
400
+ model_color() { if [ "$use_color" -eq 1 ]; then printf '\\033[1;35m'; fi; } # bold magenta
401
+ version_color() { if [ "$use_color" -eq 1 ]; then printf '\\033[1;33m'; fi; } # bold yellow
371
402
  rst() { if [ "$use_color" -eq 1 ]; then printf '\\033[0m'; fi; }
372
403
  `;
373
404
  }
@@ -488,44 +519,6 @@ progress_bar() {
488
519
  printf '%*s' "$empty" '' | tr ' ' '-'
489
520
  }`;
490
521
  }
491
- function generateUsageDisplayCode(config, colors, emojis) {
492
- if (!config.enabled) return "";
493
- let displayCode = "";
494
- if (config.showSession) {
495
- const sessionEmoji = emojis ? "\u231B" : "session:";
496
- displayCode += `
497
- # session time
498
- if [ -n "$session_txt" ]; then
499
- printf ' ${sessionEmoji} %s%s%s' "$(session_color)" "$session_txt" "$(rst)"${config.showProgressBar ? `
500
- printf ' %s[%s]%s' "$(session_color)" "$session_bar" "$(rst)"` : ""}
501
- fi`;
502
- }
503
- if (config.showCost) {
504
- const costEmoji = emojis ? "\u{1F4B5}" : "$";
505
- displayCode += `
506
- # cost
507
- if [ -n "$cost_usd" ] && [[ "$cost_usd" =~ ^[0-9.]+$ ]]; then
508
- if [ -n "$cost_per_hour" ] && [[ "$cost_per_hour" =~ ^[0-9.]+$ ]]; then
509
- printf ' ${costEmoji} %s$%.2f ($%.2f/h)%s' "$(cost_color)" "$cost_usd" "$cost_per_hour" "$(rst)"
510
- else
511
- printf ' ${costEmoji} %s$%.2f%s' "$(cost_color)" "$cost_usd" "$(rst)"
512
- fi
513
- fi`;
514
- }
515
- if (config.showTokens) {
516
- const tokenEmoji = emojis ? "\u{1F4CA}" : "tok:";
517
- displayCode += `
518
- # tokens
519
- if [ -n "$tot_tokens" ] && [[ "$tot_tokens" =~ ^[0-9]+$ ]]; then
520
- if [ -n "$tpm" ] && [[ "$tpm" =~ ^[0-9.]+$ ]] && ${config.showBurnRate ? "true" : "false"}; then
521
- printf ' ${tokenEmoji} %s%s tok (%.0f tpm)%s' "$(usage_color)" "$tot_tokens" "$tpm" "$(rst)"
522
- else
523
- printf ' ${tokenEmoji} %s%s tok%s' "$(usage_color)" "$tot_tokens" "$(rst)"
524
- fi
525
- fi`;
526
- }
527
- return displayCode;
528
- }
529
522
 
530
523
  // src/generators/bash-generator.ts
531
524
  function generateBashStatusline(config) {
@@ -533,6 +526,7 @@ function generateBashStatusline(config) {
533
526
  const hasUsage = config.features.some((f) => ["usage", "session", "tokens", "burnrate"].includes(f));
534
527
  const hasDirectory = config.features.includes("directory");
535
528
  const hasModel = config.features.includes("model");
529
+ const hasContext = config.features.includes("context");
536
530
  const usageConfig = {
537
531
  enabled: hasUsage && config.ccusageIntegration,
538
532
  showCost: config.features.includes("usage"),
@@ -555,13 +549,13 @@ function generateBashStatusline(config) {
555
549
  # Theme: ${config.theme} | Colors: ${config.colors} | Features: ${config.features.join(", ")}
556
550
 
557
551
  ${config.logging ? generateLoggingCode() : ""}
558
- input=$(cat)
552
+ ${generateBasicDataExtraction(hasDirectory, hasModel, hasContext)}
559
553
  ${generateColorBashCode({ enabled: config.colors, theme: config.theme })}
560
554
  ${config.colors ? generateBasicColors() : ""}
561
555
  ${hasUsage ? generateUsageUtilities() : ""}
562
556
  ${hasGit ? generateGitUtilities() : ""}
563
- ${generateBasicDataExtraction(hasDirectory, hasModel)}
564
557
  ${hasGit ? generateGitBashCode(gitConfig, config.colors) : ""}
558
+ ${hasContext ? generateContextBashCode(config.colors) : ""}
565
559
  ${hasUsage ? generateUsageBashCode(usageConfig, config.colors) : ""}
566
560
  ${config.logging ? generateLoggingOutput() : ""}
567
561
  ${generateDisplaySection(config, gitConfig, usageConfig)}
@@ -570,42 +564,141 @@ ${generateDisplaySection(config, gitConfig, usageConfig)}
570
564
  }
571
565
  function generateLoggingCode() {
572
566
  return `
567
+ # Enable logging
573
568
  LOG_FILE="\${HOME}/.claude/statusline.log"
574
- TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
569
+ LOG_ENABLED=1
575
570
 
576
- # ---- logging ----
577
- {
578
- echo "[$TIMESTAMP] Status line triggered with input:"
579
- (echo "$input" | jq . 2>/dev/null) || echo "$input"
580
- echo "---"
581
- } >> "$LOG_FILE" 2>/dev/null
571
+ # Logging function
572
+ log_debug() {
573
+ if [ "$LOG_ENABLED" -eq 1 ]; then
574
+ echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE"
575
+ fi
576
+ }
577
+
578
+ log_debug "=== Statusline execution started ==="
582
579
  `;
583
580
  }
584
- function generateBasicDataExtraction(hasDirectory, hasModel) {
581
+ function generateBasicDataExtraction(hasDirectory, hasModel, hasContext) {
585
582
  return `
583
+ input=$(cat)
584
+ log_debug "Input received: \${#input} characters"
585
+
586
+ log_debug "Color state: use_color=$use_color, NO_COLOR=\${NO_COLOR:-unset}, TTY test: $([ -t 1 ] && echo 'yes' || echo 'no')"
587
+
586
588
  # ---- basics ----
587
- if command -v jq >/dev/null 2>&1; then${hasDirectory ? `
589
+ if command -v jq >/dev/null 2>&1; then
590
+ log_debug "jq found, parsing JSON input"${hasDirectory ? `
588
591
  current_dir=$(echo "$input" | jq -r '.workspace.current_dir // .cwd // "unknown"' 2>/dev/null | sed "s|^$HOME|~|g")` : ""}${hasModel ? `
589
592
  model_name=$(echo "$input" | jq -r '.model.display_name // "Claude"' 2>/dev/null)
590
- model_version=$(echo "$input" | jq -r '.model.version // ""' 2>/dev/null)` : ""}
591
- else${hasDirectory ? `
593
+ model_version=$(echo "$input" | jq -r '.model.version // ""' 2>/dev/null)` : ""}${hasContext ? `
594
+ session_id=$(echo "$input" | jq -r '.session_id // ""' 2>/dev/null)` : ""}
595
+ log_debug "Parsed: dir=\${current_dir:-}, model=\${model_name:-}, version=\${model_version:-}, session=\${session_id:-}"
596
+ else
597
+ log_debug "jq not found, using defaults"${hasDirectory ? `
592
598
  current_dir="unknown"` : ""}${hasModel ? `
593
- model_name="Claude"; model_version=""` : ""}
599
+ model_name="Claude"; model_version=""` : ""}${hasContext ? `
600
+ session_id=""` : ""}
594
601
  fi
595
602
  `;
596
603
  }
604
+ function generateContextBashCode(colors) {
605
+ const sessionColors = colors ? `
606
+ # ---- session colors (blue/cyan to differentiate from context) ----
607
+ session_color() {
608
+ rem_pct=$(( 100 - session_pct ))
609
+ # Use blue/cyan colors to differentiate from context (green/yellow/red)
610
+ if (( rem_pct <= 10 )); then SCLR='1;94' # bright blue
611
+ elif (( rem_pct <= 25 )); then SCLR='1;96' # bright cyan
612
+ else SCLR='1;34'; fi # blue
613
+ if [ "$use_color" -eq 1 ]; then printf '\\033[%sm' "$SCLR"; fi
614
+ }` : `
615
+ session_color() { :; }`;
616
+ return `
617
+ # ---- context window calculation ----
618
+ context_tokens=0; context_pct=0; context_remaining=0
619
+
620
+ # Determine max context based on model
621
+ get_max_context() {
622
+ local model_name="$1"
623
+ case "$model_name" in
624
+ # Claude 3.5 and Claude 4.x models (all have 200K)
625
+ *"Opus 4"*|*"opus 4"*|*"Opus"*|*"opus"*)
626
+ echo "200000" # 200K for all Opus versions
627
+ ;;
628
+ *"Sonnet 4"*|*"sonnet 4"*|*"Sonnet 3.5"*|*"sonnet 3.5"*|*"Sonnet"*|*"sonnet"*)
629
+ echo "200000" # 200K for Sonnet 3.5+ and 4.x
630
+ ;;
631
+ *"Haiku 3.5"*|*"haiku 3.5"*|*"Haiku 4"*|*"haiku 4"*|*"Haiku"*|*"haiku"*)
632
+ echo "200000" # 200K for modern Haiku (3.5+ and 4.x)
633
+ ;;
634
+ # Legacy Claude 3.0 models (smaller context windows)
635
+ *"Claude 3 Haiku"*|*"claude 3 haiku"*)
636
+ echo "100000" # 100K for original Claude 3 Haiku
637
+ ;;
638
+ # Generic Claude patterns
639
+ *"Claude"*|*"claude"*)
640
+ echo "200000" # Default to 200K for any Claude model
641
+ ;;
642
+ *)
643
+ echo "200000" # Default to 200K for unknown models
644
+ ;;
645
+ esac
646
+ }
647
+
648
+ MAX_CONTEXT=$(get_max_context "$model_name")
649
+ log_debug "Model: $model_name, Max context: $MAX_CONTEXT"
650
+
651
+ # Progress bar function for context remaining
652
+ context_progress_bar() {
653
+ local remaining_pct="$1"
654
+ local width="$2"
655
+ # Clamp percentage to 0-100
656
+ [ "$remaining_pct" -lt 0 ] && remaining_pct=0
657
+ [ "$remaining_pct" -gt 100 ] && remaining_pct=100
658
+
659
+ local filled=$(( remaining_pct * width / 100 ))
660
+ local empty=$(( width - filled ))
661
+
662
+ # Use different characters: \u25A0 for remaining, \u25A1 for used
663
+ printf '%*s' "$filled" '' | tr ' ' '\u25A0'
664
+ printf '%*s' "$empty" '' | tr ' ' '\u25A1'
665
+ }
666
+
667
+ if [ -n "$session_id" ] && command -v jq >/dev/null 2>&1; then
668
+ # Convert current dir to session file path
669
+ project_dir=$(echo "$current_dir" | sed "s|~|$HOME|g" | sed 's|/|-|g')
670
+ session_file="$HOME/.claude/projects/\${project_dir}/\${session_id}.jsonl"
671
+
672
+ log_debug "Looking for session file: $session_file"
673
+
674
+ if [ -f "$session_file" ]; then
675
+ # Get the latest token count from the session file
676
+ latest_tokens=$(cat "$session_file" | jq -r 'select(.message.usage) | .message.usage | ((.input_tokens // 0) + (.cache_read_input_tokens // 0))' 2>/dev/null | tail -1)
677
+
678
+ if [ -n "$latest_tokens" ] && [ "$latest_tokens" -ne 0 ]; then
679
+ context_tokens=$latest_tokens
680
+ context_pct=$(( context_tokens * 100 / MAX_CONTEXT ))
681
+ context_remaining=$(( MAX_CONTEXT - context_tokens ))
682
+ log_debug "Context: tokens=$context_tokens, pct=$context_pct%, remaining=$context_remaining"
683
+ fi
684
+ fi
685
+ fi${sessionColors}
686
+ `;
687
+ }
597
688
  function generateLoggingOutput() {
598
689
  return `
599
690
  # ---- log extracted data ----
600
691
  {
601
- echo "[$TIMESTAMP] Extracted: dir=\${current_dir:-}, model=\${model_name:-}, version=\${model_version:-}, git=\${git_branch:-}, cost=\${cost_usd:-}, cost_ph=\${cost_per_hour:-}, tokens=\${tot_tokens:-}, tpm=\${tpm:-}, session_pct=\${session_pct:-}"
692
+ echo "[$TIMESTAMP] Extracted: dir=\${current_dir:-}, model=\${model_name:-}, version=\${model_version:-}, git=\${git_branch:-}, cost=\${cost_usd:-}, cost_ph=\${cost_per_hour:-}, tokens=\${tot_tokens:-}, tpm=\${tpm:-}, session_pct=\${session_pct:-}, context=\${context_tokens:-}/\${MAX_CONTEXT:-}"
602
693
  } >> "$LOG_FILE" 2>/dev/null
603
694
  `;
604
695
  }
605
696
  function generateDisplaySection(config, gitConfig, usageConfig) {
606
697
  const emojis = config.colors && !config.customEmojis;
607
698
  let displayCode = `
608
- # ---- render statusline ----`;
699
+ # ---- render statusline ----
700
+ # Add reset code at the beginning to override any terminal dim settings
701
+ printf '\\033[0m'`;
609
702
  if (config.features.includes("directory")) {
610
703
  const dirEmoji = emojis ? "\u{1F4C1}" : "dir:";
611
704
  displayCode += `
@@ -620,9 +713,115 @@ if [ -n "$model_version" ] && [ "$model_version" != "null" ]; then
620
713
  printf ' \u{1F3F7}\uFE0F %s%s%s' "$(version_color)" "$model_version" "$(rst)"
621
714
  fi`;
622
715
  }
623
- displayCode += generateUsageDisplayCode(usageConfig, config.colors, emojis);
716
+ if (config.features.includes("context")) {
717
+ const contextEmoji = emojis ? "\u{1F9E0}" : "ctx:";
718
+ displayCode += `
719
+ # context window display
720
+ if [ "$context_tokens" -gt 0 ]; then
721
+ # Calculate percentage remaining instead of used
722
+ remaining_pct=$(( 100 - context_pct ))
723
+
724
+ # Color based on how much is remaining
725
+ if [ "$remaining_pct" -lt 20 ]; then
726
+ if [ "$use_color" -eq 1 ]; then
727
+ context_color=$(printf '\\033[1;31m') # bold red if <20% remaining
728
+ else
729
+ context_color=""
730
+ fi
731
+ elif [ "$remaining_pct" -lt 40 ]; then
732
+ if [ "$use_color" -eq 1 ]; then
733
+ context_color=$(printf '\\033[1;33m') # bold yellow if <40% remaining
734
+ else
735
+ context_color=""
736
+ fi
737
+ else
738
+ if [ "$use_color" -eq 1 ]; then
739
+ context_color=$(printf '\\033[1;32m') # bold green if >40% remaining
740
+ else
741
+ context_color=""
742
+ fi
743
+ fi
744
+
745
+ # Create context progress bar (showing remaining, not used)
746
+ context_bar=$(context_progress_bar "$remaining_pct" 10)
747
+
748
+ printf ' ${contextEmoji} Context Left: %s%d%% [%s]%s' "$context_color" "$remaining_pct" "$context_bar" "$(rst)"
749
+ else
750
+ # Show TBD when context info isn't available yet
751
+ if [ "$use_color" -eq 1 ]; then
752
+ context_color=$(printf '\\033[1;37m') # bright white/gray for TBD
753
+ else
754
+ context_color=""
755
+ fi
756
+ printf ' ${contextEmoji} Context Left: %sTBD%s' "$context_color" "$(rst)"
757
+ fi`;
758
+ }
759
+ if (usageConfig.enabled) {
760
+ displayCode += `
761
+ # Add newline before usage/analytics line
762
+ usage_line_content=""
763
+ ${generateUsageLineContent(usageConfig, config.colors, emojis)}
764
+
765
+ # Print usage line only if there's content
766
+ if [ -n "$usage_line_content" ]; then
767
+ printf '\\\\n%s' "$usage_line_content"
768
+ fi`;
769
+ }
770
+ displayCode += `
771
+ printf '\\\\n'`;
624
772
  return displayCode;
625
773
  }
774
+ function generateUsageLineContent(usageConfig, colors, emojis) {
775
+ let usageContent = "";
776
+ if (usageConfig.showSession) {
777
+ const sessionEmoji = emojis ? "\u231B" : "session:";
778
+ usageContent += `
779
+ # session time
780
+ if [ -n "$session_txt" ]; then
781
+ usage_line_content="\\${usage_line_content}${sessionEmoji} \\$(session_color)\\${session_txt}\\$(rst) \\$(session_color)[\\${session_bar}]\\$(rst)"
782
+ fi`;
783
+ }
784
+ if (usageConfig.showCost) {
785
+ const costEmoji = emojis ? "\u{1F4B5}" : "cost:";
786
+ usageContent += `
787
+ # cost
788
+ if [ -n "$cost_usd" ] && [[ "$cost_usd" =~ ^[0-9.]+$ ]]; then
789
+ if [ -n "$cost_per_hour" ] && [[ "$cost_per_hour" =~ ^[0-9.]+$ ]]; then
790
+ usage_line_content="\\${usage_line_content} ${costEmoji} \\$(cost_color)\\$\\$(printf '%.2f' \\"$cost_usd\\") (\\$\\$(printf '%.2f' \\"$cost_per_hour\\")/h)\\$(rst)"
791
+ else
792
+ usage_line_content="\\${usage_line_content} ${costEmoji} \\$(cost_color)\\$\\$(printf '%.2f' \\"$cost_usd\\")\\$(rst)"
793
+ fi
794
+ fi`;
795
+ }
796
+ if (usageConfig.showTokens) {
797
+ const tokenEmoji = emojis ? "\u{1F4CA}" : "tokens:";
798
+ if (usageConfig.showBurnRate) {
799
+ usageContent += `
800
+ # tokens with burn rate
801
+ if [ -n "$tot_tokens" ] && [[ "$tot_tokens" =~ ^[0-9]+$ ]]; then
802
+ if [ -n "$tpm" ] && [[ "$tpm" =~ ^[0-9.]+$ ]]; then
803
+ usage_line_content="\\${usage_line_content} ${tokenEmoji} \\$(usage_color)\\${tot_tokens} tok (\\$(printf '%.0f' \\"$tpm\\") tpm)\\$(rst)"
804
+ else
805
+ usage_line_content="\\${usage_line_content} ${tokenEmoji} \\$(usage_color)\\${tot_tokens} tok\\$(rst)"
806
+ fi
807
+ fi`;
808
+ } else {
809
+ usageContent += `
810
+ # tokens only
811
+ if [ -n "$tot_tokens" ] && [[ "$tot_tokens" =~ ^[0-9]+$ ]]; then
812
+ usage_line_content="\\${usage_line_content} ${tokenEmoji} \\$(usage_color)\\${tot_tokens} tok\\$(rst)"
813
+ fi`;
814
+ }
815
+ } else if (usageConfig.showBurnRate) {
816
+ const burnEmoji = emojis ? "\u26A1" : "tpm:";
817
+ usageContent += `
818
+ # burn rate only
819
+ if [ -n "$tpm" ] && [[ "$tpm" =~ ^[0-9.]+$ ]]; then
820
+ usage_line_content="\\${usage_line_content} ${burnEmoji} \\$(usage_color)\\$(printf '%.0f' \\"$tpm\\") tpm\\$(rst)"
821
+ fi`;
822
+ }
823
+ return usageContent;
824
+ }
626
825
 
627
826
  // src/utils/validator.ts
628
827
  init_esm_shims();
@@ -773,7 +972,7 @@ async function initCommand(options) {
773
972
  // src/index.ts
774
973
  import chalk3 from "chalk";
775
974
  var program = new Command();
776
- program.name("cc-statusline").description("Interactive CLI tool for generating custom Claude Code statuslines").version("1.0.0");
975
+ program.name("cc-statusline").description("Interactive CLI tool for generating custom Claude Code statuslines").version("1.1.0");
777
976
  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);
778
977
  program.command("preview").description("Preview existing statusline.sh with mock data").argument("<script-path>", "Path to statusline.sh file to preview").action(async (scriptPath) => {
779
978
  const { previewCommand: previewCommand2 } = await Promise.resolve().then(() => (init_preview(), preview_exports));
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\nconst program = new Command()\n\nprogram\n .name('cc-statusline')\n .description('Interactive CLI tool for generating custom Claude Code statuslines')\n .version('1.0.0')\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'\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\n const outputPath = options.output || `./.claude/${filename}`\n const resolvedPath = path.resolve(outputPath)\n\n // Install the statusline\n if (options.install !== false) {\n const installSpinner = ora('Installing statusline...').start()\n \n try {\n await installStatusline(script, resolvedPath, config)\n installSpinner.succeed('āœ… Statusline installed!')\n \n console.log(chalk.green('\\nšŸŽ‰ Success! Your custom statusline is ready!'))\n console.log(chalk.cyan(`\\nšŸ“ Generated file: ${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 installSpinner.fail('Failed to install statusline')\n \n if (error instanceof Error && error.message === 'SETTINGS_UPDATE_FAILED') {\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 .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\": \".claude/statusline.sh\",`))\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}\n\nexport async function collectConfiguration(): Promise<StatuslineConfig> {\n console.log('šŸš€ Welcome to cc-statusline! Let\\'s create your custom Claude Code statusline.\\n')\n\n const config = await inquirer.prompt([\n {\n type: 'checkbox',\n name: 'features',\n message: 'What would you like to display in your statusline?',\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: 'šŸ’µ Usage & Cost', value: 'usage', checked: true },\n { name: 'āŒ› Session Time Remaining', value: 'session', checked: true },\n { name: 'šŸ“Š Token Statistics', value: 'tokens', checked: false },\n { name: '⚔ Burn Rate (tokens/min)', value: 'burnrate', 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 },\n {\n type: 'confirm',\n name: 'colors',\n message: 'Enable colors and emojis?',\n default: true\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: false,\n customEmojis: false\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\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\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 (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\n${config.logging ? generateLoggingCode() : ''}\ninput=$(cat)\n${generateColorBashCode({ enabled: config.colors, theme: config.theme })}\n${config.colors ? generateBasicColors() : ''}\n${hasUsage ? generateUsageUtilities() : ''}\n${hasGit ? generateGitUtilities() : ''}\n${generateBasicDataExtraction(hasDirectory, hasModel)}\n${hasGit ? generateGitBashCode(gitConfig, 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 `\nLOG_FILE=\"\\${HOME}/.claude/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): 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)` : ''}\nelse${hasDirectory ? `\n current_dir=\"unknown\"` : ''}${hasModel ? `\n model_name=\"Claude\"; model_version=\"\"` : ''}\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:-}, 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 let displayCode = `\n# ---- render statusline ----`\n\n // Directory\n if (config.features.includes('directory')) {\n const dirEmoji = emojis ? 'šŸ“' : 'dir:'\n displayCode += `\nprintf '${dirEmoji} %s%s%s' \"$(dir_color)\" \"$current_dir\" \"$(rst)\"`\n }\n\n // Git\n displayCode += generateGitDisplayCode(gitConfig, config.colors, emojis)\n\n // Model\n if (config.features.includes('model')) {\n const modelEmoji = emojis ? 'šŸ¤–' : 'model:'\n displayCode += `\nprintf ' ${modelEmoji} %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`\n }\n\n // Usage features\n displayCode += generateUsageDisplayCode(usageConfig, config.colors, emojis)\n\n return displayCode\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 (TTY-aware, respect NO_COLOR) ----\nuse_color=1\n[ -t 1 ] || use_color=0\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# ---- basic colors ----\ndir_color() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[1;36m'; fi; } # cyan\nmodel_color() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[1;35m'; fi; } # magenta \nversion_color() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[1;33m'; fi; } # yellow\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[1;32m'; fi; }\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[1;35m'; fi; }\ncost_color() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[1;36m'; fi; }\nsession_color() { \n rem_pct=$(( 100 - session_pct ))\n if (( rem_pct <= 10 )); then SCLR='1;31'\n elif (( rem_pct <= 25 )); then SCLR='1;33'\n else SCLR='1;32'; fi\n if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[%sm' \"$SCLR\"; fi\n}\n` : `\nusage_color() { :; }\ncost_color() { :; }\nsession_color() { :; }\n`\n\n return `${colorCode}\n# ---- ccusage integration ----\nsession_txt=\"\"; session_pct=0; session_bar=\"\"\ncost_usd=\"\"; cost_per_hour=\"\"; tpm=\"\"; tot_tokens=\"\"\n\nif command -v jq >/dev/null 2>&1; then\n blocks_output=$(npx ccusage@latest blocks --json 2>/dev/null || ccusage blocks --json 2>/dev/null)\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.showCost ? `\n cost_usd=$(echo \"$active_block\" | jq -r '.costUSD // empty')\n cost_per_hour=$(echo \"$active_block\" | jq -r '.burnRate.costPerHour // empty')` : ''}${config.showTokens ? `\n tot_tokens=$(echo \"$active_block\" | jq -r '.totalTokens // empty')` : ''}${config.showBurnRate ? `\n tpm=$(echo \"$active_block\" | jq -r '.burnRate.tokensPerMinute // empty')` : ''}${config.showSession || config.showProgressBar ? `\n \n # Session time calculation\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'\n\nexport async function installStatusline(\n script: string,\n outputPath: string,\n config: StatuslineConfig\n): Promise<void> {\n try {\n // Ensure the directory exists\n const dir = path.dirname(outputPath)\n await fs.mkdir(dir, { recursive: true })\n\n // Write the script\n await fs.writeFile(outputPath, script, { mode: 0o755 })\n\n // Update .claude/settings.json if it exists\n await updateSettingsJson(dir, path.basename(outputPath))\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): Promise<void> {\n const settingsPath = path.join(claudeDir, 'settings.json')\n \n try {\n let settings: any = {}\n \n // Try to read existing settings\n try {\n const settingsContent = await fs.readFile(settingsPath, 'utf-8')\n settings = JSON.parse(settingsContent)\n } catch {\n // File doesn't exist or invalid JSON, start fresh\n }\n\n // Update statusLine configuration\n settings.statusLine = {\n type: 'command',\n command: `.claude/${scriptName}`,\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,IACf;AAAA,IACA,OAAO;AAAA,MACL,IAAI;AAAA,MACJ,cAAc;AAAA,MACd,SAAS;AAAA,IACX;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;AAvNA;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;AAYrB,eAAsB,uBAAkD;AACtE,UAAQ,IAAI,wFAAkF;AAE9F,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,0BAAmB,OAAO,SAAS,SAAS,KAAK;AAAA,QACzD,EAAE,MAAM,iCAA4B,OAAO,WAAW,SAAS,KAAK;AAAA,QACpE,EAAE,MAAM,8BAAuB,OAAO,UAAU,SAAS,MAAM;AAAA,QAC/D,EAAE,MAAM,iCAA4B,OAAO,YAAY,SAAS,MAAM;AAAA,MACxE;AAAA,MACA,UAAU,CAAC,WAAqB;AAC9B,YAAI,OAAO,SAAS,GAAG;AACrB,iBAAO;AAAA,QACT;AACA,eAAO;AAAA,MACT;AAAA,IACF;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS;AAAA,MACT,SAAS;AAAA,IACX;AAAA,EACF,CAAC;AAGD,SAAO;AAAA,IACL,UAAU,OAAO;AAAA,IACjB,SAAS;AAAA,IACT,QAAQ,OAAO;AAAA,IACf,OAAO;AAAA,IACP,oBAAoB;AAAA;AAAA,IACpB,SAAS;AAAA,IACT,cAAc;AAAA,EAChB;AACF;;;ACtDA;;;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;AAAA;AAST;AAEO,SAAS,sBAA8B;AAC5C,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOT;;;AClCA;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;AAEO,SAAS,uBAAuB,QAAoB,QAAiB,QAAyB;AACnG,MAAI,CAAC,OAAO,QAAS,QAAO;AAE5B,QAAM,cAAc,SAAS,cAAO;AAEpC,MAAI,cAAc;AAAA;AAAA;AAAA,cAGN,WAAW;AAAA;AAGvB,SAAO;AACT;AAEO,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,IAWzB;AAAA;AAAA;AAAA;AAAA;AAMF,SAAO,GAAG,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qCASgB,OAAO,WAAW;AAAA;AAAA,wFAEiC,EAAE,GAAG,OAAO,aAAa;AAAA,4EACrC,EAAE,GAAG,OAAO,eAAe;AAAA,kFACrB,EAAE,GAAG,OAAO,eAAe,OAAO,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,0CAa5F,OAAO,cAAc;AAAA,2GAC4C,EAAE,GAAG,OAAO,kBAAkB;AAAA,yDAChF,EAAE;AAAA,YAC/C,EAAE;AAAA;AAAA;AAAA;AAId;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;AAEO,SAAS,yBAAyB,QAAsB,QAAiB,QAAyB;AACvG,MAAI,CAAC,OAAO,QAAS,QAAO;AAE5B,MAAI,cAAc;AAElB,MAAI,OAAO,aAAa;AACtB,UAAM,eAAe,SAAS,WAAM;AACpC,mBAAe;AAAA;AAAA;AAAA,cAGL,YAAY,sDAAsD,OAAO,kBAAkB;AAAA,oEACrC,EAAE;AAAA;AAAA,EAEpE;AAEA,MAAI,OAAO,UAAU;AACnB,UAAM,YAAY,SAAS,cAAO;AAClC,mBAAe;AAAA;AAAA;AAAA;AAAA,gBAIH,SAAS;AAAA;AAAA,gBAET,SAAS;AAAA;AAAA;AAAA,EAGvB;AAEA,MAAI,OAAO,YAAY;AACrB,UAAM,aAAa,SAAS,cAAO;AACnC,mBAAe;AAAA;AAAA;AAAA,qDAGkC,OAAO,eAAe,SAAS,OAAO;AAAA,gBAC3E,UAAU;AAAA;AAAA,gBAEV,UAAU;AAAA;AAAA;AAAA,EAGxB;AAEA,SAAO;AACT;;;AHjIO,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;AAGjD,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;AAAA,6CAE4B,SAAS;AAAA,WAC3C,OAAO,KAAK,cAAc,OAAO,MAAM,gBAAgB,OAAO,SAAS,KAAK,IAAI,CAAC;AAAA;AAAA,EAE1F,OAAO,UAAU,oBAAoB,IAAI,EAAE;AAAA;AAAA,EAE3C,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,QAAQ,CAAC;AAAA,EACnD,SAAS,oBAAoB,WAAW,OAAO,MAAM,IAAI,EAAE;AAAA,EAC3D,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;AAWT;AAEA,SAAS,4BAA4B,cAAuB,UAA2B;AACrF,SAAO;AAAA;AAAA,wCAE+B,eAAe;AAAA,yHACkE,EAAE,GAAG,WAAW;AAAA;AAAA,+EAE1D,EAAE;AAAA,MAC3E,eAAe;AAAA,2BACM,EAAE,GAAG,WAAW;AAAA,2CACA,EAAE;AAAA;AAAA;AAG7C;AAEA,SAAS,wBAAgC;AACvC,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAMT;AAEA,SAAS,uBAAuB,QAA0B,WAAgB,aAA0B;AAClG,QAAM,SAAS,OAAO,UAAU,CAAC,OAAO;AAExC,MAAI,cAAc;AAAA;AAIlB,MAAI,OAAO,SAAS,SAAS,WAAW,GAAG;AACzC,UAAM,WAAW,SAAS,cAAO;AACjC,mBAAe;AAAA,UACT,QAAQ;AAAA,EAChB;AAGA,iBAAe,uBAAuB,WAAW,OAAO,QAAQ,MAAM;AAGtE,MAAI,OAAO,SAAS,SAAS,OAAO,GAAG;AACrC,UAAM,aAAa,SAAS,cAAO;AACnC,mBAAe;AAAA,YACP,UAAU;AAAA;AAAA;AAAA;AAAA,EAIpB;AAGA,iBAAe,yBAAyB,aAAa,OAAO,QAAQ,MAAM;AAE1E,SAAO;AACT;;;AItHA;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;AAEjB,eAAsB,kBACpB,QACA,YACA,QACe;AACf,MAAI;AAEF,UAAM,MAAMA,MAAK,QAAQ,UAAU;AACnC,UAAM,GAAG,MAAM,KAAK,EAAE,WAAW,KAAK,CAAC;AAGvC,UAAM,GAAG,UAAU,YAAY,QAAQ,EAAE,MAAM,IAAM,CAAC;AAGtD,UAAM,mBAAmB,KAAKA,MAAK,SAAS,UAAU,CAAC;AAAA,EAKzD,SAAS,OAAO;AACd,UAAM,IAAI,MAAM,iCAAiC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,EAAE;AAAA,EAC3G;AACF;AAEA,eAAe,mBAAmB,WAAmB,YAAmC;AACtF,QAAM,eAAeA,MAAK,KAAK,WAAW,eAAe;AAEzD,MAAI;AACF,QAAI,WAAgB,CAAC;AAGrB,QAAI;AACF,YAAM,kBAAkB,MAAM,GAAG,SAAS,cAAc,OAAO;AAC/D,iBAAW,KAAK,MAAM,eAAe;AAAA,IACvC,QAAQ;AAAA,IAER;AAGA,aAAS,aAAa;AAAA,MACpB,MAAM;AAAA,MACN,SAAS,WAAW,UAAU;AAAA,MAC9B,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;;;APrDA,OAAO,WAAW;AAClB,OAAO,SAAS;AAChB,OAAOC,WAAU;AAOjB,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,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,aAAa,QAAQ,UAAU,aAAa,QAAQ;AAC1D,UAAM,eAAeD,MAAK,QAAQ,UAAU;AAG5C,QAAI,QAAQ,YAAY,OAAO;AAC7B,YAAM,iBAAiB,IAAI,0BAA0B,EAAE,MAAM;AAE7D,UAAI;AACF,cAAM,kBAAkB,QAAQ,cAAc,MAAM;AACpD,uBAAe,QAAQ,8BAAyB;AAEhD,gBAAQ,IAAI,MAAM,MAAM,uDAAgD,CAAC;AACzE,gBAAQ,IAAI,MAAM,KAAK;AAAA,4BAAwB,MAAM,MAAM,YAAY,CAAC,EAAE,CAAC;AAC3E,gBAAQ,IAAI,MAAM,KAAK,eAAe,CAAC;AACvC,gBAAQ,IAAI,MAAM,MAAM,sDAAsD,CAAC;AAC/E,gBAAQ,IAAI,MAAM,MAAM,qDAAqD,CAAC;AAAA,MAEhF,SAAS,OAAO;AACd,uBAAe,KAAK,8BAA8B;AAElD,YAAI,iBAAiB,SAAS,MAAM,YAAY,0BAA0B;AACxE,kBAAQ,IAAI,MAAM,OAAO,mEAAyD,CAAC;AACnF,kBAAQ,IAAI,MAAM,KAAK,kCAAkC,CAAC;AAC1D,kBAAQ,IAAI,MAAM,MAAM,8CAA8C,CAAC;AACvE,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,yCAAyC,CAAC;AACjE,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;;;ADxGA,OAAOG,YAAW;AAElB,IAAM,UAAU,IAAI,QAAQ;AAE5B,QACG,KAAK,eAAe,EACpB,YAAY,oEAAoE,EAChF,QAAQ,OAAO;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,IAAID,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","path","testStatuslineScript","generateMockClaudeInput","chalk","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 },\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\nconst program = new Command()\n\nprogram\n .name('cc-statusline')\n .description('Interactive CLI tool for generating custom Claude Code statuslines')\n .version('1.1.0')\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'\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\n const outputPath = options.output || `./.claude/${filename}`\n const resolvedPath = path.resolve(outputPath)\n\n // Install the statusline\n if (options.install !== false) {\n const installSpinner = ora('Installing statusline...').start()\n \n try {\n await installStatusline(script, resolvedPath, config)\n installSpinner.succeed('āœ… Statusline installed!')\n \n console.log(chalk.green('\\nšŸŽ‰ Success! Your custom statusline is ready!'))\n console.log(chalk.cyan(`\\nšŸ“ Generated file: ${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 installSpinner.fail('Failed to install statusline')\n \n if (error instanceof Error && error.message === 'SETTINGS_UPDATE_FAILED') {\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 .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\": \".claude/statusline.sh\",`))\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}\n\nexport async function collectConfiguration(): Promise<StatuslineConfig> {\n console.log('šŸš€ Welcome to cc-statusline! Let\\'s create your custom Claude Code statusline.\\n')\n\n // Step 1: Core features (most users want these)\n const coreConfig = await inquirer.prompt([\n {\n type: 'checkbox',\n name: 'coreFeatures',\n message: 'šŸ“‹ Select core features for your statusline:',\n choices: [\n { name: 'šŸ“ Working Directory', value: 'directory', checked: true },\n { name: '🌿 Git Branch', value: 'git', checked: true },\n { name: 'šŸ¤– Model Name', value: 'model', checked: true },\n { name: '🧠 Context Window (remaining %)', value: 'context', checked: true }\n ],\n validate: (answer: string[]) => {\n if (answer.length < 1) {\n return 'You must choose at least one core feature.'\n }\n return true\n }\n }\n ])\n\n // Step 2: Usage tracking\n const usageConfig = await inquirer.prompt([\n {\n type: 'confirm',\n name: 'enableUsage',\n message: 'šŸ’° Enable cost and session tracking? (requires ccusage)',\n default: true\n }\n ])\n\n let usageFeatures: string[] = []\n if (usageConfig.enableUsage) {\n const usageDetails = await inquirer.prompt([\n {\n type: 'checkbox',\n name: 'usageFeatures',\n message: 'šŸ“Š Which usage features would you like?',\n choices: [\n { name: 'šŸ’µ Cost & Hourly Rate', value: 'usage', checked: true },\n { name: 'āŒ› Session Time Remaining', value: 'session', checked: true },\n { name: 'šŸ“Š Token Statistics', value: 'tokens', checked: false },\n { name: '⚔ Burn Rate (tokens/min)', value: 'burnrate', checked: false }\n ]\n }\n ])\n usageFeatures = usageDetails.usageFeatures\n }\n\n // Step 3: Display options\n const displayConfig = await inquirer.prompt([\n {\n type: 'confirm',\n name: 'colors',\n message: 'šŸŽØ Enable colors and emojis?',\n default: true\n },\n {\n type: 'confirm',\n name: 'logging',\n message: 'šŸ“ Enable debug logging? (for troubleshooting)',\n default: false\n }\n ])\n\n // Combine all selected features\n const allFeatures = [...coreConfig.coreFeatures, ...usageFeatures]\n\n // Set intelligent defaults\n return {\n features: allFeatures,\n runtime: 'bash',\n colors: displayConfig.colors,\n theme: 'detailed',\n ccusageIntegration: usageConfig.enableUsage,\n logging: displayConfig.logging,\n customEmojis: false\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, generateUsageUtilities } from '../features/usage.js'\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 (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\n${config.logging ? generateLoggingCode() : ''}\n${generateBasicDataExtraction(hasDirectory, hasModel, hasContext)}\n${generateColorBashCode({ enabled: config.colors, theme: config.theme })}\n${config.colors ? generateBasicColors() : ''}\n${hasUsage ? generateUsageUtilities() : ''}\n${hasGit ? generateGitUtilities() : ''}\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# Enable logging\nLOG_FILE=\"\\${HOME}/.claude/statusline.log\"\nLOG_ENABLED=1\n\n# Logging function\nlog_debug() {\n if [ \"$LOG_ENABLED\" -eq 1 ]; then\n echo \"[$(date '+%Y-%m-%d %H:%M:%S')] $1\" >> \"$LOG_FILE\"\n fi\n}\n\nlog_debug \"=== Statusline execution started ===\"\n`\n}\n\nfunction generateBasicDataExtraction(hasDirectory: boolean, hasModel: boolean, hasContext: boolean): string {\n return `\ninput=$(cat)\nlog_debug \"Input received: \\${#input} characters\"\n\nlog_debug \"Color state: use_color=\\$use_color, NO_COLOR=\\${NO_COLOR:-unset}, TTY test: \\$([ -t 1 ] && echo 'yes' || echo 'no')\"\n\n# ---- basics ----\nif command -v jq >/dev/null 2>&1; then\n log_debug \"jq found, parsing JSON input\"${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 log_debug \"Parsed: dir=\\${current_dir:-}, model=\\${model_name:-}, version=\\${model_version:-}, session=\\${session_id:-}\"\nelse\n log_debug \"jq not found, using defaults\"${hasDirectory ? `\n current_dir=\"unknown\"` : ''}${hasModel ? `\n model_name=\"Claude\"; model_version=\"\"` : ''}${hasContext ? `\n session_id=\"\"` : ''}\nfi\n`\n}\n\nfunction generateContextBashCode(colors: boolean): string {\n const sessionColors = colors ? `\n# ---- session colors (blue/cyan to differentiate from context) ----\nsession_color() { \n rem_pct=$(( 100 - session_pct ))\n # Use blue/cyan colors to differentiate from context (green/yellow/red)\n if (( rem_pct <= 10 )); then SCLR='1;94' # bright blue\n elif (( rem_pct <= 25 )); then SCLR='1;96' # bright cyan\n else SCLR='1;34'; fi # blue\n if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[%sm' \"$SCLR\"; fi\n}` : `\nsession_color() { :; }`\n\n return `\n# ---- context window calculation ----\ncontext_tokens=0; context_pct=0; context_remaining=0\n\n# Determine max context based on model\nget_max_context() {\n local model_name=\"$1\"\n case \"$model_name\" in\n # Claude 3.5 and Claude 4.x models (all have 200K)\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 (3.5+ and 4.x)\n ;;\n # Legacy Claude 3.0 models (smaller context windows)\n *\"Claude 3 Haiku\"*|*\"claude 3 haiku\"*)\n echo \"100000\" # 100K for original Claude 3 Haiku\n ;;\n # Generic Claude patterns\n *\"Claude\"*|*\"claude\"*)\n echo \"200000\" # Default to 200K for any Claude model\n ;;\n *)\n echo \"200000\" # Default to 200K for unknown models\n ;;\n esac\n}\n\nMAX_CONTEXT=$(get_max_context \"$model_name\")\nlog_debug \"Model: $model_name, Max context: $MAX_CONTEXT\"\n\n# Progress bar function for context remaining\ncontext_progress_bar() {\n local remaining_pct=\"$1\"\n local width=\"$2\"\n # Clamp percentage to 0-100\n [ \"$remaining_pct\" -lt 0 ] && remaining_pct=0\n [ \"$remaining_pct\" -gt 100 ] && remaining_pct=100\n \n local filled=$(( remaining_pct * width / 100 ))\n local empty=$(( width - filled ))\n \n # Use different characters: ā–  for remaining, ā–” for used\n printf '%*s' \"$filled\" '' | tr ' ' 'ā– '\n printf '%*s' \"$empty\" '' | tr ' ' 'ā–”'\n}\n\nif [ -n \"$session_id\" ] && command -v jq >/dev/null 2>&1; then\n # Convert current dir to session file path\n project_dir=$(echo \"$current_dir\" | sed \"s|~|$HOME|g\" | sed 's|/|-|g')\n session_file=\"$HOME/.claude/projects/\\${project_dir}/\\${session_id}.jsonl\"\n \n log_debug \"Looking for session file: $session_file\"\n \n if [ -f \"$session_file\" ]; then\n # Get the latest token count from the session file\n latest_tokens=$(cat \"$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\" -ne 0 ]; then\n context_tokens=$latest_tokens\n context_pct=$(( context_tokens * 100 / MAX_CONTEXT ))\n context_remaining=$(( MAX_CONTEXT - context_tokens ))\n log_debug \"Context: tokens=$context_tokens, pct=$context_pct%, remaining=$context_remaining\"\n fi\n fi\nfi${sessionColors}\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:-}, cost=\\${cost_usd:-}, cost_ph=\\${cost_per_hour:-}, tokens=\\${tot_tokens:-}, tpm=\\${tpm:-}, session_pct=\\${session_pct:-}, context=\\${context_tokens:-}/\\${MAX_CONTEXT:-}\"\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 let displayCode = `\n# ---- render statusline ----\n# Add reset code at the beginning to override any terminal dim settings\nprintf '\\\\033[0m'`\n\n // Directory\n if (config.features.includes('directory')) {\n const dirEmoji = emojis ? 'šŸ“' : 'dir:'\n displayCode += `\nprintf '${dirEmoji} %s%s%s' \"$(dir_color)\" \"$current_dir\" \"$(rst)\"`\n }\n\n // Git\n displayCode += generateGitDisplayCode(gitConfig, config.colors, emojis)\n\n // Model\n if (config.features.includes('model')) {\n const modelEmoji = emojis ? 'šŸ¤–' : 'model:'\n displayCode += `\nprintf ' ${modelEmoji} %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`\n }\n\n // Context window\n if (config.features.includes('context')) {\n const contextEmoji = emojis ? '🧠' : 'ctx:'\n displayCode += `\n# context window display\nif [ \"$context_tokens\" -gt 0 ]; then\n # Calculate percentage remaining instead of used\n remaining_pct=$(( 100 - context_pct ))\n \n # Color based on how much is remaining\n if [ \"$remaining_pct\" -lt 20 ]; then\n if [ \"$use_color\" -eq 1 ]; then\n context_color=$(printf '\\\\033[1;31m') # bold red if <20% remaining\n else\n context_color=\"\"\n fi\n elif [ \"$remaining_pct\" -lt 40 ]; then\n if [ \"$use_color\" -eq 1 ]; then\n context_color=$(printf '\\\\033[1;33m') # bold yellow if <40% remaining\n else\n context_color=\"\"\n fi\n else\n if [ \"$use_color\" -eq 1 ]; then\n context_color=$(printf '\\\\033[1;32m') # bold green if >40% remaining\n else\n context_color=\"\"\n fi\n fi\n \n # Create context progress bar (showing remaining, not used)\n context_bar=$(context_progress_bar \"$remaining_pct\" 10)\n \n printf ' ${contextEmoji} Context Left: %s%d%% [%s]%s' \"$context_color\" \"$remaining_pct\" \"$context_bar\" \"$(rst)\"\nelse\n # Show TBD when context info isn't available yet\n if [ \"$use_color\" -eq 1 ]; then\n context_color=$(printf '\\\\033[1;37m') # bright white/gray for TBD\n else\n context_color=\"\"\n fi\n printf ' ${contextEmoji} Context Left: %sTBD%s' \"$context_color\" \"$(rst)\"\nfi`\n }\n\n // Usage features on second line\n if (usageConfig.enabled) {\n displayCode += `\n# Add newline before usage/analytics line\nusage_line_content=\"\"\n${generateUsageLineContent(usageConfig, config.colors, emojis)}\n\n# Print usage line only if there's content\nif [ -n \"$usage_line_content\" ]; then\n printf '\\\\\\\\n%s' \"$usage_line_content\"\nfi`\n }\n\n // Add newline at the end\n displayCode += `\nprintf '\\\\\\\\n'`\n\n return displayCode\n}\n\nfunction generateUsageLineContent(usageConfig: any, colors: boolean, emojis: boolean): string {\n let usageContent = ''\n\n // Session time\n if (usageConfig.showSession) {\n const sessionEmoji = emojis ? 'āŒ›' : 'session:'\n usageContent += `\n# session time\nif [ -n \"$session_txt\" ]; then\n usage_line_content=\"\\\\${usage_line_content}${sessionEmoji} \\\\$(session_color)\\\\${session_txt}\\\\$(rst) \\\\$(session_color)[\\\\${session_bar}]\\\\$(rst)\"\nfi`\n }\n\n // Cost tracking\n if (usageConfig.showCost) {\n const costEmoji = emojis ? 'šŸ’µ' : 'cost:'\n usageContent += `\n# cost\nif [ -n \"$cost_usd\" ] && [[ \"$cost_usd\" =~ ^[0-9.]+$ ]]; then\n if [ -n \"$cost_per_hour\" ] && [[ \"$cost_per_hour\" =~ ^[0-9.]+$ ]]; then\n usage_line_content=\"\\\\${usage_line_content} ${costEmoji} \\\\$(cost_color)\\\\$\\\\$(printf '%.2f' \\\\\"$cost_usd\\\\\") (\\\\$\\\\$(printf '%.2f' \\\\\"$cost_per_hour\\\\\")/h)\\\\$(rst)\"\n else\n usage_line_content=\"\\\\${usage_line_content} ${costEmoji} \\\\$(cost_color)\\\\$\\\\$(printf '%.2f' \\\\\"$cost_usd\\\\\")\\\\$(rst)\"\n fi\nfi`\n }\n\n // Token statistics\n if (usageConfig.showTokens) {\n const tokenEmoji = emojis ? 'šŸ“Š' : 'tokens:'\n if (usageConfig.showBurnRate) {\n usageContent += `\n# tokens with burn rate\nif [ -n \"$tot_tokens\" ] && [[ \"$tot_tokens\" =~ ^[0-9]+$ ]]; then\n if [ -n \"$tpm\" ] && [[ \"$tpm\" =~ ^[0-9.]+$ ]]; then\n usage_line_content=\"\\\\${usage_line_content} ${tokenEmoji} \\\\$(usage_color)\\\\${tot_tokens} tok (\\\\$(printf '%.0f' \\\\\"$tpm\\\\\") tpm)\\\\$(rst)\"\n else\n usage_line_content=\"\\\\${usage_line_content} ${tokenEmoji} \\\\$(usage_color)\\\\${tot_tokens} tok\\\\$(rst)\"\n fi\nfi`\n } else {\n usageContent += `\n# tokens only\nif [ -n \"$tot_tokens\" ] && [[ \"$tot_tokens\" =~ ^[0-9]+$ ]]; then\n usage_line_content=\"\\\\${usage_line_content} ${tokenEmoji} \\\\$(usage_color)\\\\${tot_tokens} tok\\\\$(rst)\"\nfi`\n }\n } else if (usageConfig.showBurnRate) {\n // Show burn rate without tokens\n const burnEmoji = emojis ? '⚔' : 'tpm:'\n usageContent += `\n# burn rate only\nif [ -n \"$tpm\" ] && [[ \"$tpm\" =~ ^[0-9.]+$ ]]; then\n usage_line_content=\"\\\\${usage_line_content} ${burnEmoji} \\\\$(usage_color)\\\\$(printf '%.0f' \\\\\"$tpm\\\\\") tpm\\\\$(rst)\"\nfi`\n }\n\n return usageContent\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) ----\n# Force colors for Claude Code statusline (Claude Code doesn't pass TTY)\nuse_color=1\n# Only disable if NO_COLOR is explicitly set\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# ---- basic colors ----\ndir_color() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[1;36m'; fi; } # bold cyan\nmodel_color() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[1;35m'; fi; } # bold magenta \nversion_color() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[1;33m'; fi; } # bold yellow\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[1;32m'; fi; }\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[1;35m'; fi; }\ncost_color() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[1;36m'; fi; }\nsession_color() { \n rem_pct=$(( 100 - session_pct ))\n if (( rem_pct <= 10 )); then SCLR='1;31'\n elif (( rem_pct <= 25 )); then SCLR='1;33'\n else SCLR='1;32'; fi\n if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[%sm' \"$SCLR\"; fi\n}\n` : `\nusage_color() { :; }\ncost_color() { :; }\nsession_color() { :; }\n`\n\n return `${colorCode}\n# ---- ccusage integration ----\nsession_txt=\"\"; session_pct=0; session_bar=\"\"\ncost_usd=\"\"; cost_per_hour=\"\"; tpm=\"\"; tot_tokens=\"\"\n\nif command -v jq >/dev/null 2>&1; then\n blocks_output=$(npx ccusage@latest blocks --json 2>/dev/null || ccusage blocks --json 2>/dev/null)\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.showCost ? `\n cost_usd=$(echo \"$active_block\" | jq -r '.costUSD // empty')\n cost_per_hour=$(echo \"$active_block\" | jq -r '.burnRate.costPerHour // empty')` : ''}${config.showTokens ? `\n tot_tokens=$(echo \"$active_block\" | jq -r '.totalTokens // empty')` : ''}${config.showBurnRate ? `\n tpm=$(echo \"$active_block\" | jq -r '.burnRate.tokensPerMinute // empty')` : ''}${config.showSession || config.showProgressBar ? `\n \n # Session time calculation\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'\n\nexport async function installStatusline(\n script: string,\n outputPath: string,\n config: StatuslineConfig\n): Promise<void> {\n try {\n // Ensure the directory exists\n const dir = path.dirname(outputPath)\n await fs.mkdir(dir, { recursive: true })\n\n // Write the script\n await fs.writeFile(outputPath, script, { mode: 0o755 })\n\n // Update .claude/settings.json if it exists\n await updateSettingsJson(dir, path.basename(outputPath))\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): Promise<void> {\n const settingsPath = path.join(claudeDir, 'settings.json')\n \n try {\n let settings: any = {}\n \n // Try to read existing settings\n try {\n const settingsContent = await fs.readFile(settingsPath, 'utf-8')\n settings = JSON.parse(settingsContent)\n } catch {\n // File doesn't exist or invalid JSON, start fresh\n }\n\n // Update statusLine configuration\n settings.statusLine = {\n type: 'command',\n command: `.claude/${scriptName}`,\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","path","testStatuslineScript","generateMockClaudeInput","chalk","previewCommand"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chongdashu/cc-statusline",
3
- "version": "1.0.1",
3
+ "version": "1.1.0",
4
4
  "description": "Interactive CLI tool for generating custom Claude Code statuslines",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",