cc-pulse 1.4.0 → 1.5.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/README.md +88 -50
- package/dist/cli.js +40 -21
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,7 +5,13 @@
|
|
|
5
5
|
|
|
6
6
|
A real-time statusline for [Claude Code](https://docs.anthropic.com/en/docs/claude-code).
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
**Full mode** shows names, groups, and token breakdown:
|
|
9
|
+
|
|
10
|
+

|
|
11
|
+
|
|
12
|
+
**Compact mode** shows counts only:
|
|
13
|
+
|
|
14
|
+

|
|
9
15
|
|
|
10
16
|
## Quick Start
|
|
11
17
|
|
|
@@ -24,68 +30,63 @@ Add to `~/.claude/settings.json`:
|
|
|
24
30
|
}
|
|
25
31
|
```
|
|
26
32
|
|
|
27
|
-
Restart Claude Code
|
|
33
|
+
Restart Claude Code and the statusline appears below the input area.
|
|
28
34
|
|
|
29
35
|
## Features
|
|
30
36
|
|
|
31
37
|
| Feature | Description |
|
|
32
38
|
|---------|-------------|
|
|
33
|
-
| **Context usage** |
|
|
39
|
+
| **Context usage** | Percentage used, colour shifts from green to red as you approach limits |
|
|
34
40
|
| **Token breakdown** | Input, output, and cache tokens at a glance |
|
|
35
|
-
| **Model info** |
|
|
36
|
-
| **Cost tracking** | Session cost with
|
|
41
|
+
| **Model info** | Model family and version, e.g. "Opus 4.6" |
|
|
42
|
+
| **Cost tracking** | Session cost with colour coding |
|
|
37
43
|
| **MCP health** | Live connection status for all MCP servers |
|
|
38
|
-
| **Hook monitoring** | Active hooks by event type
|
|
39
|
-
| **Skills display** |
|
|
40
|
-
| **Git status** | Branch name
|
|
41
|
-
| **Responsive layout** | Width-aware wrapping
|
|
44
|
+
| **Hook monitoring** | Active hooks by event type with broken path detection |
|
|
45
|
+
| **Skills display** | Adapts automatically: individual names, prefix grouping, or counts only |
|
|
46
|
+
| **Git status** | Branch name and file change counts |
|
|
47
|
+
| **Responsive layout** | Width-aware wrapping and a compact mode for smaller screens |
|
|
42
48
|
|
|
43
49
|
## What You Get
|
|
44
50
|
|
|
45
|
-
Six lines of information, updated on every message:
|
|
46
|
-
|
|
47
51
|
| Line | Content |
|
|
48
52
|
|------|---------|
|
|
49
|
-
| **Identity** | Project name
|
|
50
|
-
| **Git** | Branch
|
|
51
|
-
| **Engine** | Model, context
|
|
52
|
-
| **MCP** | Server count
|
|
53
|
-
| **Hooks** | Hook count by event type
|
|
54
|
-
| **Skills** |
|
|
53
|
+
| **Identity** | Project name and working directory |
|
|
54
|
+
| **Git** | Branch and file changes (new, modified, deleted) |
|
|
55
|
+
| **Engine** | Model, context usage, tokens, cost, session duration |
|
|
56
|
+
| **MCP** | Server count and individual status |
|
|
57
|
+
| **Hooks** | Hook count by event type with broken path warnings |
|
|
58
|
+
| **Skills** | Names when few, prefix groups when many |
|
|
55
59
|
|
|
56
60
|
## Responsive Display
|
|
57
61
|
|
|
58
|
-
The statusline adapts to your setup automatically
|
|
62
|
+
The statusline adapts to your setup automatically.
|
|
59
63
|
|
|
60
|
-
**Skills**
|
|
61
|
-
-
|
|
62
|
-
-
|
|
63
|
-
-
|
|
64
|
+
**Skills** adapt based on count:
|
|
65
|
+
- 10 or fewer: lists all names, e.g. `✦ Skills 5 beads excalidraw mermaid tmux repomix`
|
|
66
|
+
- More than 10 with shared prefixes: groups them, e.g. `✦ Skills 89 bmad:77 beads excalidraw ...`
|
|
67
|
+
- More than 10 without groups: caps at 10 names with overflow, e.g. `✦ Skills 15 a b c ... +5`
|
|
64
68
|
|
|
65
|
-
**Hooks**
|
|
66
|
-
-
|
|
67
|
-
-
|
|
69
|
+
**Hooks** adapt based on total count:
|
|
70
|
+
- 6 or fewer: shows all names per event, e.g. `⚡Hooks 4 Submit:2 lint,format Post:2 test,deploy`
|
|
71
|
+
- More than 6: caps names to 3 per group, e.g. `⚡Hooks 12 Submit:5 lint,format,check +2`
|
|
68
72
|
|
|
69
|
-
**Width-aware wrapping**
|
|
73
|
+
**Width-aware wrapping** breaks long lines at component boundaries instead of cutting them off. Items wrap at 5 per line for readability.
|
|
70
74
|
|
|
71
|
-
**Compact mode**
|
|
75
|
+
**Compact mode** collapses everything to counts only. Toggle with `/pulse-compact` or set in config:
|
|
72
76
|
```json
|
|
73
77
|
{
|
|
74
78
|
"compact": true
|
|
75
79
|
}
|
|
76
80
|
```
|
|
77
81
|
|
|
78
|
-
In compact mode, everything collapses to counts only:
|
|
79
|
-
- `⬢ MCP 3/4` | `⚡Hooks 8` | `✦ Skills 89` | `Used 30%` | `$2.50`
|
|
80
|
-
|
|
81
82
|
## Configuration
|
|
82
83
|
|
|
83
|
-
Create `~/.config/claude-pulse/config.json` to
|
|
84
|
+
Create `~/.config/claude-pulse/config.json` to customise. Only include what you want to change.
|
|
84
85
|
|
|
85
86
|
<details>
|
|
86
87
|
<summary><strong>Compact Mode</strong></summary>
|
|
87
88
|
|
|
88
|
-
Minimal display
|
|
89
|
+
Minimal display with counts and essential info only. Toggle with `/pulse-compact` or set manually:
|
|
89
90
|
|
|
90
91
|
```json
|
|
91
92
|
{
|
|
@@ -93,14 +94,14 @@ Minimal display showing only counts and essential info. Toggle with the `/pulse-
|
|
|
93
94
|
}
|
|
94
95
|
```
|
|
95
96
|
|
|
96
|
-
|
|
97
|
+
Skills, hooks, and MCP show counts only. Context hides the token breakdown. Cost hides burn rate. CWD shortens.
|
|
97
98
|
|
|
98
99
|
</details>
|
|
99
100
|
|
|
100
101
|
<details>
|
|
101
102
|
<summary><strong>Context Window</strong></summary>
|
|
102
103
|
|
|
103
|
-
Shows how much of the context window is used.
|
|
104
|
+
Shows how much of the context window is used. Colours shift as usage increases.
|
|
104
105
|
|
|
105
106
|
```json
|
|
106
107
|
{
|
|
@@ -121,11 +122,7 @@ Shows how much of the context window is used. Colors shift as usage increases.
|
|
|
121
122
|
| `detailed` | `Used 116.0k/200.0k (58%)` |
|
|
122
123
|
| `both` | `●●●●●●○○○○ 116.0k / 200.0k` |
|
|
123
124
|
|
|
124
|
-
|
|
125
|
-
- **Green**: < 70% used (safe)
|
|
126
|
-
- **Yellow**: 70% used (warn)
|
|
127
|
-
- **Orange**: 85% used (critical)
|
|
128
|
-
- **Red**: 95% used (danger)
|
|
125
|
+
Colour thresholds: green below 70%, yellow at 70%, orange at 85%, red at 95%.
|
|
129
126
|
|
|
130
127
|
</details>
|
|
131
128
|
|
|
@@ -146,14 +143,14 @@ Shows how much of the context window is used. Colors shift as usage increases.
|
|
|
146
143
|
|
|
147
144
|
| Option | Effect |
|
|
148
145
|
|--------|--------|
|
|
149
|
-
| `showNames: true` | List each server with status |
|
|
150
|
-
| `showOnlyProblems: true` | Hide line when all servers healthy |
|
|
151
|
-
| `maxDisplay: 4` | Limit servers shown
|
|
146
|
+
| `showNames: true` | List each server with its status |
|
|
147
|
+
| `showOnlyProblems: true` | Hide the line when all servers are healthy |
|
|
148
|
+
| `maxDisplay: 4` | Limit servers shown, with "+N more" for the rest |
|
|
152
149
|
|
|
153
150
|
| Icon | Status |
|
|
154
151
|
|------|--------|
|
|
155
152
|
| ✓ | Connected |
|
|
156
|
-
| ✗ | Disconnected
|
|
153
|
+
| ✗ | Disconnected |
|
|
157
154
|
| ○ | Disabled |
|
|
158
155
|
| ▲ | Error |
|
|
159
156
|
|
|
@@ -179,7 +176,7 @@ Shows how much of the context window is used. Colors shift as usage increases.
|
|
|
179
176
|
| `showNames: false` | `⚡Hooks 8 Submit:3 Post:2 End:1` |
|
|
180
177
|
| Both `false` | `⚡Hooks 8` |
|
|
181
178
|
|
|
182
|
-
|
|
179
|
+
With more than 6 hooks, names are capped to 3 per event group with a `+N` overflow count.
|
|
183
180
|
|
|
184
181
|
Broken hooks (invalid paths) show in red with ▲.
|
|
185
182
|
|
|
@@ -199,7 +196,7 @@ Broken hooks (invalid paths) show in red with ▲.
|
|
|
199
196
|
}
|
|
200
197
|
```
|
|
201
198
|
|
|
202
|
-
|
|
199
|
+
Colour thresholds: green below $1, yellow $1 to $2, orange $2 to $5, red above $5.
|
|
203
200
|
|
|
204
201
|
</details>
|
|
205
202
|
|
|
@@ -220,16 +217,44 @@ Shows your custom slash commands from `~/.claude/skills/` and `.claude/skills/`.
|
|
|
220
217
|
}
|
|
221
218
|
```
|
|
222
219
|
|
|
223
|
-
The display adapts automatically based on how many skills you have
|
|
220
|
+
The display adapts automatically based on how many skills you have. See [Responsive Display](#responsive-display) above.
|
|
224
221
|
|
|
225
222
|
Broken skills (missing SKILL.md or invalid frontmatter) show in red with ▲.
|
|
226
223
|
|
|
227
224
|
</details>
|
|
228
225
|
|
|
226
|
+
<details>
|
|
227
|
+
<summary><strong>CWD (Working Directory)</strong></summary>
|
|
228
|
+
|
|
229
|
+
Control how the current directory is displayed:
|
|
230
|
+
|
|
231
|
+
```json
|
|
232
|
+
{
|
|
233
|
+
"components": {
|
|
234
|
+
"cwd": {
|
|
235
|
+
"style": "short",
|
|
236
|
+
"maxLength": 30,
|
|
237
|
+
"showIcon": true
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
| Style | Example |
|
|
244
|
+
|-------|---------|
|
|
245
|
+
| `short` (default) | `~/…/fix-1612` |
|
|
246
|
+
| `full` | `/home/user/.worktree/my-project/2026-02-13/fix-1612` |
|
|
247
|
+
| `basename` | `fix-1612` |
|
|
248
|
+
| `project` | Project folder name |
|
|
249
|
+
|
|
250
|
+
Increase `maxLength` to show more of the path, or use `basename` if you only care about the folder name.
|
|
251
|
+
|
|
252
|
+
</details>
|
|
253
|
+
|
|
229
254
|
<details>
|
|
230
255
|
<summary><strong>Dividers</strong></summary>
|
|
231
256
|
|
|
232
|
-
Add horizontal line separators between status sections:
|
|
257
|
+
Add horizontal line separators between all status sections:
|
|
233
258
|
|
|
234
259
|
```json
|
|
235
260
|
{
|
|
@@ -241,6 +266,19 @@ Off by default.
|
|
|
241
266
|
|
|
242
267
|
</details>
|
|
243
268
|
|
|
269
|
+
<details>
|
|
270
|
+
<summary><strong>Section Separators</strong></summary>
|
|
271
|
+
|
|
272
|
+
Add light `---` separators after MCP, hooks, and skills sections. On by default in full mode, hidden in compact mode.
|
|
273
|
+
|
|
274
|
+
```json
|
|
275
|
+
{
|
|
276
|
+
"sectionSeparators": false
|
|
277
|
+
}
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
</details>
|
|
281
|
+
|
|
244
282
|
<details>
|
|
245
283
|
<summary><strong>Layout</strong></summary>
|
|
246
284
|
|
|
@@ -257,7 +295,7 @@ The 6-line structure is fixed. You can toggle lines and change separators:
|
|
|
257
295
|
|
|
258
296
|
| Line | Key | Toggleable |
|
|
259
297
|
|------|-----|------------|
|
|
260
|
-
| Identity |
|
|
298
|
+
| Identity | n/a | No |
|
|
261
299
|
| Git | `git` | Yes |
|
|
262
300
|
| Engine | `engine` | Yes |
|
|
263
301
|
| MCP | `mcp` | Yes |
|
|
@@ -289,7 +327,7 @@ cc-pulse ships with a skill you can install to your Claude Code skills directory
|
|
|
289
327
|
|---------|-------------|
|
|
290
328
|
| `/pulse-compact` | Toggle compact mode on/off |
|
|
291
329
|
|
|
292
|
-
|
|
330
|
+
Copy `skills/pulse-compact/` to `~/.claude/skills/` or your project's `.claude/skills/`.
|
|
293
331
|
|
|
294
332
|
## Development
|
|
295
333
|
|
|
@@ -301,7 +339,7 @@ bun run build
|
|
|
301
339
|
bun test
|
|
302
340
|
```
|
|
303
341
|
|
|
304
|
-
|
|
342
|
+
For local testing, use the full path in settings: `"command": "node /path/to/claude-pulse/dist/cli.js"`
|
|
305
343
|
|
|
306
344
|
## License
|
|
307
345
|
|
package/dist/cli.js
CHANGED
|
@@ -16,7 +16,7 @@ var __export = (target, all) => {
|
|
|
16
16
|
// package.json
|
|
17
17
|
var package_default = {
|
|
18
18
|
name: "cc-pulse",
|
|
19
|
-
version: "1.
|
|
19
|
+
version: "1.5.0",
|
|
20
20
|
description: "A customizable, real-time statusline for Claude Code",
|
|
21
21
|
type: "module",
|
|
22
22
|
bin: {
|
|
@@ -458,22 +458,25 @@ function renderHooks(config, theme) {
|
|
|
458
458
|
const header = `${theme.yellow}⚡${hookLabel} ${summary.total}${theme.reset}`;
|
|
459
459
|
const MAX_NAMES_PER_GROUP = 3;
|
|
460
460
|
const compact = summary.total > 6;
|
|
461
|
-
const items =
|
|
461
|
+
const items = [];
|
|
462
|
+
for (const [event, detail] of Object.entries(summary.events)) {
|
|
462
463
|
const label = EVENT_LABELS[event] ?? event;
|
|
463
|
-
const brokenStr = detail.broken.length > 0 ? ` ${theme.red}${detail.broken.join(",")} ▲${theme.reset}` : "";
|
|
464
464
|
const countStr = showCount ? `${theme.peach}${detail.count}${theme.reset}` : "";
|
|
465
|
-
|
|
465
|
+
const eventTag = `${theme.lavender}${label}:${theme.reset}${countStr}`;
|
|
466
466
|
if (showNames && detail.names.length > 0) {
|
|
467
467
|
const cap = compact ? MAX_NAMES_PER_GROUP : detail.names.length;
|
|
468
468
|
const displayed = detail.names.slice(0, cap);
|
|
469
469
|
const overflow = detail.names.length - cap;
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
470
|
+
const nameStr = `${theme.flamingo}${displayed.join(",")}${theme.reset}`;
|
|
471
|
+
const overflowStr = overflow > 0 ? ` ${theme.overlay0}+${overflow}${theme.reset}` : "";
|
|
472
|
+
items.push(`${eventTag} ${nameStr}${overflowStr}`);
|
|
473
|
+
} else {
|
|
474
|
+
items.push(eventTag);
|
|
474
475
|
}
|
|
475
|
-
|
|
476
|
-
|
|
476
|
+
if (detail.broken.length > 0) {
|
|
477
|
+
items.push(`${theme.red}${detail.broken.join(",")} ▲${theme.reset}`);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
477
480
|
const text = items.length > 0 ? `${header} ${items.join(" ")}` : header;
|
|
478
481
|
return { text, header, items };
|
|
479
482
|
}
|
|
@@ -495,9 +498,11 @@ function extractHookInfo(command) {
|
|
|
495
498
|
const parts = command.split(/\s+/);
|
|
496
499
|
for (const part of parts) {
|
|
497
500
|
if (part.includes("/")) {
|
|
498
|
-
const
|
|
501
|
+
const cleaned = part.replace(/^["']|["']$/g, "");
|
|
502
|
+
const expanded = cleaned.replace(/\$(\w+)/g, (_, v) => process.env[v] ?? `$${v}`);
|
|
503
|
+
const base = expanded.split("/").pop() ?? expanded;
|
|
499
504
|
const name2 = base.replace(/\.[^.]+$/, "");
|
|
500
|
-
const broken = !existsSync2(
|
|
505
|
+
const broken = !existsSync2(expanded);
|
|
501
506
|
return { name: name2, broken };
|
|
502
507
|
}
|
|
503
508
|
}
|
|
@@ -894,19 +899,23 @@ function renderSkills(config, theme) {
|
|
|
894
899
|
for (const [prefix, names] of Object.entries(groups).sort((a, b) => b[1].length - a[1].length)) {
|
|
895
900
|
items.push(`${theme.overlay1}${prefix}:${theme.peach}${names.length}${theme.reset}`);
|
|
896
901
|
}
|
|
897
|
-
|
|
898
|
-
items.push(`${theme.flamingo}${
|
|
902
|
+
for (const name of ungrouped) {
|
|
903
|
+
items.push(`${theme.flamingo}${name}${theme.reset}`);
|
|
899
904
|
}
|
|
900
905
|
} else {
|
|
901
906
|
const CAP = 10;
|
|
902
907
|
const capped = validNames.slice(0, CAP);
|
|
903
|
-
|
|
908
|
+
for (const name of capped) {
|
|
909
|
+
items.push(`${theme.flamingo}${name}${theme.reset}`);
|
|
910
|
+
}
|
|
904
911
|
if (validNames.length > CAP) {
|
|
905
912
|
items.push(`${theme.overlay0}+${validNames.length - CAP}${theme.reset}`);
|
|
906
913
|
}
|
|
907
914
|
}
|
|
908
915
|
} else {
|
|
909
|
-
|
|
916
|
+
for (const name of validNames) {
|
|
917
|
+
items.push(`${theme.flamingo}${name}${theme.reset}`);
|
|
918
|
+
}
|
|
910
919
|
}
|
|
911
920
|
const overflow = summary.valid > maxDisplay ? summary.valid - maxDisplay : 0;
|
|
912
921
|
if (overflow > 0) {
|
|
@@ -1228,6 +1237,8 @@ function mergeConfig(target, source) {
|
|
|
1228
1237
|
result.compact = source.compact;
|
|
1229
1238
|
if (source.dividers !== undefined)
|
|
1230
1239
|
result.dividers = source.dividers;
|
|
1240
|
+
if (source.sectionSeparators !== undefined)
|
|
1241
|
+
result.sectionSeparators = source.sectionSeparators;
|
|
1231
1242
|
if (source.lines !== undefined)
|
|
1232
1243
|
result.lines = source.lines;
|
|
1233
1244
|
if (source.interactive !== undefined)
|
|
@@ -14973,6 +14984,7 @@ var PulseConfigSchema = exports_external.object({
|
|
|
14973
14984
|
theme: exports_external.string(),
|
|
14974
14985
|
compact: exports_external.boolean().optional(),
|
|
14975
14986
|
dividers: exports_external.boolean().optional(),
|
|
14987
|
+
sectionSeparators: exports_external.boolean().optional(),
|
|
14976
14988
|
lines: LinesConfigSchema.optional(),
|
|
14977
14989
|
components: ComponentConfigsSchema,
|
|
14978
14990
|
interactive: exports_external.object({
|
|
@@ -15030,7 +15042,7 @@ var ANSI_RE = /\x1b\[[0-9;]*[A-Za-z]/g;
|
|
|
15030
15042
|
function visibleLength(str) {
|
|
15031
15043
|
return str.replace(ANSI_RE, "").length;
|
|
15032
15044
|
}
|
|
15033
|
-
function wrapParts(parts, separator, maxWidth, indent = 2) {
|
|
15045
|
+
function wrapParts(parts, separator, maxWidth, indent = 2, maxPerLine = 0) {
|
|
15034
15046
|
if (parts.length === 0)
|
|
15035
15047
|
return "";
|
|
15036
15048
|
const sepWidth = visibleLength(separator);
|
|
@@ -15038,16 +15050,20 @@ function wrapParts(parts, separator, maxWidth, indent = 2) {
|
|
|
15038
15050
|
const lines = [];
|
|
15039
15051
|
let currentLine = parts[0];
|
|
15040
15052
|
let currentWidth = visibleLength(parts[0]);
|
|
15053
|
+
let partsOnLine = 1;
|
|
15041
15054
|
for (let i = 1;i < parts.length; i++) {
|
|
15042
15055
|
const partWidth = visibleLength(parts[i]);
|
|
15043
15056
|
const wouldBe = currentWidth + sepWidth + partWidth;
|
|
15044
|
-
|
|
15057
|
+
const hitMax = maxPerLine > 0 && partsOnLine >= maxPerLine;
|
|
15058
|
+
if (wouldBe > maxWidth || hitMax) {
|
|
15045
15059
|
lines.push(currentLine);
|
|
15046
15060
|
currentLine = pad + parts[i];
|
|
15047
15061
|
currentWidth = indent + partWidth;
|
|
15062
|
+
partsOnLine = 1;
|
|
15048
15063
|
} else {
|
|
15049
15064
|
currentLine += separator + parts[i];
|
|
15050
15065
|
currentWidth = wouldBe;
|
|
15066
|
+
partsOnLine++;
|
|
15051
15067
|
}
|
|
15052
15068
|
}
|
|
15053
15069
|
lines.push(currentLine);
|
|
@@ -15137,18 +15153,21 @@ Configuration:
|
|
|
15137
15153
|
continue;
|
|
15138
15154
|
if (outputs.length === 1 && outputs[0].header && outputs[0].items?.length) {
|
|
15139
15155
|
const { header, items } = outputs[0];
|
|
15140
|
-
const rendered = wrapParts([header, ...items], " ", termWidth);
|
|
15156
|
+
const rendered = wrapParts([header, ...items], " ", termWidth, 2, 4);
|
|
15141
15157
|
outputLines.push(rendered);
|
|
15142
15158
|
} else {
|
|
15143
15159
|
const parts = outputs.map((o) => o.text);
|
|
15144
15160
|
outputLines.push(wrapParts(parts, sep, termWidth));
|
|
15145
15161
|
}
|
|
15162
|
+
if (!config2.compact && config2.sectionSeparators !== false && (line.name === "mcp" || line.name === "hooks" || line.name === "skills")) {
|
|
15163
|
+
outputLines.push(`${theme.overlay0}---${theme.reset}`);
|
|
15164
|
+
}
|
|
15146
15165
|
}
|
|
15147
15166
|
if (config2.dividers) {
|
|
15148
15167
|
const divider = `${theme.overlay0}${"─".repeat(termWidth)}${theme.reset}`;
|
|
15149
|
-
console.log(outputLines.join(`
|
|
15168
|
+
console.log(`${outputLines.join(`
|
|
15150
15169
|
${divider}
|
|
15151
|
-
`)
|
|
15170
|
+
`)}
|
|
15152
15171
|
${divider}`);
|
|
15153
15172
|
} else {
|
|
15154
15173
|
console.log(outputLines.join(`
|