cc-context-stats 1.12.1 → 1.13.1
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 +11 -1
- package/package.json +1 -1
- package/scripts/statusline.js +267 -27
package/README.md
CHANGED
|
@@ -91,7 +91,7 @@ graph LR
|
|
|
91
91
|
|
|
92
92
|
## Customization
|
|
93
93
|
|
|
94
|
-
Every element in the status line can be individually colored and toggled. Configuration lives in `~/.claude/statusline.conf` (created automatically on first run).
|
|
94
|
+
Every element in the status line can be individually colored and toggled. Configuration lives in `~/.claude/statusline.conf` (created automatically on first run). See [`examples/statusline.conf`](examples/statusline.conf) for the canonical reference with all parameters documented.
|
|
95
95
|
|
|
96
96
|
### Status Line Anatomy
|
|
97
97
|
|
|
@@ -334,6 +334,16 @@ Add to `~/.claude/settings.json`:
|
|
|
334
334
|
}
|
|
335
335
|
```
|
|
336
336
|
|
|
337
|
+
**(Optional) Copy the example config for full customization:**
|
|
338
|
+
|
|
339
|
+
A default config is created automatically on first run. To start from the fully-documented example instead, copy it before launching:
|
|
340
|
+
|
|
341
|
+
```bash
|
|
342
|
+
cp examples/statusline.conf ~/.claude/statusline.conf
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
See [`examples/statusline.conf`](examples/statusline.conf) for all available settings with detailed explanations.
|
|
346
|
+
|
|
337
347
|
Restart Claude Code. MI score and context stats appear in your status bar immediately.
|
|
338
348
|
|
|
339
349
|
### Real-Time Dashboard
|
package/package.json
CHANGED
package/scripts/statusline.js
CHANGED
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
* Configuration:
|
|
7
7
|
* Create/edit ~/.claude/statusline.conf and set:
|
|
8
8
|
*
|
|
9
|
-
* autocompact=
|
|
10
|
-
* autocompact=
|
|
9
|
+
* autocompact=false (when autocompact is disabled in Claude Code - default)
|
|
10
|
+
* autocompact=true (when you enable autocompact via /config in Claude Code)
|
|
11
11
|
*
|
|
12
12
|
* token_detail=true (show exact token count like 64,000 - default)
|
|
13
13
|
* token_detail=false (show abbreviated tokens like 64.0k)
|
|
@@ -114,35 +114,49 @@ function getMIColor(mi, utilization, greenColor, yellowColor, redColor) {
|
|
|
114
114
|
/**
|
|
115
115
|
* Determine context zone indicator (P/C/D/X/Z) based on token usage.
|
|
116
116
|
* Returns { zone, colorName }.
|
|
117
|
+
* zoneConfig is an optional object of threshold overrides (0 = use default).
|
|
117
118
|
*/
|
|
118
|
-
function getContextZone(usedTokens, contextWindowSize) {
|
|
119
|
+
function getContextZone(usedTokens, contextWindowSize, zoneConfig) {
|
|
119
120
|
if (contextWindowSize === 0) {
|
|
120
121
|
return { zone: 'Plan', colorName: 'green' };
|
|
121
122
|
}
|
|
122
123
|
|
|
123
|
-
const
|
|
124
|
+
const zc = zoneConfig || {};
|
|
125
|
+
|
|
126
|
+
const lmt = zc.large_model_threshold || LARGE_MODEL_THRESHOLD;
|
|
127
|
+
const isLarge = contextWindowSize >= lmt;
|
|
124
128
|
|
|
125
129
|
if (isLarge) {
|
|
126
|
-
|
|
130
|
+
const pMax = zc.zone_1m_plan_max || ZONE_1M_P_MAX;
|
|
131
|
+
const cMax = zc.zone_1m_code_max || ZONE_1M_C_MAX;
|
|
132
|
+
const dMax = zc.zone_1m_dump_max || ZONE_1M_D_MAX;
|
|
133
|
+
const xMax = zc.zone_1m_xdump_max || ZONE_1M_X_MAX;
|
|
134
|
+
|
|
135
|
+
if (usedTokens < pMax) {
|
|
127
136
|
return { zone: 'Plan', colorName: 'green' };
|
|
128
137
|
}
|
|
129
|
-
if (usedTokens <
|
|
138
|
+
if (usedTokens < cMax) {
|
|
130
139
|
return { zone: 'Code', colorName: 'yellow' };
|
|
131
140
|
}
|
|
132
|
-
if (usedTokens <
|
|
141
|
+
if (usedTokens < dMax) {
|
|
133
142
|
return { zone: 'Dump', colorName: 'orange' };
|
|
134
143
|
}
|
|
135
|
-
if (usedTokens <
|
|
144
|
+
if (usedTokens < xMax) {
|
|
136
145
|
return { zone: 'ExDump', colorName: 'dark_red' };
|
|
137
146
|
}
|
|
138
147
|
return { zone: 'Dead', colorName: 'gray' };
|
|
139
148
|
}
|
|
140
149
|
|
|
141
|
-
// Standard models
|
|
142
|
-
const
|
|
143
|
-
const
|
|
144
|
-
const
|
|
145
|
-
const
|
|
150
|
+
// Standard models
|
|
151
|
+
const dumpRatio = zc.zone_std_dump_ratio || ZONE_STD_DUMP_ZONE;
|
|
152
|
+
const warnBuf = zc.zone_std_warn_buffer || ZONE_STD_WARN_BUFFER;
|
|
153
|
+
const hardLim = zc.zone_std_hard_limit || ZONE_STD_HARD_LIMIT;
|
|
154
|
+
const deadRat = zc.zone_std_dead_ratio || ZONE_STD_DEAD_ZONE;
|
|
155
|
+
|
|
156
|
+
const dumpZoneTokens = Math.floor(contextWindowSize * dumpRatio);
|
|
157
|
+
const warnStart = Math.max(0, dumpZoneTokens - warnBuf);
|
|
158
|
+
const hardLimitTokens = Math.floor(contextWindowSize * hardLim);
|
|
159
|
+
const deadZoneTokens = Math.floor(contextWindowSize * deadRat);
|
|
146
160
|
|
|
147
161
|
if (usedTokens < warnStart) {
|
|
148
162
|
return { zone: 'Plan', colorName: 'green' };
|
|
@@ -284,6 +298,23 @@ const COLOR_CONFIG_KEYS = {
|
|
|
284
298
|
color_separator: 'separator',
|
|
285
299
|
};
|
|
286
300
|
|
|
301
|
+
// Zone threshold config keys (integer token counts)
|
|
302
|
+
const ZONE_INT_KEYS = new Set([
|
|
303
|
+
'zone_1m_plan_max',
|
|
304
|
+
'zone_1m_code_max',
|
|
305
|
+
'zone_1m_dump_max',
|
|
306
|
+
'zone_1m_xdump_max',
|
|
307
|
+
'zone_std_warn_buffer',
|
|
308
|
+
'large_model_threshold',
|
|
309
|
+
]);
|
|
310
|
+
|
|
311
|
+
// Zone threshold config keys (float ratios 0-1)
|
|
312
|
+
const ZONE_FLOAT_KEYS = new Set([
|
|
313
|
+
'zone_std_dump_ratio',
|
|
314
|
+
'zone_std_hard_limit',
|
|
315
|
+
'zone_std_dead_ratio',
|
|
316
|
+
]);
|
|
317
|
+
|
|
287
318
|
/**
|
|
288
319
|
* Return the visible width of a string after stripping ANSI escape sequences.
|
|
289
320
|
*/
|
|
@@ -384,7 +415,7 @@ function getGitInfo(projectDir, magentaColor, cyanColor) {
|
|
|
384
415
|
|
|
385
416
|
function readConfig() {
|
|
386
417
|
const config = {
|
|
387
|
-
autocompact:
|
|
418
|
+
autocompact: false,
|
|
388
419
|
tokenDetail: true,
|
|
389
420
|
showDelta: true,
|
|
390
421
|
showSession: true,
|
|
@@ -393,6 +424,7 @@ function readConfig() {
|
|
|
393
424
|
showMI: false,
|
|
394
425
|
miCurveBeta: 0,
|
|
395
426
|
colors: {},
|
|
427
|
+
zoneConfig: {},
|
|
396
428
|
};
|
|
397
429
|
const configPath = path.join(os.homedir(), '.claude', 'statusline.conf');
|
|
398
430
|
|
|
@@ -403,29 +435,219 @@ function readConfig() {
|
|
|
403
435
|
if (!fs.existsSync(configDir)) {
|
|
404
436
|
fs.mkdirSync(configDir, { recursive: true });
|
|
405
437
|
}
|
|
406
|
-
const defaultConfig =
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
#
|
|
438
|
+
const defaultConfig = `\
|
|
439
|
+
# ============================================================================
|
|
440
|
+
# cc-context-stats — statusline configuration
|
|
441
|
+
# ============================================================================
|
|
442
|
+
#
|
|
443
|
+
# Copy this file to: ~/.claude/statusline.conf
|
|
444
|
+
# Windows: %USERPROFILE%\\.claude\\statusline.conf
|
|
445
|
+
#
|
|
446
|
+
# Full reference:
|
|
447
|
+
# https://github.com/luongnv89/cc-context-stats/blob/main/docs/configuration.md
|
|
448
|
+
#
|
|
449
|
+
# Format:
|
|
450
|
+
# - key=value (no spaces around '=')
|
|
451
|
+
# - Lines starting with '#' are comments
|
|
452
|
+
# - Unrecognized keys are silently ignored
|
|
453
|
+
# - Missing or invalid values fall back to built-in defaults
|
|
454
|
+
#
|
|
455
|
+
# ============================================================================
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
# ─── Display Settings ───────────────────────────────────────────────────────
|
|
459
|
+
#
|
|
460
|
+
# These boolean flags control which elements appear in the statusline.
|
|
461
|
+
# Any value other than "false" (case-insensitive) is treated as true.
|
|
462
|
+
|
|
463
|
+
# Autocompact buffer display.
|
|
464
|
+
# When true, 22.5% of the context window is reserved for Claude Code's
|
|
465
|
+
# autocompact feature. This affects the "free tokens" calculation.
|
|
466
|
+
# Must match your Claude Code setting — check with: /config
|
|
467
|
+
# true -> shows [AC:45k] buffer in statusline
|
|
468
|
+
# false -> shows [AC:off]
|
|
469
|
+
autocompact=false
|
|
470
|
+
|
|
471
|
+
# Token display format.
|
|
472
|
+
# true = exact count with commas (e.g., 64,000 free)
|
|
473
|
+
# false = abbreviated with suffix (e.g., 64.0k free)
|
|
474
|
+
# Also affects the delta display (+2,500 vs +2.5k).
|
|
410
475
|
token_detail=true
|
|
411
476
|
|
|
412
|
-
# Show token delta since last refresh (
|
|
413
|
-
#
|
|
477
|
+
# Show token delta since last refresh (e.g., +2,500).
|
|
478
|
+
# Displays how many tokens were consumed since the previous statusline update.
|
|
479
|
+
# Requires file I/O on every refresh to read the previous state.
|
|
480
|
+
# Disable if you want to reduce disk overhead.
|
|
414
481
|
show_delta=true
|
|
415
482
|
|
|
416
|
-
# Show
|
|
483
|
+
# Show the session ID at the end of the statusline.
|
|
484
|
+
# Useful when running multiple Claude Code instances to identify sessions.
|
|
485
|
+
# Double-click in terminal to select and copy.
|
|
417
486
|
show_session=true
|
|
418
487
|
|
|
419
|
-
#
|
|
420
|
-
#
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
#
|
|
488
|
+
# Show input/output token breakdown.
|
|
489
|
+
# Reserved for future use — currently read but not displayed.
|
|
490
|
+
show_io_tokens=true
|
|
491
|
+
|
|
492
|
+
# Disable rotating text and icon animations for accessibility.
|
|
493
|
+
# false = animations enabled (default)
|
|
494
|
+
# true = static display, no motion
|
|
495
|
+
reduced_motion=false
|
|
496
|
+
|
|
497
|
+
|
|
498
|
+
# ─── Model Intelligence (MI) ────────────────────────────────────────────────
|
|
499
|
+
#
|
|
500
|
+
# MI measures how effectively the model uses its context window. The score
|
|
501
|
+
# ranges from 0.000 (fully degraded) to 1.000 (optimal). As context fills,
|
|
502
|
+
# MI degrades following a model-specific curve.
|
|
503
|
+
|
|
504
|
+
# Show the MI score in the statusline (e.g., MI:0.918).
|
|
505
|
+
# When enabled, also requires state file I/O for tracking.
|
|
506
|
+
# false = MI score hidden (default)
|
|
507
|
+
# true = MI score visible
|
|
508
|
+
show_mi=false
|
|
509
|
+
|
|
510
|
+
# Override the MI degradation curve beta for all models.
|
|
511
|
+
# Each model has a built-in profile that controls how quickly MI degrades:
|
|
512
|
+
# opus = 1.8 (retains quality longest, steep drop near end)
|
|
513
|
+
# sonnet = 1.5 (moderate degradation)
|
|
514
|
+
# haiku = 1.2 (degrades earliest)
|
|
515
|
+
# Set to 0 to use the model-specific profile (recommended).
|
|
516
|
+
# Set a positive value (e.g., 1.5) to override for all models.
|
|
517
|
+
mi_curve_beta=0
|
|
518
|
+
|
|
519
|
+
|
|
520
|
+
# ─── Zone Threshold Overrides ───────────────────────────────────────────────
|
|
521
|
+
#
|
|
522
|
+
# Zones indicate how much context pressure your session is under:
|
|
523
|
+
# Plan (P) = plenty of room, ideal for planning and exploration
|
|
524
|
+
# Code (C) = normal coding zone, context is filling but healthy
|
|
525
|
+
# Dump (D) = getting full, consider wrapping up or starting fresh
|
|
526
|
+
# ExDump (X) = critical, autocompact may trigger, quality degrading
|
|
527
|
+
# Dead (Z) = context exhausted, start a new session
|
|
528
|
+
#
|
|
529
|
+
# There are two threshold sets: one for large models (1M+ context) using
|
|
530
|
+
# absolute token counts, and one for standard models using ratios (0-1).
|
|
531
|
+
#
|
|
532
|
+
# Uncomment and set a positive value to override the built-in defaults.
|
|
533
|
+
# Invalid values (negative, non-numeric, ratios outside 0-1) are ignored
|
|
534
|
+
# with a warning to stderr.
|
|
535
|
+
|
|
536
|
+
# Context windows >= this value use 1M-class thresholds (token count).
|
|
537
|
+
# Models below this threshold use the standard ratio-based zones.
|
|
538
|
+
# large_model_threshold=500000
|
|
539
|
+
|
|
540
|
+
# --- 1M-Class Models (context >= large_model_threshold) ---
|
|
541
|
+
# Values are absolute token counts for zone boundaries (tokens used).
|
|
542
|
+
# zone_1m_plan_max=70000 # Plan -> Code boundary
|
|
543
|
+
# zone_1m_code_max=100000 # Code -> Dump boundary
|
|
544
|
+
# zone_1m_dump_max=250000 # Dump -> ExDump boundary
|
|
545
|
+
# zone_1m_xdump_max=275000 # ExDump -> Dead boundary
|
|
546
|
+
|
|
547
|
+
# --- Standard Models (context < large_model_threshold) ---
|
|
548
|
+
# Ratios are 0-1 fractions of the total context window.
|
|
549
|
+
# zone_std_dump_ratio=0.40 # Dump zone starts at 40% utilization
|
|
550
|
+
# zone_std_warn_buffer=30000 # Show warning this many tokens before dump zone
|
|
551
|
+
# zone_std_hard_limit=0.70 # Hard limit at 70% utilization
|
|
552
|
+
# zone_std_dead_ratio=0.75 # Dead zone starts at 75% utilization
|
|
553
|
+
|
|
554
|
+
|
|
555
|
+
# ─── Base Color Slots ───────────────────────────────────────────────────────
|
|
556
|
+
#
|
|
557
|
+
# Override the 6 base palette colors used for MI-based traffic-light coloring
|
|
558
|
+
# and as fallbacks for per-property colors (see next section).
|
|
559
|
+
#
|
|
560
|
+
# Accepts named colors or hex codes (#rrggbb).
|
|
561
|
+
#
|
|
562
|
+
# Named colors (18 available):
|
|
563
|
+
# Standard: black, red, green, yellow, blue, magenta, cyan, white
|
|
564
|
+
# Bright: bright_black, bright_red, bright_green, bright_yellow,
|
|
565
|
+
# bright_blue, bright_magenta, bright_cyan, bright_white
|
|
566
|
+
# Special: bold_white, dim
|
|
567
|
+
#
|
|
568
|
+
# Hex colors: any #rrggbb value (requires 24-bit color terminal support)
|
|
569
|
+
#
|
|
570
|
+
# Unrecognized values are ignored with a warning to stderr.
|
|
571
|
+
|
|
572
|
+
# Traffic-light colors — used for MI score and context zone indicators.
|
|
573
|
+
# Colors are determined by BOTH MI score and context utilization:
|
|
574
|
+
# color_green -> MI >= 0.90 AND context < 40% (model operating well)
|
|
575
|
+
# color_yellow -> MI in (0.80, 0.90) OR context in [40%, 80%) (pressure building)
|
|
576
|
+
# color_red -> MI <= 0.80 OR context >= 80% (significant degradation)
|
|
577
|
+
color_green=#7dcfff
|
|
578
|
+
color_yellow=#e0af68
|
|
579
|
+
color_red=#f7768e
|
|
580
|
+
|
|
581
|
+
# Legacy element fallback colors:
|
|
582
|
+
# color_blue -> fallback for project name (if color_project_name not set)
|
|
583
|
+
# color_magenta -> fallback for branch name (if color_branch_name not set)
|
|
584
|
+
# color_cyan -> git change-count brackets (e.g., [3])
|
|
585
|
+
color_blue=#7aa2f7
|
|
586
|
+
color_magenta=#bb9af7
|
|
587
|
+
color_cyan=#2ac3de
|
|
588
|
+
|
|
589
|
+
|
|
590
|
+
# ─── Per-Property Colors ────────────────────────────────────────────────────
|
|
591
|
+
#
|
|
592
|
+
# Override individual statusline elements. These take precedence over
|
|
593
|
+
# base color slots above.
|
|
594
|
+
#
|
|
595
|
+
# Fallback chain: per-property key -> base color slot -> built-in default
|
|
596
|
+
#
|
|
597
|
+
# For example, if color_project_name is not set, it falls back to color_blue
|
|
598
|
+
# (if set), then to the built-in cyan.
|
|
599
|
+
|
|
600
|
+
# Context tokens remaining — the most critical info.
|
|
601
|
+
# When not set, uses zone traffic-light color (green/yellow/red) automatically.
|
|
602
|
+
# Set explicitly to use a fixed color regardless of zone.
|
|
603
|
+
# color_context_length=bold_white
|
|
604
|
+
|
|
605
|
+
# Project directory name (e.g., "my-project").
|
|
606
|
+
color_project_name=bright_cyan
|
|
607
|
+
|
|
608
|
+
# Git branch name (e.g., "main").
|
|
609
|
+
color_branch_name=bright_magenta
|
|
610
|
+
|
|
611
|
+
# MI score display (e.g., "MI:0.918").
|
|
612
|
+
# When not set, uses MI-based traffic-light color automatically.
|
|
613
|
+
color_mi_score=#ff9e64
|
|
614
|
+
|
|
615
|
+
# Zone indicator label (e.g., "Plan", "Code", "Dump").
|
|
616
|
+
# When not set, uses zone traffic-light color automatically.
|
|
617
|
+
# color_zone=bright_green
|
|
618
|
+
|
|
619
|
+
# Structural elements: model name, token delta, session ID.
|
|
620
|
+
# "dim" makes these visually recede so primary info stands out.
|
|
621
|
+
color_separator=dim
|
|
622
|
+
|
|
623
|
+
|
|
624
|
+
# ─── Statusline Layout Reference ────────────────────────────────────────────
|
|
625
|
+
#
|
|
626
|
+
# The statusline elements are displayed in this order (highest priority first):
|
|
627
|
+
#
|
|
628
|
+
# project_name | branch [changes] | tokens_free (%) | Zone | MI:score | +delta | Model | session_id
|
|
629
|
+
#
|
|
630
|
+
# Example output:
|
|
631
|
+
# my-project | main [3] | 64,000 free (32.0%) | Code | MI:0.918 | +2,500 | Opus 4.6 | abc-123
|
|
632
|
+
#
|
|
633
|
+
# If the terminal is too narrow, lower-priority elements are dropped:
|
|
634
|
+
# 1. session_id (dropped first)
|
|
635
|
+
# 2. model name
|
|
636
|
+
# 3. token delta
|
|
637
|
+
# 4. MI score
|
|
638
|
+
# 5. zone indicator
|
|
639
|
+
# 6. context info
|
|
640
|
+
# 7. git info
|
|
641
|
+
# 8. project name (always shown, never dropped)
|
|
424
642
|
`;
|
|
425
643
|
fs.writeFileSync(configPath, defaultConfig);
|
|
426
644
|
} catch (e) {
|
|
427
645
|
process.stderr.write(`[statusline] warning: failed to create config: ${e.message}\n`);
|
|
646
|
+
return config;
|
|
428
647
|
}
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
if (!fs.existsSync(configPath)) {
|
|
429
651
|
return config;
|
|
430
652
|
}
|
|
431
653
|
|
|
@@ -464,6 +686,24 @@ show_session=true
|
|
|
464
686
|
if (ansi) {
|
|
465
687
|
config.colors[COLOR_CONFIG_KEYS[keyTrimmed]] = ansi;
|
|
466
688
|
}
|
|
689
|
+
} else if (ZONE_INT_KEYS.has(keyTrimmed)) {
|
|
690
|
+
const v = parseInt(rawValue, 10);
|
|
691
|
+
if (!isNaN(v) && v > 0) {
|
|
692
|
+
config.zoneConfig[keyTrimmed] = v;
|
|
693
|
+
} else {
|
|
694
|
+
process.stderr.write(
|
|
695
|
+
`[statusline] warning: ${keyTrimmed} must be a positive integer, ignoring '${rawValue}'\n`
|
|
696
|
+
);
|
|
697
|
+
}
|
|
698
|
+
} else if (ZONE_FLOAT_KEYS.has(keyTrimmed)) {
|
|
699
|
+
const v = parseFloat(rawValue);
|
|
700
|
+
if (!isNaN(v) && v > 0 && v < 1) {
|
|
701
|
+
config.zoneConfig[keyTrimmed] = v;
|
|
702
|
+
} else {
|
|
703
|
+
process.stderr.write(
|
|
704
|
+
`[statusline] warning: ${keyTrimmed} must be between 0 and 1, ignoring '${rawValue}'\n`
|
|
705
|
+
);
|
|
706
|
+
}
|
|
467
707
|
}
|
|
468
708
|
}
|
|
469
709
|
} catch (e) {
|
|
@@ -572,7 +812,7 @@ process.stdin.on('end', () => {
|
|
|
572
812
|
: `${(freeTokens / 1000).toFixed(1)}k`;
|
|
573
813
|
|
|
574
814
|
// Zone indicator — determines color for both context info and zone label
|
|
575
|
-
const zoneResult = getContextZone(usedTokens, totalSize);
|
|
815
|
+
const zoneResult = getContextZone(usedTokens, totalSize, config.zoneConfig);
|
|
576
816
|
const zoneAnsi = zoneAnsiColor(zoneResult.colorName);
|
|
577
817
|
|
|
578
818
|
// Context info uses zone color (traffic-light), with per-property override
|