ccstatusline 1.0.13 → 1.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +90 -36
- package/dist/ccstatusline.js +154 -29
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,36 +1,31 @@
|
|
|
1
1
|
# ccstatusline
|
|
2
2
|
|
|
3
|
-
A customizable status line formatter for Claude Code CLI that displays model info, git branch, token usage, and other metrics in your terminal.
|
|
3
|
+
> 🎨 A highly customizable status line formatter for Claude Code CLI that displays model info, git branch, token usage, and other metrics in your terminal.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+

|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
- 🎨 **Fully customizable** - Choose what to display and customize colors
|
|
9
|
-
- 📐 **Multi-line support** - Configure up to 3 status lines
|
|
10
|
-
- 🖥️ **Interactive TUI** - Built-in configuration interface using React/Ink
|
|
11
|
-
- 🚀 **Cross-platform** - Works with both Bun and Node.js
|
|
12
|
-
- 📏 **Auto-width detection** - Automatically adapts to terminal width with flex separators
|
|
7
|
+
## ✨ Features
|
|
13
8
|
|
|
14
|
-
|
|
9
|
+
- **📊 Real-time Metrics** - Display model name, git branch, token usage, session duration, and more
|
|
10
|
+
- **🎨 Fully Customizable** - Choose what to display and customize colors for each element
|
|
11
|
+
- **📐 Multi-line Support** - Configure up to 3 independent status lines
|
|
12
|
+
- **🖥️ Interactive TUI** - Built-in configuration interface using React/Ink
|
|
13
|
+
- **🚀 Cross-platform** - Works seamlessly with both Bun and Node.js
|
|
14
|
+
- **📏 Smart Width Detection** - Automatically adapts to terminal width with flex separators
|
|
15
|
+
- **⚡ Zero Config** - Sensible defaults that work out of the box
|
|
15
16
|
|
|
16
|
-
|
|
17
|
+
## 🚀 Quick Start
|
|
18
|
+
|
|
19
|
+
### No installation needed! Use directly with npx:
|
|
17
20
|
|
|
18
21
|
```bash
|
|
19
22
|
# Run the configuration TUI
|
|
20
23
|
npx ccstatusline@latest
|
|
21
24
|
```
|
|
22
25
|
|
|
23
|
-
## Setup
|
|
24
|
-
|
|
25
26
|
### Configure ccstatusline
|
|
26
27
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
```bash
|
|
30
|
-
npx ccstatusline@latest
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
This launches a TUI where you can:
|
|
28
|
+
The interactive configuration tool provides a terminal UI where you can:
|
|
34
29
|
- Configure up to 3 separate status lines
|
|
35
30
|
- Add/remove/reorder status line items
|
|
36
31
|
- Customize colors for each element
|
|
@@ -39,13 +34,13 @@ This launches a TUI where you can:
|
|
|
39
34
|
- Install/uninstall to Claude Code settings
|
|
40
35
|
- Preview your status line in real-time
|
|
41
36
|
|
|
42
|
-
Your settings are saved to `~/.config/ccstatusline/settings.json
|
|
37
|
+
> 💡 **Tip:** Your settings are automatically saved to `~/.config/ccstatusline/settings.json`
|
|
43
38
|
|
|
44
|
-
## Usage
|
|
39
|
+
## 📖 Usage
|
|
45
40
|
|
|
46
41
|
Once configured, ccstatusline automatically formats your Claude Code status line. The status line appears at the bottom of your terminal during Claude Code sessions.
|
|
47
42
|
|
|
48
|
-
### Available Status Items
|
|
43
|
+
### 📊 Available Status Items
|
|
49
44
|
|
|
50
45
|
- **Model Name** - Shows the current Claude model (e.g., "Claude 3.5 Sonnet")
|
|
51
46
|
- **Git Branch** - Displays current git branch name
|
|
@@ -60,10 +55,11 @@ Once configured, ccstatusline automatically formats your Claude Code status line
|
|
|
60
55
|
- **Context Percentage** - Shows percentage of context limit used
|
|
61
56
|
- **Terminal Width** - Shows detected terminal width (for debugging)
|
|
62
57
|
- **Custom Text** - Add your own custom text to the status line
|
|
58
|
+
- **Custom Command** - Execute shell commands and display their output (refreshes whenever the statusline is updated by Claude Code)
|
|
63
59
|
- **Separator** - Visual divider between items (customizable: |, -, comma, space)
|
|
64
60
|
- **Flex Separator** - Expands to fill available space
|
|
65
61
|
|
|
66
|
-
### TUI Controls
|
|
62
|
+
### ⌨️ TUI Controls
|
|
67
63
|
|
|
68
64
|
#### Main Menu
|
|
69
65
|
- **↑↓** - Navigate menu items
|
|
@@ -79,7 +75,10 @@ Once configured, ccstatusline automatically formats your Claude Code status line
|
|
|
79
75
|
- **d** - Delete selected item
|
|
80
76
|
- **c** - Clear entire line
|
|
81
77
|
- **r** - Toggle raw value mode (no labels)
|
|
82
|
-
- **e** - Edit
|
|
78
|
+
- **e** - Edit value (for custom-text and custom-command items)
|
|
79
|
+
- **w** - Set max width (for custom-command items)
|
|
80
|
+
- **t** - Set timeout in milliseconds (for custom-command items)
|
|
81
|
+
- **p** - Toggle preserve colors (for custom-command items)
|
|
83
82
|
- **Space** - Change separator character (for separator items)
|
|
84
83
|
- **ESC** - Go back
|
|
85
84
|
|
|
@@ -94,23 +93,63 @@ Configure how flex separators calculate available width:
|
|
|
94
93
|
- **Full width minus 40** - Leaves space for auto-compact message (default)
|
|
95
94
|
- **Full width until compact** - Switches based on context percentage threshold
|
|
96
95
|
|
|
97
|
-
### Raw Value Mode
|
|
96
|
+
### 🔤 Raw Value Mode
|
|
98
97
|
|
|
99
98
|
Some items support "raw value" mode which displays just the value without a label:
|
|
100
99
|
- Normal: `Model: Claude 3.5 Sonnet` → Raw: `Claude 3.5 Sonnet`
|
|
101
100
|
- Normal: `Session: 2hr 15m` → Raw: `2hr 15m`
|
|
102
101
|
- Normal: `Ctx: 18.6k` → Raw: `18.6k`
|
|
103
102
|
|
|
104
|
-
###
|
|
103
|
+
### 🔧 Custom Widgets
|
|
104
|
+
|
|
105
|
+
#### Custom Text Widget
|
|
106
|
+
Add static text to your status line. Perfect for:
|
|
107
|
+
- Project identifiers
|
|
108
|
+
- Environment indicators (dev/prod)
|
|
109
|
+
- Personal labels or reminders
|
|
110
|
+
|
|
111
|
+
#### Custom Command Widget
|
|
112
|
+
Execute shell commands and display their output dynamically:
|
|
113
|
+
- Refreshes whenever the statusline is updated by Claude Code
|
|
114
|
+
- Receives the full Claude Code JSON data via stdin (model info, session ID, transcript path, etc.)
|
|
115
|
+
- Displays command output inline in your status line
|
|
116
|
+
- Configurable timeout (default: 1000ms)
|
|
117
|
+
- Examples:
|
|
118
|
+
- `pwd | xargs basename` - Show current directory name
|
|
119
|
+
- `node -v` - Display Node.js version
|
|
120
|
+
- `git rev-parse --short HEAD` - Show current commit hash
|
|
121
|
+
- `date +%H:%M` - Display current time
|
|
122
|
+
- `curl -s wttr.in?format="%t"` - Show current temperature
|
|
123
|
+
- `npx -y ccusage statusline` - Display Claude usage metrics (set timeout: 5000ms)
|
|
124
|
+
|
|
125
|
+
> ⚠️ **Note:** Commands should complete quickly to avoid delays. Long-running commands will be killed after the configured timeout. If you're not seeing output from your custom command, try increasing the timeout value (press 't' in the editor).
|
|
126
|
+
|
|
127
|
+
> 💡 **Tip:** Custom commands can be other Claude Code compatible status line formatters! They receive the same JSON via stdin that ccstatusline receives from Claude Code, allowing you to chain or combine multiple status line tools.
|
|
128
|
+
|
|
129
|
+
### 🔗 Integration Example: ccusage
|
|
130
|
+
|
|
131
|
+
[ccusage](https://github.com/samuelint/ccusage) is a tool that tracks and displays Claude Code usage metrics. You can integrate it directly into your status line:
|
|
132
|
+
|
|
133
|
+
1. Add a Custom Command widget
|
|
134
|
+
2. Set command: `npx -y ccusage statusline`
|
|
135
|
+
3. Set timeout: `5000` (5 seconds for initial download)
|
|
136
|
+
4. Enable "preserve colors" to keep ccusage's color formatting
|
|
137
|
+
|
|
138
|
+

|
|
139
|
+
|
|
140
|
+
The command receives Claude Code's JSON data via stdin, allowing ccusage to access session information, model details, and transcript data for accurate usage tracking.
|
|
141
|
+
|
|
142
|
+
### ✂️ Smart Truncation
|
|
105
143
|
|
|
106
144
|
When terminal width is detected, status lines automatically truncate with ellipsis (...) if they exceed the available width, preventing line wrapping.
|
|
107
145
|
|
|
108
|
-
## Development
|
|
146
|
+
## 🛠️ Development
|
|
109
147
|
|
|
110
148
|
### Prerequisites
|
|
111
149
|
|
|
112
|
-
- [Bun](https://bun.sh)
|
|
150
|
+
- [Bun](https://bun.sh) (v1.0+)
|
|
113
151
|
- Git
|
|
152
|
+
- Node.js 18+ (optional, for npm publishing)
|
|
114
153
|
|
|
115
154
|
### Setup
|
|
116
155
|
|
|
@@ -133,7 +172,7 @@ bun run src/ccstatusline.ts
|
|
|
133
172
|
bun run build
|
|
134
173
|
```
|
|
135
174
|
|
|
136
|
-
### Project Structure
|
|
175
|
+
### 📁 Project Structure
|
|
137
176
|
|
|
138
177
|
```
|
|
139
178
|
ccstatusline/
|
|
@@ -147,7 +186,7 @@ ccstatusline/
|
|
|
147
186
|
├── tsconfig.json
|
|
148
187
|
└── README.md
|
|
149
188
|
```
|
|
150
|
-
## Contributing
|
|
189
|
+
## 🤝 Contributing
|
|
151
190
|
|
|
152
191
|
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
153
192
|
|
|
@@ -157,14 +196,29 @@ Contributions are welcome! Please feel free to submit a Pull Request.
|
|
|
157
196
|
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
158
197
|
5. Open a Pull Request
|
|
159
198
|
|
|
160
|
-
## License
|
|
199
|
+
## 📄 License
|
|
200
|
+
|
|
201
|
+
[MIT](LICENSE) © Matthew Breedlove
|
|
202
|
+
|
|
203
|
+
## 👤 Author
|
|
204
|
+
|
|
205
|
+
**Matthew Breedlove**
|
|
161
206
|
|
|
162
|
-
|
|
207
|
+
- GitHub: [@sirmalloc](https://github.com/sirmalloc)
|
|
163
208
|
|
|
164
|
-
##
|
|
209
|
+
## 🙏 Acknowledgments
|
|
165
210
|
|
|
166
|
-
|
|
211
|
+
- Built for use with [Claude Code CLI](https://claude.ai/code) by Anthropic
|
|
212
|
+
- Powered by [Ink](https://github.com/vadimdemedes/ink) for the terminal UI
|
|
213
|
+
- Made with ❤️ for the Claude Code community
|
|
167
214
|
|
|
168
|
-
|
|
215
|
+
---
|
|
169
216
|
|
|
170
|
-
|
|
217
|
+
<p align="center">
|
|
218
|
+
<a href="https://www.npmjs.com/package/ccstatusline">
|
|
219
|
+
<img src="https://img.shields.io/npm/v/ccstatusline.svg" alt="npm version">
|
|
220
|
+
</a>
|
|
221
|
+
<a href="https://github.com/sirmalloc/ccstatusline/blob/main/LICENSE">
|
|
222
|
+
<img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License">
|
|
223
|
+
</a>
|
|
224
|
+
</p>
|
package/dist/ccstatusline.js
CHANGED
|
@@ -182,7 +182,7 @@ async function getExistingStatusLine() {
|
|
|
182
182
|
// src/tui.tsx
|
|
183
183
|
import * as fs3 from "fs";
|
|
184
184
|
import * as path3 from "path";
|
|
185
|
-
var __dirname = "/Users/sirmalloc/
|
|
185
|
+
var __dirname = "/Users/sirmalloc/Projects/Personal/ccstatusline/src";
|
|
186
186
|
import { jsxDEV, Fragment } from "react/jsx-dev-runtime";
|
|
187
187
|
function getPackageVersion() {
|
|
188
188
|
try {
|
|
@@ -254,31 +254,31 @@ var renderSingleLine = (items, terminalWidth, widthDetectionAvailable, settings)
|
|
|
254
254
|
elements.push(changesColor("(+42,-10)"));
|
|
255
255
|
break;
|
|
256
256
|
case "tokens-input":
|
|
257
|
-
const inputColor = chalk[item.color || "
|
|
257
|
+
const inputColor = chalk[item.color || "blue"] || chalk.blue;
|
|
258
258
|
elements.push(inputColor(item.rawValue ? "15.2k" : "In: 15.2k"));
|
|
259
259
|
break;
|
|
260
260
|
case "tokens-output":
|
|
261
|
-
const outputColor = chalk[item.color || "
|
|
261
|
+
const outputColor = chalk[item.color || "white"] || chalk.white;
|
|
262
262
|
elements.push(outputColor(item.rawValue ? "3.4k" : "Out: 3.4k"));
|
|
263
263
|
break;
|
|
264
264
|
case "tokens-cached":
|
|
265
|
-
const cachedColor = chalk[item.color || "
|
|
265
|
+
const cachedColor = chalk[item.color || "cyan"] || chalk.cyan;
|
|
266
266
|
elements.push(cachedColor(item.rawValue ? "12k" : "Cached: 12k"));
|
|
267
267
|
break;
|
|
268
268
|
case "tokens-total":
|
|
269
|
-
const totalColor = chalk[item.color || "
|
|
269
|
+
const totalColor = chalk[item.color || "cyan"] || chalk.cyan;
|
|
270
270
|
elements.push(totalColor(item.rawValue ? "30.6k" : "Total: 30.6k"));
|
|
271
271
|
break;
|
|
272
272
|
case "context-length":
|
|
273
|
-
const ctxColor = chalk[item.color || "
|
|
273
|
+
const ctxColor = chalk[item.color || "dim"] || chalk.dim;
|
|
274
274
|
elements.push(ctxColor(item.rawValue ? "18.6k" : "Ctx: 18.6k"));
|
|
275
275
|
break;
|
|
276
276
|
case "context-percentage":
|
|
277
|
-
const ctxPctColor = chalk[item.color || "
|
|
277
|
+
const ctxPctColor = chalk[item.color || "blue"] || chalk.blue;
|
|
278
278
|
elements.push(ctxPctColor(item.rawValue ? "9.3%" : "Ctx: 9.3%"));
|
|
279
279
|
break;
|
|
280
280
|
case "session-clock":
|
|
281
|
-
const sessionColor = chalk[item.color || "
|
|
281
|
+
const sessionColor = chalk[item.color || "yellow"] || chalk.yellow;
|
|
282
282
|
elements.push(sessionColor(item.rawValue ? "2hr 15m" : "Session: 2hr 15m"));
|
|
283
283
|
break;
|
|
284
284
|
case "version":
|
|
@@ -286,7 +286,7 @@ var renderSingleLine = (items, terminalWidth, widthDetectionAvailable, settings)
|
|
|
286
286
|
elements.push(versionColor(item.rawValue ? "1.0.72" : "Version: 1.0.72"));
|
|
287
287
|
break;
|
|
288
288
|
case "terminal-width":
|
|
289
|
-
const termColor = chalk[item.color || "
|
|
289
|
+
const termColor = chalk[item.color || "gray"] || chalk.gray;
|
|
290
290
|
const detectedWidth = canDetectTerminalWidth() ? terminalWidth : "??";
|
|
291
291
|
elements.push(termColor(item.rawValue ? `${detectedWidth}` : `Term: ${detectedWidth}`));
|
|
292
292
|
break;
|
|
@@ -529,6 +529,8 @@ var ItemsEditor = ({ items, onUpdate, onBack, lineNumber }) => {
|
|
|
529
529
|
const [commandCursorPos, setCommandCursorPos] = useState(0);
|
|
530
530
|
const [editingMaxWidth, setEditingMaxWidth] = useState(false);
|
|
531
531
|
const [maxWidthInput, setMaxWidthInput] = useState("");
|
|
532
|
+
const [editingTimeout, setEditingTimeout] = useState(false);
|
|
533
|
+
const [timeoutInput, setTimeoutInput] = useState("");
|
|
532
534
|
const separatorChars = ["|", "-", ",", " "];
|
|
533
535
|
useInput((input, key) => {
|
|
534
536
|
if (editingText) {
|
|
@@ -619,6 +621,30 @@ var ItemsEditor = ({ items, onUpdate, onBack, lineNumber }) => {
|
|
|
619
621
|
} else if (input && /\d/.test(input)) {
|
|
620
622
|
setMaxWidthInput(maxWidthInput + input);
|
|
621
623
|
}
|
|
624
|
+
} else if (editingTimeout) {
|
|
625
|
+
if (key.return) {
|
|
626
|
+
const currentItem2 = items[selectedIndex];
|
|
627
|
+
if (currentItem2) {
|
|
628
|
+
const timeout = parseInt(timeoutInput, 10);
|
|
629
|
+
const newItems = [...items];
|
|
630
|
+
if (!isNaN(timeout) && timeout > 0) {
|
|
631
|
+
newItems[selectedIndex] = { ...currentItem2, timeout };
|
|
632
|
+
} else {
|
|
633
|
+
const { timeout: _, ...rest } = currentItem2;
|
|
634
|
+
newItems[selectedIndex] = rest;
|
|
635
|
+
}
|
|
636
|
+
onUpdate(newItems);
|
|
637
|
+
}
|
|
638
|
+
setEditingTimeout(false);
|
|
639
|
+
setTimeoutInput("");
|
|
640
|
+
} else if (key.escape) {
|
|
641
|
+
setEditingTimeout(false);
|
|
642
|
+
setTimeoutInput("");
|
|
643
|
+
} else if (key.backspace || key.delete) {
|
|
644
|
+
setTimeoutInput(timeoutInput.slice(0, -1));
|
|
645
|
+
} else if (input && /\d/.test(input)) {
|
|
646
|
+
setTimeoutInput(timeoutInput + input);
|
|
647
|
+
}
|
|
622
648
|
} else if (moveMode) {
|
|
623
649
|
if (key.upArrow && selectedIndex > 0) {
|
|
624
650
|
const newItems = [...items];
|
|
@@ -771,6 +797,12 @@ var ItemsEditor = ({ items, onUpdate, onBack, lineNumber }) => {
|
|
|
771
797
|
setMaxWidthInput(currentItem2.maxWidth ? currentItem2.maxWidth.toString() : "");
|
|
772
798
|
setEditingMaxWidth(true);
|
|
773
799
|
}
|
|
800
|
+
} else if (input === "t" && items.length > 0) {
|
|
801
|
+
const currentItem2 = items[selectedIndex];
|
|
802
|
+
if (currentItem2 && currentItem2.type === "custom-command") {
|
|
803
|
+
setTimeoutInput(currentItem2.timeout ? currentItem2.timeout.toString() : "1000");
|
|
804
|
+
setEditingTimeout(true);
|
|
805
|
+
}
|
|
774
806
|
} else if (input === "p" && items.length > 0) {
|
|
775
807
|
const currentItem2 = items[selectedIndex];
|
|
776
808
|
if (currentItem2 && currentItem2.type === "custom-command") {
|
|
@@ -783,14 +815,50 @@ var ItemsEditor = ({ items, onUpdate, onBack, lineNumber }) => {
|
|
|
783
815
|
}
|
|
784
816
|
}
|
|
785
817
|
});
|
|
818
|
+
const getDefaultColor = (type) => {
|
|
819
|
+
switch (type) {
|
|
820
|
+
case "model":
|
|
821
|
+
return "cyan";
|
|
822
|
+
case "git-branch":
|
|
823
|
+
return "magenta";
|
|
824
|
+
case "git-changes":
|
|
825
|
+
return "yellow";
|
|
826
|
+
case "session-clock":
|
|
827
|
+
return "yellow";
|
|
828
|
+
case "version":
|
|
829
|
+
return "green";
|
|
830
|
+
case "tokens-input":
|
|
831
|
+
return "blue";
|
|
832
|
+
case "tokens-output":
|
|
833
|
+
return "white";
|
|
834
|
+
case "tokens-cached":
|
|
835
|
+
return "cyan";
|
|
836
|
+
case "tokens-total":
|
|
837
|
+
return "cyan";
|
|
838
|
+
case "context-length":
|
|
839
|
+
return "dim";
|
|
840
|
+
case "context-percentage":
|
|
841
|
+
return "blue";
|
|
842
|
+
case "terminal-width":
|
|
843
|
+
return "gray";
|
|
844
|
+
case "custom-text":
|
|
845
|
+
return "white";
|
|
846
|
+
case "custom-command":
|
|
847
|
+
return "white";
|
|
848
|
+
default:
|
|
849
|
+
return "white";
|
|
850
|
+
}
|
|
851
|
+
};
|
|
786
852
|
const getItemDisplay = (item) => {
|
|
853
|
+
const colorName = item.color || getDefaultColor(item.type);
|
|
854
|
+
const colorFunc = chalk[colorName] || chalk.white;
|
|
787
855
|
switch (item.type) {
|
|
788
856
|
case "model":
|
|
789
|
-
return
|
|
857
|
+
return colorFunc("Model");
|
|
790
858
|
case "git-branch":
|
|
791
|
-
return
|
|
859
|
+
return colorFunc("Git Branch");
|
|
792
860
|
case "git-changes":
|
|
793
|
-
return
|
|
861
|
+
return colorFunc("Git Changes");
|
|
794
862
|
case "separator": {
|
|
795
863
|
const char = item.character || "|";
|
|
796
864
|
const charDisplay = char === " " ? "(space)" : char;
|
|
@@ -799,30 +867,34 @@ var ItemsEditor = ({ items, onUpdate, onBack, lineNumber }) => {
|
|
|
799
867
|
case "flex-separator":
|
|
800
868
|
return chalk.yellow("Flex Separator");
|
|
801
869
|
case "tokens-input":
|
|
802
|
-
return
|
|
870
|
+
return colorFunc("Tokens Input");
|
|
803
871
|
case "tokens-output":
|
|
804
|
-
return
|
|
872
|
+
return colorFunc("Tokens Output");
|
|
805
873
|
case "tokens-cached":
|
|
806
|
-
return
|
|
874
|
+
return colorFunc("Tokens Cached");
|
|
807
875
|
case "tokens-total":
|
|
808
|
-
return
|
|
876
|
+
return colorFunc("Tokens Total");
|
|
809
877
|
case "context-length":
|
|
810
|
-
return
|
|
878
|
+
return colorFunc("Context Length");
|
|
811
879
|
case "context-percentage":
|
|
812
|
-
return
|
|
880
|
+
return colorFunc("Context %");
|
|
813
881
|
case "session-clock":
|
|
814
|
-
return
|
|
882
|
+
return colorFunc("Session Clock");
|
|
815
883
|
case "terminal-width":
|
|
816
|
-
return
|
|
884
|
+
return colorFunc("Terminal Width");
|
|
817
885
|
case "version":
|
|
818
|
-
return
|
|
886
|
+
return colorFunc("Version");
|
|
819
887
|
case "custom-text":
|
|
820
888
|
const text = item.customText || "Empty";
|
|
821
|
-
return
|
|
889
|
+
return colorFunc(`Custom Text (${text})`);
|
|
822
890
|
case "custom-command":
|
|
823
891
|
const cmd = item.commandPath || "No command";
|
|
824
892
|
const truncatedCmd = cmd.length > 30 ? `${cmd.substring(0, 27)}...` : cmd;
|
|
825
|
-
|
|
893
|
+
if (!item.preserveColors) {
|
|
894
|
+
return colorFunc(`Custom Command (${truncatedCmd})`);
|
|
895
|
+
} else {
|
|
896
|
+
return chalk.white(`Custom Command (${truncatedCmd}) [preserving colors]`);
|
|
897
|
+
}
|
|
826
898
|
}
|
|
827
899
|
};
|
|
828
900
|
const hasFlexSeparator = items.some((item) => item.type === "flex-separator");
|
|
@@ -841,7 +913,7 @@ var ItemsEditor = ({ items, onUpdate, onBack, lineNumber }) => {
|
|
|
841
913
|
helpText += ", (e)dit text";
|
|
842
914
|
}
|
|
843
915
|
if (isCustomCommand) {
|
|
844
|
-
helpText += ", (e)dit cmd, (w)idth, (p)reserve colors";
|
|
916
|
+
helpText += ", (e)dit cmd, (w)idth, (t)imeout, (p)reserve colors";
|
|
845
917
|
}
|
|
846
918
|
helpText += ", Enter to move, (a)dd, (i)nsert, (d)elete, (c)lear line";
|
|
847
919
|
if (canToggleRaw) {
|
|
@@ -917,6 +989,20 @@ var ItemsEditor = ({ items, onUpdate, onBack, lineNumber }) => {
|
|
|
917
989
|
children: "Press Enter to save, ESC to cancel"
|
|
918
990
|
}, undefined, false, undefined, this)
|
|
919
991
|
]
|
|
992
|
+
}, undefined, true, undefined, this) : editingTimeout ? /* @__PURE__ */ jsxDEV(Box, {
|
|
993
|
+
flexDirection: "column",
|
|
994
|
+
children: [
|
|
995
|
+
/* @__PURE__ */ jsxDEV(Text, {
|
|
996
|
+
children: [
|
|
997
|
+
"Enter timeout in milliseconds (default 1000): ",
|
|
998
|
+
timeoutInput
|
|
999
|
+
]
|
|
1000
|
+
}, undefined, true, undefined, this),
|
|
1001
|
+
/* @__PURE__ */ jsxDEV(Text, {
|
|
1002
|
+
dimColor: true,
|
|
1003
|
+
children: "Press Enter to save, ESC to cancel"
|
|
1004
|
+
}, undefined, false, undefined, this)
|
|
1005
|
+
]
|
|
920
1006
|
}, undefined, true, undefined, this) : moveMode ? /* @__PURE__ */ jsxDEV(Text, {
|
|
921
1007
|
dimColor: true,
|
|
922
1008
|
children: "↑↓ to move item, ESC or Enter to exit move mode"
|
|
@@ -977,6 +1063,40 @@ var ItemsEditor = ({ items, onUpdate, onBack, lineNumber }) => {
|
|
|
977
1063
|
var ColorMenu = ({ items, onUpdate, onBack }) => {
|
|
978
1064
|
const colorableItems = items.filter((item) => ["model", "git-branch", "git-changes", "tokens-input", "tokens-output", "tokens-cached", "tokens-total", "context-length", "context-percentage", "session-clock", "terminal-width", "version", "custom-text", "custom-command"].includes(item.type) && !(item.type === "custom-command" && item.preserveColors));
|
|
979
1065
|
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
1066
|
+
const getDefaultColor = (type) => {
|
|
1067
|
+
switch (type) {
|
|
1068
|
+
case "model":
|
|
1069
|
+
return "cyan";
|
|
1070
|
+
case "git-branch":
|
|
1071
|
+
return "magenta";
|
|
1072
|
+
case "git-changes":
|
|
1073
|
+
return "yellow";
|
|
1074
|
+
case "session-clock":
|
|
1075
|
+
return "yellow";
|
|
1076
|
+
case "version":
|
|
1077
|
+
return "green";
|
|
1078
|
+
case "tokens-input":
|
|
1079
|
+
return "blue";
|
|
1080
|
+
case "tokens-output":
|
|
1081
|
+
return "white";
|
|
1082
|
+
case "tokens-cached":
|
|
1083
|
+
return "cyan";
|
|
1084
|
+
case "tokens-total":
|
|
1085
|
+
return "cyan";
|
|
1086
|
+
case "context-length":
|
|
1087
|
+
return "dim";
|
|
1088
|
+
case "context-percentage":
|
|
1089
|
+
return "blue";
|
|
1090
|
+
case "terminal-width":
|
|
1091
|
+
return "gray";
|
|
1092
|
+
case "custom-text":
|
|
1093
|
+
return "white";
|
|
1094
|
+
case "custom-command":
|
|
1095
|
+
return "white";
|
|
1096
|
+
default:
|
|
1097
|
+
return "white";
|
|
1098
|
+
}
|
|
1099
|
+
};
|
|
980
1100
|
useInput((input, key) => {
|
|
981
1101
|
if (key.escape) {
|
|
982
1102
|
onBack();
|
|
@@ -1044,14 +1164,17 @@ var ColorMenu = ({ items, onUpdate, onBack }) => {
|
|
|
1044
1164
|
return "Version";
|
|
1045
1165
|
case "custom-text":
|
|
1046
1166
|
return `Custom Text (${item.customText || "Empty"})`;
|
|
1047
|
-
case "custom-command":
|
|
1048
|
-
|
|
1167
|
+
case "custom-command": {
|
|
1168
|
+
const cmd = item.commandPath ? item.commandPath.substring(0, 20) + (item.commandPath.length > 20 ? "..." : "") : "No command";
|
|
1169
|
+
const timeout = item.timeout ? ` ${item.timeout}ms` : "";
|
|
1170
|
+
return `Custom Command (${cmd}${timeout})`;
|
|
1171
|
+
}
|
|
1049
1172
|
default:
|
|
1050
1173
|
return item.type;
|
|
1051
1174
|
}
|
|
1052
1175
|
};
|
|
1053
1176
|
const menuItems = colorableItems.map((item, index) => {
|
|
1054
|
-
const color = item.color ||
|
|
1177
|
+
const color = item.color || getDefaultColor(item.type);
|
|
1055
1178
|
const colorFunc = chalk[color] || chalk.white;
|
|
1056
1179
|
return {
|
|
1057
1180
|
label: colorFunc(`${getItemLabel(item)} #${index + 1}`),
|
|
@@ -1101,7 +1224,7 @@ var ColorMenu = ({ items, onUpdate, onBack }) => {
|
|
|
1101
1224
|
"whiteBright"
|
|
1102
1225
|
];
|
|
1103
1226
|
const selectedItem = selectedIndex < colorableItems.length ? colorableItems[selectedIndex] : null;
|
|
1104
|
-
const currentColor = selectedItem ? selectedItem.color ||
|
|
1227
|
+
const currentColor = selectedItem ? selectedItem.color || getDefaultColor(selectedItem.type) : "white";
|
|
1105
1228
|
const colorIndex = colors.indexOf(currentColor);
|
|
1106
1229
|
const colorNumber = colorIndex === -1 ? 8 : colorIndex + 1;
|
|
1107
1230
|
const colorDisplay = chalk[currentColor] ? chalk[currentColor](currentColor) : chalk.white(currentColor);
|
|
@@ -1856,10 +1979,12 @@ function renderSingleLine2(items, settings, data, tokenMetrics, sessionDuration)
|
|
|
1856
1979
|
case "custom-command":
|
|
1857
1980
|
if (item.commandPath) {
|
|
1858
1981
|
try {
|
|
1982
|
+
const timeout = item.timeout || 1000;
|
|
1859
1983
|
const output = execSync2(item.commandPath, {
|
|
1860
1984
|
encoding: "utf8",
|
|
1985
|
+
input: JSON.stringify(data),
|
|
1861
1986
|
stdio: ["pipe", "pipe", "ignore"],
|
|
1862
|
-
timeout
|
|
1987
|
+
timeout
|
|
1863
1988
|
}).trim();
|
|
1864
1989
|
if (output) {
|
|
1865
1990
|
let finalOutput = output;
|