cc-context-stats 1.5.0 → 1.5.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.
@@ -111,7 +111,10 @@
111
111
  "Read(//Users/montimage/.claude/**)",
112
112
  "Bash(git checkout:*)",
113
113
  "Bash(npm publish:*)",
114
- "Bash(npm view:*)"
114
+ "Bash(npm view:*)",
115
+ "WebSearch",
116
+ "Bash(COLUMNS=120 python3 -c \"import shutil; print\\(shutil.get_terminal_size\\(\\).columns\\)\")",
117
+ "Bash(COLUMNS=80 python3 -c \"import shutil; print\\(shutil.get_terminal_size\\(\\).columns\\)\")"
115
118
  ]
116
119
  }
117
120
  }
@@ -69,7 +69,9 @@ jobs:
69
69
  run: sudo apt-get update && sudo apt-get install -y jq bats
70
70
 
71
71
  - name: Install Python dependencies
72
- run: pip install -r requirements-dev.txt
72
+ run: |
73
+ pip install -r requirements-dev.txt
74
+ pip install -e .
73
75
 
74
76
  - name: Install Node.js dependencies
75
77
  run: npm ci
package/RELEASE_NOTES.md CHANGED
@@ -1,9 +1,10 @@
1
- ## What's Changed
2
-
3
- ### Refactoring
4
- - **Remove icon and pacman display options from statusline** — Simplify the statusline by removing `icon_mode` config option (`standard`/`pacman`/`off`), activity icons, and pacman meter visualization. Activity tier detection and text labels are preserved for context-stats. Net removal of ~413 lines across 10 files (#13) @luongnv89
1
+ ## v1.5.1 — 2026-03-11
5
2
 
6
3
  ### Bug Fixes
7
- - **Eliminate watch mode flickering via double-buffered rendering** — Replace cursor-home + line-by-line overwrites with full-frame buffering that writes the entire screen in a single `sys.stdout.write()` call, eliminating visible flicker during watch mode refreshes
4
+ - **Fix session ID disappearing from statusline** — Claude Code runs statusline scripts as piped subprocesses with no real TTY, causing terminal width detection to always return 80 columns. This made `fit_to_width()` drop lower-priority parts like session ID even when the real terminal had plenty of space. Now uses 200 columns as default when no TTY is detected; Claude Code's own UI handles overflow.
5
+ - **Fix CI failures** — Resolve ESLint, Python 3.9 compatibility, and release workflow issues
6
+
7
+ ### Other Changes
8
+ - Update logo SVG assets
8
9
 
9
- **Full Changelog**: https://github.com/luongnv89/cc-context-stats/compare/v1.4.0...v1.5.0
10
+ **Full Changelog**: https://github.com/luongnv89/cc-context-stats/compare/v1.5.0...v1.5.1
@@ -1,16 +1,19 @@
1
1
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
2
- <!-- Favicon — ultra-minimal gauge -->
3
- <rect width="16" height="16" rx="3" fill="#000000"/>
4
- <!-- Gauge arc -->
5
- <path d="M 2.5 12 A 6 6 0 1 1 13.5 12" stroke="#1a1a1a" stroke-width="1.8" fill="none" stroke-linecap="round"/>
6
- <!-- Green segment -->
7
- <path d="M 2.5 12 A 6 6 0 0 1 4.6 6.4" stroke="#22C55E" stroke-width="1.8" fill="none" stroke-linecap="round"/>
8
- <!-- Yellow segment -->
9
- <path d="M 4.6 6.4 A 6 6 0 0 1 11.4 6.4" stroke="#F59E0B" stroke-width="1.8" fill="none" stroke-linecap="round"/>
10
- <!-- Red segment -->
11
- <path d="M 11.4 6.4 A 6 6 0 0 1 13.5 12" stroke="#EF4444" stroke-width="1.8" fill="none" stroke-linecap="round"/>
12
- <!-- Needle -->
13
- <line x1="8" y1="8" x2="5.2" y2="5.2" stroke="#FFFFFF" stroke-width="1" stroke-linecap="round"/>
14
- <!-- Pivot -->
15
- <circle cx="8" cy="8" r="1" fill="#22C55E"/>
2
+ <defs>
3
+ <linearGradient id="fav-grad" x1="0%" y1="0%" x2="100%" y2="0%">
4
+ <stop offset="0%" stop-color="#22C55E"/>
5
+ <stop offset="50%" stop-color="#E9AB34"/>
6
+ <stop offset="100%" stop-color="#EF4444"/>
7
+ </linearGradient>
8
+ </defs>
9
+
10
+ <!-- Background -->
11
+ <rect width="16" height="16" rx="3" fill="#1A1A1A"/>
12
+
13
+ <!-- Simplified wave for 16x16 -->
14
+ <path d="M 2 12 C 4 12, 5 10, 7 8 C 9 6, 10 4, 12 3 C 13 2, 14 3, 14 2.5"
15
+ stroke="url(#fav-grad)" stroke-width="1.5" fill="none" stroke-linecap="round"/>
16
+
17
+ <!-- Dot -->
18
+ <circle cx="12" cy="3" r="1.5" fill="#E9AB34"/>
16
19
  </svg>
@@ -1,23 +1,24 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 64" width="320" height="64">
2
- <!-- Black version for light backgrounds -->
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 360 72" width="360" height="72">
2
+ <!-- Black version for light backgrounds — no background rectangle -->
3
3
 
4
- <!-- Gauge track arc (light gray) -->
5
- <path d="M 12 50 A 22 22 0 1 1 52 50" stroke="#E5E7EB" stroke-width="5" fill="none" stroke-linecap="round"/>
6
- <!-- Green zone -->
7
- <path d="M 12 50 A 22 22 0 0 1 18.2 30.4" stroke="#16A34A" stroke-width="5" fill="none" stroke-linecap="round"/>
8
- <!-- Yellow zone -->
9
- <path d="M 18.2 30.4 A 22 22 0 0 1 45.8 30.4" stroke="#D97706" stroke-width="5" fill="none" stroke-linecap="round"/>
10
- <!-- Red zone -->
11
- <path d="M 45.8 30.4 A 22 22 0 0 1 52 50" stroke="#DC2626" stroke-width="5" fill="none" stroke-linecap="round"/>
12
- <!-- Needle -->
13
- <line x1="32" y1="38" x2="21" y2="27" stroke="#000000" stroke-width="2.5" stroke-linecap="round"/>
14
- <!-- Pivot -->
15
- <circle cx="32" cy="38" r="3" fill="#16A34A"/>
4
+ <!-- Mark: Context wave -->
5
+ <g transform="translate(8, 4)">
6
+ <path d="M 10 48 C 16 48, 18 42, 22 40 C 26 38, 28 36, 32 32 C 36 28, 38 22, 42 18 C 46 14, 50 16, 54 14"
7
+ stroke="#1A1A1A" stroke-width="3.5" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
8
+ <path d="M 10 52 C 16 52, 18 46, 22 44 C 26 42, 28 40, 32 36 C 36 32, 38 26, 42 22 C 46 18, 50 20, 54 18"
9
+ stroke="#1A1A1A" stroke-width="1.5" fill="none" stroke-linecap="round" opacity="0.25"/>
10
+ <circle cx="42" cy="18" r="3.5" fill="#1A1A1A"/>
11
+ <circle cx="42" cy="18" r="6" fill="#1A1A1A" opacity="0.12"/>
12
+ <line x1="10" y1="54" x2="54" y2="54" stroke="#1A1A1A" stroke-width="1" stroke-linecap="round" opacity="0.3"/>
13
+ </g>
16
14
 
17
15
  <!-- Divider -->
18
- <line x1="68" y1="12" x2="68" y2="52" stroke="#D1D5DB" stroke-width="1"/>
16
+ <line x1="76" y1="16" x2="76" y2="56" stroke="#1A1A1A" stroke-width="1" opacity="0.2"/>
19
17
 
20
- <!-- Wordmark black -->
21
- <text x="82" y="30" font-family="'SF Mono', 'Fira Mono', 'Courier New', monospace" font-size="18" font-weight="700" fill="#000000" letter-spacing="-0.5">cc-context</text>
22
- <text x="82" y="50" font-family="'SF Mono', 'Fira Mono', 'Courier New', monospace" font-size="14" font-weight="500" fill="#16A34A" letter-spacing="2">stats</text>
18
+ <!-- Wordmark -->
19
+ <text x="90" y="35" font-family="'SF Mono', 'JetBrains Mono', 'Fira Code', 'Cascadia Code', monospace" font-size="22" font-weight="700" fill="#1A1A1A" letter-spacing="-0.3">cc-context</text>
20
+ <text x="90" y="55" font-family="'SF Mono', 'JetBrains Mono', 'Fira Code', 'Cascadia Code', monospace" font-size="15" font-weight="500" fill="#1A1A1A" letter-spacing="3" opacity="0.6">stats</text>
21
+
22
+ <!-- Right accent bar -->
23
+ <rect x="348" y="20" width="2" height="32" rx="1" fill="#1A1A1A" opacity="0.35"/>
23
24
  </svg>
@@ -1,30 +1,40 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 64" width="320" height="64">
2
- <!-- Background -->
3
- <rect width="320" height="64" rx="12" fill="#000000"/>
4
-
5
- <!-- Mark: Gauge icon (left, inset) -->
6
- <!-- Gauge track arc -->
7
- <path d="M 12 50 A 22 22 0 1 1 52 50" stroke="#1a1a1a" stroke-width="5" fill="none" stroke-linecap="round"/>
8
- <!-- Green zone -->
9
- <path d="M 12 50 A 22 22 0 0 1 18.2 30.4" stroke="#22C55E" stroke-width="5" fill="none" stroke-linecap="round"/>
10
- <!-- Yellow zone -->
11
- <path d="M 18.2 30.4 A 22 22 0 0 1 45.8 30.4" stroke="#F59E0B" stroke-width="5" fill="none" stroke-linecap="round"/>
12
- <!-- Red zone -->
13
- <path d="M 45.8 30.4 A 22 22 0 0 1 52 50" stroke="#EF4444" stroke-width="5" fill="none" stroke-linecap="round"/>
14
- <!-- Needle -->
15
- <line x1="32" y1="38" x2="21" y2="27" stroke="#FFFFFF" stroke-width="2.5" stroke-linecap="round"/>
16
- <!-- Pivot -->
17
- <circle cx="32" cy="38" r="3" fill="#22C55E"/>
18
-
19
- <!-- Divider line -->
20
- <line x1="68" y1="12" x2="68" y2="52" stroke="#1f1f1f" stroke-width="1"/>
21
-
22
- <!-- Wordmark: "cc-context" on top row, "stats" accent -->
23
- <!-- Primary text -->
24
- <text x="82" y="30" font-family="'SF Mono', 'Fira Mono', 'Courier New', monospace" font-size="18" font-weight="700" fill="#FFFFFF" letter-spacing="-0.5">cc-context</text>
25
- <!-- Accent text with green highlight -->
26
- <text x="82" y="50" font-family="'SF Mono', 'Fira Mono', 'Courier New', monospace" font-size="14" font-weight="500" fill="#22C55E" letter-spacing="2">stats</text>
27
-
28
- <!-- Subtle border accent on right -->
29
- <rect x="308" y="16" width="2" height="32" rx="1" fill="#22C55E" opacity="0.6"/>
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 360 72" width="360" height="72">
2
+ <defs>
3
+ <linearGradient id="full-wave-grad" x1="0%" y1="0%" x2="100%" y2="0%">
4
+ <stop offset="0%" stop-color="#22C55E"/>
5
+ <stop offset="50%" stop-color="#E9AB34"/>
6
+ <stop offset="100%" stop-color="#EF4444"/>
7
+ </linearGradient>
8
+ </defs>
9
+
10
+ <!-- Background pill -->
11
+ <rect width="360" height="72" rx="14" fill="#1A1A1A"/>
12
+
13
+ <!-- Mark: Context wave in left area -->
14
+ <g transform="translate(8, 4)">
15
+ <!-- Context wave -->
16
+ <path d="M 10 48 C 16 48, 18 42, 22 40 C 26 38, 28 36, 32 32 C 36 28, 38 22, 42 18 C 46 14, 50 16, 54 14"
17
+ stroke="url(#full-wave-grad)" stroke-width="3.5" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
18
+
19
+ <!-- Echo line -->
20
+ <path d="M 10 52 C 16 52, 18 46, 22 44 C 26 42, 28 40, 32 36 C 36 32, 38 26, 42 22 C 46 18, 50 20, 54 18"
21
+ stroke="url(#full-wave-grad)" stroke-width="1.5" fill="none" stroke-linecap="round" opacity="0.3"/>
22
+
23
+ <!-- Cursor dot -->
24
+ <circle cx="42" cy="18" r="3.5" fill="#E9AB34"/>
25
+ <circle cx="42" cy="18" r="6" fill="#E9AB34" opacity="0.15"/>
26
+
27
+ <!-- Baseline -->
28
+ <line x1="10" y1="54" x2="54" y2="54" stroke="#8B7D6B" stroke-width="1" stroke-linecap="round" opacity="0.4"/>
29
+ </g>
30
+
31
+ <!-- Divider -->
32
+ <line x1="76" y1="16" x2="76" y2="56" stroke="#8B7D6B" stroke-width="1" opacity="0.25"/>
33
+
34
+ <!-- Wordmark -->
35
+ <text x="90" y="35" font-family="'SF Mono', 'JetBrains Mono', 'Fira Code', 'Cascadia Code', monospace" font-size="22" font-weight="700" fill="#FFFFFF" letter-spacing="-0.3">cc-context</text>
36
+ <text x="90" y="55" font-family="'SF Mono', 'JetBrains Mono', 'Fira Code', 'Cascadia Code', monospace" font-size="15" font-weight="500" fill="#E9AB34" letter-spacing="3">stats</text>
37
+
38
+ <!-- Right accent bar -->
39
+ <rect x="348" y="20" width="2" height="32" rx="1" fill="#E9AB34" opacity="0.5"/>
30
40
  </svg>
@@ -1,26 +1,27 @@
1
1
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
2
- <!-- App icon — square with padding and rounded corners -->
3
- <rect width="512" height="512" rx="96" fill="#000000"/>
2
+ <defs>
3
+ <linearGradient id="icon-wave-grad" x1="0%" y1="0%" x2="100%" y2="0%">
4
+ <stop offset="0%" stop-color="#22C55E"/>
5
+ <stop offset="50%" stop-color="#E9AB34"/>
6
+ <stop offset="100%" stop-color="#EF4444"/>
7
+ </linearGradient>
8
+ </defs>
4
9
 
5
- <!-- Gauge track (background) -->
6
- <path d="M 96 352 A 176 176 0 1 1 416 352" stroke="#111111" stroke-width="38" fill="none" stroke-linecap="round"/>
10
+ <!-- Background -->
11
+ <rect width="512" height="512" rx="96" fill="#1A1A1A"/>
7
12
 
8
- <!-- Green zone (0-40%) -->
9
- <path d="M 96 352 A 176 176 0 0 1 145.6 194.8" stroke="#22C55E" stroke-width="38" fill="none" stroke-linecap="round"/>
13
+ <!-- Context wave (scaled up) -->
14
+ <path d="M 96 376 C 144 376, 160 328, 192 312 C 224 296, 240 280, 272 248 C 304 216, 320 168, 352 136 C 384 104, 400 120, 432 104"
15
+ stroke="url(#icon-wave-grad)" stroke-width="24" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
10
16
 
11
- <!-- Yellow zone (40-80%) -->
12
- <path d="M 145.6 194.8 A 176 176 0 0 1 366.4 194.8" stroke="#F59E0B" stroke-width="38" fill="none" stroke-linecap="round"/>
17
+ <!-- Echo line -->
18
+ <path d="M 96 408 C 144 408, 160 360, 192 344 C 224 328, 240 312, 272 280 C 304 248, 320 200, 352 168 C 384 136, 400 152, 432 136"
19
+ stroke="url(#icon-wave-grad)" stroke-width="10" fill="none" stroke-linecap="round" opacity="0.25"/>
13
20
 
14
- <!-- Red zone (80-100%) -->
15
- <path d="M 366.4 194.8 A 176 176 0 0 1 416 352" stroke="#EF4444" stroke-width="38" fill="none" stroke-linecap="round"/>
21
+ <!-- Cursor dot -->
22
+ <circle cx="352" cy="136" r="28" fill="#E9AB34"/>
23
+ <circle cx="352" cy="136" r="48" fill="#E9AB34" opacity="0.12"/>
16
24
 
17
- <!-- Needle at ~55% -->
18
- <line x1="256" y1="256" x2="168" y2="168" stroke="#FFFFFF" stroke-width="20" stroke-linecap="round"/>
19
-
20
- <!-- Pivot dot -->
21
- <circle cx="256" cy="256" r="24" fill="#22C55E"/>
22
-
23
- <!-- Label dots at zone boundaries -->
24
- <circle cx="96" cy="352" r="8" fill="#6B7280"/>
25
- <circle cx="416" cy="352" r="8" fill="#6B7280"/>
25
+ <!-- Baseline -->
26
+ <line x1="96" y1="424" x2="432" y2="424" stroke="#8B7D6B" stroke-width="6" stroke-linecap="round" opacity="0.35"/>
26
27
  </svg>
@@ -1,26 +1,28 @@
1
1
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="64" height="64">
2
- <!-- Background square with rounded corners -->
3
- <rect width="64" height="64" rx="12" fill="#000000"/>
2
+ <defs>
3
+ <linearGradient id="wave-grad" x1="0%" y1="0%" x2="100%" y2="0%">
4
+ <stop offset="0%" stop-color="#22C55E"/>
5
+ <stop offset="50%" stop-color="#E9AB34"/>
6
+ <stop offset="100%" stop-color="#EF4444"/>
7
+ </linearGradient>
8
+ </defs>
4
9
 
5
- <!-- Gauge track arc (background) -->
6
- <path d="M 12 44 A 22 22 0 1 1 52 44" stroke="#1a1a1a" stroke-width="5" fill="none" stroke-linecap="round"/>
10
+ <!-- Background -->
11
+ <rect width="64" height="64" rx="14" fill="#1A1A1A"/>
7
12
 
8
- <!-- Gauge fill: green zone (0-40%) -->
9
- <path d="M 12 44 A 22 22 0 0 1 18.2 24.4" stroke="#22C55E" stroke-width="5" fill="none" stroke-linecap="round"/>
13
+ <!-- Context wave: a flowing curve rising from left (low usage) to right (high usage) -->
14
+ <!-- This represents the context growth graph - the core concept of the tool -->
15
+ <path d="M 10 48 C 16 48, 18 42, 22 40 C 26 38, 28 36, 32 32 C 36 28, 38 22, 42 18 C 46 14, 50 16, 54 14"
16
+ stroke="url(#wave-grad)" stroke-width="3.5" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
10
17
 
11
- <!-- Gauge fill: yellow zone (40-80%) -->
12
- <path d="M 18.2 24.4 A 22 22 0 0 1 45.8 24.4" stroke="#F59E0B" stroke-width="5" fill="none" stroke-linecap="round"/>
18
+ <!-- Secondary pulse line (echo effect for depth) -->
19
+ <path d="M 10 52 C 16 52, 18 46, 22 44 C 26 42, 28 40, 32 36 C 36 32, 38 26, 42 22 C 46 18, 50 20, 54 18"
20
+ stroke="url(#wave-grad)" stroke-width="1.5" fill="none" stroke-linecap="round" opacity="0.3"/>
13
21
 
14
- <!-- Gauge fill: red zone (80-100%) -->
15
- <path d="M 45.8 24.4 A 22 22 0 0 1 52 44" stroke="#EF4444" stroke-width="5" fill="none" stroke-linecap="round"/>
22
+ <!-- Cursor dot at the "current position" on the wave -->
23
+ <circle cx="42" cy="18" r="3.5" fill="#E9AB34"/>
24
+ <circle cx="42" cy="18" r="6" fill="#E9AB34" opacity="0.15"/>
16
25
 
17
- <!-- Needle at ~55% (in dumb zone) -->
18
- <line x1="32" y1="32" x2="21" y2="21" stroke="#FFFFFF" stroke-width="2.5" stroke-linecap="round"/>
19
-
20
- <!-- Needle pivot center dot -->
21
- <circle cx="32" cy="32" r="3" fill="#22C55E"/>
22
-
23
- <!-- Tick marks at zone boundaries -->
24
- <line x1="12" y1="44" x2="14.5" y2="41.5" stroke="#6B7280" stroke-width="1.5" stroke-linecap="round"/>
25
- <line x1="52" y1="44" x2="49.5" y2="41.5" stroke="#6B7280" stroke-width="1.5" stroke-linecap="round"/>
26
+ <!-- Baseline -->
27
+ <line x1="10" y1="54" x2="54" y2="54" stroke="#8B7D6B" stroke-width="1" stroke-linecap="round" opacity="0.4"/>
26
28
  </svg>
@@ -1,23 +1,24 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 64" width="320" height="64">
2
- <!-- White version for dark backgrounds — no bg rect -->
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 360 72" width="360" height="72">
2
+ <!-- White version for dark backgrounds — no background rectangle -->
3
3
 
4
- <!-- Gauge track arc (dim white) -->
5
- <path d="M 12 50 A 22 22 0 1 1 52 50" stroke="rgba(255,255,255,0.15)" stroke-width="5" fill="none" stroke-linecap="round"/>
6
- <!-- Green zone -->
7
- <path d="M 12 50 A 22 22 0 0 1 18.2 30.4" stroke="#22C55E" stroke-width="5" fill="none" stroke-linecap="round"/>
8
- <!-- Yellow zone -->
9
- <path d="M 18.2 30.4 A 22 22 0 0 1 45.8 30.4" stroke="#F59E0B" stroke-width="5" fill="none" stroke-linecap="round"/>
10
- <!-- Red zone -->
11
- <path d="M 45.8 30.4 A 22 22 0 0 1 52 50" stroke="#EF4444" stroke-width="5" fill="none" stroke-linecap="round"/>
12
- <!-- Needle -->
13
- <line x1="32" y1="38" x2="21" y2="27" stroke="#FFFFFF" stroke-width="2.5" stroke-linecap="round"/>
14
- <!-- Pivot -->
15
- <circle cx="32" cy="38" r="3" fill="#22C55E"/>
4
+ <!-- Mark: Context wave -->
5
+ <g transform="translate(8, 4)">
6
+ <path d="M 10 48 C 16 48, 18 42, 22 40 C 26 38, 28 36, 32 32 C 36 28, 38 22, 42 18 C 46 14, 50 16, 54 14"
7
+ stroke="#FFFFFF" stroke-width="3.5" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
8
+ <path d="M 10 52 C 16 52, 18 46, 22 44 C 26 42, 28 40, 32 36 C 36 32, 38 26, 42 22 C 46 18, 50 20, 54 18"
9
+ stroke="#FFFFFF" stroke-width="1.5" fill="none" stroke-linecap="round" opacity="0.25"/>
10
+ <circle cx="42" cy="18" r="3.5" fill="#FFFFFF"/>
11
+ <circle cx="42" cy="18" r="6" fill="#FFFFFF" opacity="0.12"/>
12
+ <line x1="10" y1="54" x2="54" y2="54" stroke="#FFFFFF" stroke-width="1" stroke-linecap="round" opacity="0.3"/>
13
+ </g>
16
14
 
17
15
  <!-- Divider -->
18
- <line x1="68" y1="12" x2="68" y2="52" stroke="rgba(255,255,255,0.2)" stroke-width="1"/>
16
+ <line x1="76" y1="16" x2="76" y2="56" stroke="#FFFFFF" stroke-width="1" opacity="0.2"/>
19
17
 
20
- <!-- Wordmark white -->
21
- <text x="82" y="30" font-family="'SF Mono', 'Fira Mono', 'Courier New', monospace" font-size="18" font-weight="700" fill="#FFFFFF" letter-spacing="-0.5">cc-context</text>
22
- <text x="82" y="50" font-family="'SF Mono', 'Fira Mono', 'Courier New', monospace" font-size="14" font-weight="500" fill="#22C55E" letter-spacing="2">stats</text>
18
+ <!-- Wordmark -->
19
+ <text x="90" y="35" font-family="'SF Mono', 'JetBrains Mono', 'Fira Code', 'Cascadia Code', monospace" font-size="22" font-weight="700" fill="#FFFFFF" letter-spacing="-0.3">cc-context</text>
20
+ <text x="90" y="55" font-family="'SF Mono', 'JetBrains Mono', 'Fira Code', 'Cascadia Code', monospace" font-size="15" font-weight="500" fill="#FFFFFF" letter-spacing="3" opacity="0.7">stats</text>
21
+
22
+ <!-- Right accent bar -->
23
+ <rect x="348" y="20" width="2" height="32" rx="1" fill="#FFFFFF" opacity="0.4"/>
23
24
  </svg>
@@ -1,7 +1,6 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 220 48" width="220" height="48">
2
- <!-- Background transparent -->
3
- <!-- Primary text -->
4
- <text x="0" y="28" font-family="'SF Mono', 'Fira Mono', 'Courier New', monospace" font-size="22" font-weight="700" fill="#000000" letter-spacing="-0.5">cc-context</text>
5
- <!-- Accent -->
6
- <text x="0" y="44" font-family="'SF Mono', 'Fira Mono', 'Courier New', monospace" font-size="14" font-weight="500" fill="#22C55E" letter-spacing="2">stats</text>
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 260 52" width="260" height="52">
2
+ <!-- Wordmark only — transparent background -->
3
+ <!-- "cc-context" bold, "stats" in golden amber below -->
4
+ <text x="0" y="30" font-family="'SF Mono', 'JetBrains Mono', 'Fira Code', 'Cascadia Code', monospace" font-size="24" font-weight="700" fill="#1A1A1A" letter-spacing="-0.3">cc-context</text>
5
+ <text x="0" y="48" font-family="'SF Mono', 'JetBrains Mono', 'Fira Code', 'Cascadia Code', monospace" font-size="15" font-weight="500" fill="#E9AB34" letter-spacing="3">stats</text>
7
6
  </svg>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cc-context-stats",
3
- "version": "1.5.0",
3
+ "version": "1.5.1",
4
4
  "description": "Monitor your Claude Code session context in real-time - track token usage and never run out of context",
5
5
  "main": "scripts/statusline.js",
6
6
  "scripts": {
package/pyproject.toml CHANGED
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "cc-context-stats"
7
- version = "1.5.0"
7
+ version = "1.5.1"
8
8
  description = "Monitor your Claude Code session context in real-time - track token usage and never run out of context"
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
@@ -116,13 +116,21 @@ visible_width() {
116
116
  }
117
117
 
118
118
  get_terminal_width() {
119
- # Return terminal width, fallback to 80
119
+ # Return terminal width for fit_to_width truncation.
120
+ # When running inside Claude Code's statusline subprocess, neither $COLUMNS
121
+ # nor tput can detect the real terminal width (they always return 80).
122
+ # If COLUMNS is explicitly set, trust it. Otherwise use 200 as default
123
+ # so no parts are unnecessarily dropped; Claude Code handles overflow.
120
124
  if [[ -n "$COLUMNS" ]]; then
121
125
  echo "$COLUMNS"
122
126
  else
123
127
  local cols
124
128
  cols=$(tput cols 2>/dev/null || echo 80)
125
- echo "$cols"
129
+ if [[ "$cols" -eq 80 ]]; then
130
+ echo 200
131
+ else
132
+ echo "$cols"
133
+ fi
126
134
  fi
127
135
  }
128
136
 
@@ -22,12 +22,19 @@ visible_width() {
22
22
  }
23
23
 
24
24
  get_terminal_width() {
25
+ # When running inside Claude Code's statusline subprocess, $COLUMNS is not set
26
+ # and tput falls back to 80. If COLUMNS is set, trust it. Otherwise use 200
27
+ # so no parts are dropped; Claude Code handles overflow.
25
28
  if [[ -n "$COLUMNS" ]]; then
26
29
  echo "$COLUMNS"
27
30
  else
28
31
  local cols
29
32
  cols=$(tput cols 2>/dev/null || echo 80)
30
- echo "$cols"
33
+ if [[ "$cols" -eq 80 ]]; then
34
+ echo 200
35
+ else
36
+ echo "$cols"
37
+ fi
31
38
  fi
32
39
  }
33
40
 
@@ -16,12 +16,19 @@ visible_width() {
16
16
  }
17
17
 
18
18
  get_terminal_width() {
19
+ # When running inside Claude Code's statusline subprocess, $COLUMNS is not set
20
+ # and tput falls back to 80. If COLUMNS is set, trust it. Otherwise use 200
21
+ # so no parts are dropped; Claude Code handles overflow.
19
22
  if [[ -n "$COLUMNS" ]]; then
20
23
  echo "$COLUMNS"
21
24
  else
22
25
  local cols
23
26
  cols=$(tput cols 2>/dev/null || echo 80)
24
- echo "$cols"
27
+ if [[ "$cols" -eq 80 ]]; then
28
+ echo 200
29
+ else
30
+ echo "$cols"
31
+ fi
25
32
  fi
26
33
  }
27
34
 
@@ -46,6 +46,7 @@ const RESET = '\x1b[0m';
46
46
  * Return the visible width of a string after stripping ANSI escape sequences.
47
47
  */
48
48
  function visibleWidth(s) {
49
+ // eslint-disable-next-line no-control-regex
49
50
  return s.replace(/\x1b\[[0-9;]*m/g, '').length;
50
51
  }
51
52
 
@@ -51,8 +51,21 @@ def visible_width(s):
51
51
 
52
52
 
53
53
  def get_terminal_width():
54
- """Return the terminal width in columns, defaulting to 80."""
55
- return shutil.get_terminal_size().columns
54
+ """Return the terminal width in columns.
55
+
56
+ When running inside Claude Code's statusline subprocess, neither $COLUMNS
57
+ nor tput/shutil can detect the real terminal width (they always return 80).
58
+ If COLUMNS is not explicitly set and shutil falls back to 80, we use a
59
+ generous default of 200 so that no parts are unnecessarily dropped;
60
+ Claude Code's own UI handles any overflow/truncation.
61
+ """
62
+ # If COLUMNS is explicitly set, trust it (real terminal or test override)
63
+ if os.environ.get("COLUMNS"):
64
+ return shutil.get_terminal_size().columns
65
+ # No COLUMNS env var — likely a Claude Code subprocess with no real TTY.
66
+ # shutil will fall back to 80, which is too narrow. Use 200 instead.
67
+ cols = shutil.get_terminal_size(fallback=(200, 24)).columns
68
+ return 200 if cols == 80 else cols
56
69
 
57
70
 
58
71
  def fit_to_width(parts, max_width):
@@ -3,7 +3,7 @@
3
3
  Never run out of context unexpectedly - monitor your session context in real-time.
4
4
  """
5
5
 
6
- __version__ = "1.5.0"
6
+ __version__ = "1.5.1"
7
7
 
8
8
  from claude_statusline.core.config import Config
9
9
  from claude_statusline.core.state import StateFile
@@ -15,8 +15,23 @@ def visible_width(s: str) -> int:
15
15
 
16
16
 
17
17
  def get_terminal_width() -> int:
18
- """Return the terminal width in columns, defaulting to 80."""
19
- return shutil.get_terminal_size().columns
18
+ """Return the terminal width in columns.
19
+
20
+ When running inside Claude Code's statusline subprocess, neither $COLUMNS
21
+ nor tput/shutil can detect the real terminal width (they always return 80).
22
+ If COLUMNS is not explicitly set and shutil falls back to 80, we use a
23
+ generous default of 200 so that no parts are unnecessarily dropped;
24
+ Claude Code's own UI handles any overflow/truncation.
25
+ """
26
+ import os
27
+
28
+ # If COLUMNS is explicitly set, trust it (real terminal or test override)
29
+ if os.environ.get("COLUMNS"):
30
+ return shutil.get_terminal_size().columns
31
+ # No COLUMNS env var — likely a Claude Code subprocess with no real TTY.
32
+ # shutil will fall back to 80, which is too narrow. Use 200 instead.
33
+ cols = shutil.get_terminal_size(fallback=(200, 24)).columns
34
+ return 200 if cols == 80 else cols
20
35
 
21
36
 
22
37
  def fit_to_width(parts: list[str], max_width: int) -> str:
@@ -38,8 +38,25 @@ class TestVisibleWidth:
38
38
  class TestGetTerminalWidth:
39
39
  """Tests for get_terminal_width()."""
40
40
 
41
- def test_fallback_to_80(self):
42
- with patch("claude_statusline.formatters.layout.shutil.get_terminal_size") as mock:
41
+ def test_fallback_to_200_when_no_columns_env(self):
42
+ """When COLUMNS is not set and shutil returns 80, use 200 (Claude Code subprocess)."""
43
+ with (
44
+ patch("claude_statusline.formatters.layout.shutil.get_terminal_size") as mock,
45
+ patch.dict("os.environ", {}, clear=False),
46
+ ):
47
+ # Remove COLUMNS if present
48
+ import os
49
+
50
+ os.environ.pop("COLUMNS", None)
51
+ mock.return_value = type("Size", (), {"columns": 80})()
52
+ assert get_terminal_width() == 200
53
+
54
+ def test_respects_columns_env_80(self):
55
+ """When COLUMNS=80 is explicitly set, trust it."""
56
+ with (
57
+ patch("claude_statusline.formatters.layout.shutil.get_terminal_size") as mock,
58
+ patch.dict("os.environ", {"COLUMNS": "80"}),
59
+ ):
43
60
  mock.return_value = type("Size", (), {"columns": 80})()
44
61
  assert get_terminal_width() == 80
45
62
 
@@ -1,5 +1,7 @@
1
1
  """Tests for statusline.py script."""
2
2
 
3
+ from __future__ import annotations
4
+
3
5
  import json
4
6
  import os
5
7
  import re