@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 +25 -0
- package/README.md +165 -136
- package/dist/index.js +276 -77
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
-
|
|
3
|
+
<div align="center">
|
|
4
4
|
|
|
5
|
-
Transform your Claude Code experience with a beautiful, informative statusline
|
|
5
|
+
š **Transform your Claude Code experience with a beautiful, informative statusline**
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
<img src="docs/images/cc-statusline-running.gif" alt="cc-statusline in action" width="600">
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
*Real-time directory, git branch, model info, costs, and session time tracking*
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
[](https://www.npmjs.com/package/@chongdashu/cc-statusline)
|
|
12
|
+
[](https://opensource.org/licenses/MIT)
|
|
13
|
+
[](https://nodejs.org/)
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
</div>
|
|
16
16
|
|
|
17
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
29
|
+
<img src="docs/images/cc-statusline-init.gif" alt="Demo of cc-statusline setup" width="500">
|
|
60
30
|
|
|
61
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
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
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
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
|
-
|
|
64
|
+
### šØ Example Outputs
|
|
90
65
|
|
|
91
|
-
**Minimal
|
|
66
|
+
**Minimal Setup:**
|
|
92
67
|
```
|
|
93
68
|
š ~/my-app šæ main š¤ Claude Sonnet
|
|
94
69
|
```
|
|
95
70
|
|
|
96
|
-
**With
|
|
71
|
+
**With Context Tracking:**
|
|
97
72
|
```
|
|
98
|
-
š ~/my-app šæ main š¤
|
|
73
|
+
š ~/my-app šæ main š¤ Sonnet 4 š§ Context Left: 58% [ā ā ā ā ā ā ā”ā”ā”ā”]
|
|
99
74
|
```
|
|
100
75
|
|
|
101
|
-
**Full
|
|
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
|
-
|
|
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
|
-
##
|
|
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
|
-
|
|
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
|
-
**
|
|
113
|
-
-
|
|
114
|
-
-
|
|
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
|
-
|
|
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
|
-
## š
|
|
141
|
+
## š File Structure
|
|
122
142
|
|
|
123
|
-
After
|
|
143
|
+
After installation, you'll have a clean setup:
|
|
124
144
|
|
|
125
145
|
```
|
|
126
146
|
.claude/
|
|
127
|
-
āāā statusline.sh # Your
|
|
128
|
-
āāā settings.json # Auto-updated
|
|
147
|
+
āāā statusline.sh # šÆ Your generated statusline script
|
|
148
|
+
āāā settings.json # āļø Auto-updated Claude Code configuration
|
|
129
149
|
```
|
|
130
150
|
|
|
131
|
-
|
|
132
|
-
|
|
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
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
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
|
-
|
|
177
|
-
|
|
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
|
-
|
|
180
|
-
|
|
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
|
-
|
|
183
|
-
|
|
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
|
-
|
|
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
|
-
|
|
210
|
+
See our [Contributing Guide](CONTRIBUTING.md) for detailed information.
|
|
189
211
|
|
|
190
|
-
|
|
191
|
-
- Code standards and conventions
|
|
192
|
-
- Testing your changes
|
|
193
|
-
- Submitting pull requests
|
|
212
|
+
## š Stats
|
|
194
213
|
|
|
195
|
-
|
|
214
|
+
<div align="center">
|
|
196
215
|
|
|
197
|
-
|
|
216
|
+

|
|
217
|
+

|
|
218
|
+

|
|
198
219
|
|
|
199
|
-
|
|
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
|
-
|
|
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
|
|
301
|
+
const coreConfig = await inquirer.prompt([
|
|
302
302
|
{
|
|
303
303
|
type: "checkbox",
|
|
304
|
-
name: "
|
|
305
|
-
message: "
|
|
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
|
|
310
|
-
{ name: "\u{
|
|
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:
|
|
361
|
+
features: allFeatures,
|
|
331
362
|
runtime: "bash",
|
|
332
|
-
colors:
|
|
363
|
+
colors: displayConfig.colors,
|
|
333
364
|
theme: "detailed",
|
|
334
|
-
ccusageIntegration:
|
|
335
|
-
|
|
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 (
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
569
|
+
LOG_ENABLED=1
|
|
575
570
|
|
|
576
|
-
#
|
|
577
|
-
{
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
}
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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":"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","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"]}
|