cc-context-stats 1.7.0 → 1.8.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.
Files changed (102) hide show
  1. package/package.json +9 -1
  2. package/scripts/context-stats.sh +1 -1
  3. package/scripts/statusline.js +128 -18
  4. package/.editorconfig +0 -60
  5. package/.eslintrc.json +0 -35
  6. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -49
  7. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -31
  8. package/.github/PULL_REQUEST_TEMPLATE.md +0 -33
  9. package/.github/dependabot.yml +0 -44
  10. package/.github/workflows/ci.yml +0 -294
  11. package/.github/workflows/release.yml +0 -151
  12. package/.pre-commit-config.yaml +0 -74
  13. package/.prettierrc +0 -33
  14. package/.shellcheckrc +0 -10
  15. package/CHANGELOG.md +0 -163
  16. package/CLAUDE.md +0 -66
  17. package/CODE_OF_CONDUCT.md +0 -59
  18. package/CONTRIBUTING.md +0 -240
  19. package/RELEASE_NOTES.md +0 -19
  20. package/SECURITY.md +0 -44
  21. package/TODOS.md +0 -72
  22. package/assets/logo/favicon.svg +0 -19
  23. package/assets/logo/logo-black.svg +0 -24
  24. package/assets/logo/logo-full.svg +0 -40
  25. package/assets/logo/logo-icon.svg +0 -27
  26. package/assets/logo/logo-mark.svg +0 -28
  27. package/assets/logo/logo-white.svg +0 -24
  28. package/assets/logo/logo-wordmark.svg +0 -6
  29. package/config/settings-example.json +0 -7
  30. package/config/settings-node.json +0 -7
  31. package/config/settings-python.json +0 -7
  32. package/docs/ARCHITECTURE.md +0 -128
  33. package/docs/CSV_FORMAT.md +0 -42
  34. package/docs/DEPLOYMENT.md +0 -71
  35. package/docs/DEVELOPMENT.md +0 -161
  36. package/docs/configuration.md +0 -118
  37. package/docs/context-stats.md +0 -143
  38. package/docs/installation.md +0 -255
  39. package/docs/scripts.md +0 -140
  40. package/docs/troubleshooting.md +0 -278
  41. package/images/claude-statusline-token-graph.gif +0 -0
  42. package/images/claude-statusline.png +0 -0
  43. package/images/context-status-dumbzone.png +0 -0
  44. package/images/context-status.png +0 -0
  45. package/images/statusline-detail.png +0 -0
  46. package/images/token-graph.jpeg +0 -0
  47. package/images/token-graph.png +0 -0
  48. package/images/v1.6.1.png +0 -0
  49. package/install +0 -351
  50. package/install.sh +0 -298
  51. package/jest.config.js +0 -11
  52. package/pyproject.toml +0 -115
  53. package/requirements-dev.txt +0 -12
  54. package/scripts/statusline-full.sh +0 -304
  55. package/scripts/statusline-git.sh +0 -88
  56. package/scripts/statusline-minimal.sh +0 -67
  57. package/scripts/statusline.py +0 -485
  58. package/src/claude_statusline/__init__.py +0 -11
  59. package/src/claude_statusline/__main__.py +0 -6
  60. package/src/claude_statusline/cli/__init__.py +0 -1
  61. package/src/claude_statusline/cli/context_stats.py +0 -512
  62. package/src/claude_statusline/cli/explain.py +0 -228
  63. package/src/claude_statusline/cli/statusline.py +0 -169
  64. package/src/claude_statusline/core/__init__.py +0 -1
  65. package/src/claude_statusline/core/colors.py +0 -124
  66. package/src/claude_statusline/core/config.py +0 -148
  67. package/src/claude_statusline/core/git.py +0 -78
  68. package/src/claude_statusline/core/state.py +0 -323
  69. package/src/claude_statusline/formatters/__init__.py +0 -1
  70. package/src/claude_statusline/formatters/layout.py +0 -67
  71. package/src/claude_statusline/formatters/time.py +0 -50
  72. package/src/claude_statusline/formatters/tokens.py +0 -70
  73. package/src/claude_statusline/graphs/__init__.py +0 -1
  74. package/src/claude_statusline/graphs/renderer.py +0 -366
  75. package/src/claude_statusline/graphs/statistics.py +0 -92
  76. package/src/claude_statusline/ui/__init__.py +0 -1
  77. package/src/claude_statusline/ui/icons.py +0 -93
  78. package/src/claude_statusline/ui/waiting.py +0 -62
  79. package/tests/bash/test_delta_parity.bats +0 -199
  80. package/tests/bash/test_install.bats +0 -29
  81. package/tests/bash/test_parity.bats +0 -315
  82. package/tests/bash/test_statusline_full.bats +0 -139
  83. package/tests/bash/test_statusline_git.bats +0 -42
  84. package/tests/bash/test_statusline_minimal.bats +0 -37
  85. package/tests/fixtures/json/comma_in_path.json +0 -31
  86. package/tests/fixtures/json/high_usage.json +0 -17
  87. package/tests/fixtures/json/low_usage.json +0 -17
  88. package/tests/fixtures/json/medium_usage.json +0 -17
  89. package/tests/fixtures/json/valid_full.json +0 -30
  90. package/tests/fixtures/json/valid_minimal.json +0 -9
  91. package/tests/node/rotation.test.js +0 -89
  92. package/tests/node/statusline.test.js +0 -240
  93. package/tests/python/conftest.py +0 -84
  94. package/tests/python/test_colors.py +0 -105
  95. package/tests/python/test_config_colors.py +0 -78
  96. package/tests/python/test_data_pipeline.py +0 -446
  97. package/tests/python/test_explain.py +0 -177
  98. package/tests/python/test_icons.py +0 -152
  99. package/tests/python/test_layout.py +0 -127
  100. package/tests/python/test_state_rotation_validation.py +0 -232
  101. package/tests/python/test_statusline.py +0 -215
  102. package/tests/python/test_waiting.py +0 -127
@@ -1,485 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Python status line script for Claude Code
4
- Usage: Copy to ~/.claude/statusline.py and make executable
5
-
6
- Configuration:
7
- Create/edit ~/.claude/statusline.conf and set:
8
-
9
- autocompact=true (when autocompact is enabled in Claude Code - default)
10
- autocompact=false (when you disable autocompact via /config in Claude Code)
11
-
12
- token_detail=true (show exact token count like 64,000 - default)
13
- token_detail=false (show abbreviated tokens like 64.0k)
14
-
15
- show_delta=true (show token delta since last refresh like [+2,500] - default)
16
- show_delta=false (disable delta display - saves file I/O on every refresh)
17
-
18
- show_session=true (show session_id in status line - default)
19
- show_session=false (hide session_id from status line)
20
-
21
- When AC is enabled, 22.5% of context window is reserved for autocompact buffer.
22
-
23
- State file format (CSV):
24
- timestamp,total_input_tokens,total_output_tokens,current_usage_input_tokens,
25
- current_usage_output_tokens,current_usage_cache_creation,current_usage_cache_read,
26
- total_cost_usd,total_lines_added,total_lines_removed,session_id,model_id,
27
- workspace_project_dir,context_window_size
28
- """
29
-
30
- import json
31
- import os
32
- import re
33
- import shutil
34
- import subprocess
35
- import sys
36
- import tempfile
37
-
38
- ROTATION_THRESHOLD = 10_000
39
- ROTATION_KEEP = 5_000
40
-
41
-
42
- def maybe_rotate_state_file(state_file):
43
- """Rotate a state file if it exceeds ROTATION_THRESHOLD lines.
44
-
45
- Keeps the most recent ROTATION_KEEP lines via atomic temp-file + rename.
46
- """
47
- try:
48
- if not os.path.exists(state_file):
49
- return
50
- with open(state_file) as f:
51
- lines = f.readlines()
52
- if len(lines) <= ROTATION_THRESHOLD:
53
- return
54
- keep = lines[-ROTATION_KEEP:]
55
- fd, tmp_path = tempfile.mkstemp(dir=os.path.dirname(state_file), suffix=".tmp")
56
- try:
57
- with os.fdopen(fd, "w") as tmp_f:
58
- tmp_f.writelines(keep)
59
- os.replace(tmp_path, state_file)
60
- except BaseException:
61
- try:
62
- os.unlink(tmp_path)
63
- except OSError:
64
- pass
65
- raise
66
- except OSError as e:
67
- sys.stderr.write(f"[statusline] warning: failed to rotate state file: {e}\n")
68
-
69
-
70
- # ANSI Colors (defaults, overridable via config)
71
- BLUE = "\033[0;34m"
72
- MAGENTA = "\033[0;35m"
73
- CYAN = "\033[0;36m"
74
- GREEN = "\033[0;32m"
75
- YELLOW = "\033[0;33m"
76
- RED = "\033[0;31m"
77
- DIM = "\033[2m"
78
- RESET = "\033[0m"
79
-
80
- # Named colors for config parsing
81
- _COLOR_NAMES = {
82
- "black": "\033[0;30m",
83
- "red": "\033[0;31m",
84
- "green": "\033[0;32m",
85
- "yellow": "\033[0;33m",
86
- "blue": "\033[0;34m",
87
- "magenta": "\033[0;35m",
88
- "cyan": "\033[0;36m",
89
- "white": "\033[0;37m",
90
- "bright_black": "\033[0;90m",
91
- "bright_red": "\033[0;91m",
92
- "bright_green": "\033[0;92m",
93
- "bright_yellow": "\033[0;93m",
94
- "bright_blue": "\033[0;94m",
95
- "bright_magenta": "\033[0;95m",
96
- "bright_cyan": "\033[0;96m",
97
- "bright_white": "\033[0;97m",
98
- }
99
-
100
-
101
- def _parse_color(value):
102
- """Parse a color name or #rrggbb hex into an ANSI escape code."""
103
- value = value.strip().lower()
104
- if value in _COLOR_NAMES:
105
- return _COLOR_NAMES[value]
106
- if re.match(r"^#[0-9a-f]{6}$", value):
107
- r, g, b = int(value[1:3], 16), int(value[3:5], 16), int(value[5:7], 16)
108
- return f"\033[38;2;{r};{g};{b}m"
109
- return None
110
-
111
-
112
- # Color config keys and which color slot they map to
113
- _COLOR_KEYS = {
114
- "color_green": "green",
115
- "color_yellow": "yellow",
116
- "color_red": "red",
117
- "color_blue": "blue",
118
- "color_magenta": "magenta",
119
- "color_cyan": "cyan",
120
- }
121
-
122
- # Pattern to strip ANSI escape sequences
123
- _ANSI_RE = re.compile(r"\033\[[0-9;]*m")
124
-
125
-
126
- def visible_width(s):
127
- """Return the visible width of a string after stripping ANSI escape sequences."""
128
- return len(_ANSI_RE.sub("", s))
129
-
130
-
131
- def get_terminal_width():
132
- """Return the terminal width in columns.
133
-
134
- When running inside Claude Code's statusline subprocess, neither $COLUMNS
135
- nor tput/shutil can detect the real terminal width (they always return 80).
136
- If COLUMNS is not explicitly set and shutil falls back to 80, we use a
137
- generous default of 200 so that no parts are unnecessarily dropped;
138
- Claude Code's own UI handles any overflow/truncation.
139
- """
140
- # If COLUMNS is explicitly set, trust it (real terminal or test override)
141
- if os.environ.get("COLUMNS"):
142
- return shutil.get_terminal_size().columns
143
- # No COLUMNS env var — likely a Claude Code subprocess with no real TTY.
144
- # shutil will fall back to 80, which is too narrow. Use 200 instead.
145
- cols = shutil.get_terminal_size(fallback=(200, 24)).columns
146
- return 200 if cols == 80 else cols
147
-
148
-
149
- def fit_to_width(parts, max_width):
150
- """Assemble parts into a single line that fits within max_width.
151
-
152
- Parts are added in priority order (first = highest priority).
153
- The first part (base) is always included. Subsequent parts are
154
- included only if adding them does not exceed max_width.
155
- Empty parts are skipped.
156
- """
157
- if not parts:
158
- return ""
159
-
160
- result = parts[0]
161
- current_width = visible_width(result)
162
-
163
- for part in parts[1:]:
164
- if not part:
165
- continue
166
- part_width = visible_width(part)
167
- if current_width + part_width <= max_width:
168
- result += part
169
- current_width += part_width
170
-
171
- return result
172
-
173
-
174
- def get_git_info(project_dir, magenta=None, cyan=None):
175
- """Get git branch and change count"""
176
- if magenta is None:
177
- magenta = MAGENTA
178
- if cyan is None:
179
- cyan = CYAN
180
- git_dir = os.path.join(project_dir, ".git")
181
- if not os.path.isdir(git_dir):
182
- return ""
183
-
184
- try:
185
- # Get branch name (skip optional locks for performance)
186
- result = subprocess.run(
187
- ["git", "--no-optional-locks", "rev-parse", "--abbrev-ref", "HEAD"],
188
- cwd=project_dir,
189
- capture_output=True,
190
- text=True,
191
- timeout=5,
192
- )
193
- branch = result.stdout.strip()
194
-
195
- if not branch:
196
- return ""
197
-
198
- # Count changes
199
- result = subprocess.run(
200
- ["git", "--no-optional-locks", "status", "--porcelain"],
201
- cwd=project_dir,
202
- capture_output=True,
203
- text=True,
204
- timeout=5,
205
- )
206
- changes = len([line for line in result.stdout.split("\n") if line.strip()])
207
-
208
- if changes > 0:
209
- return f" | {magenta}{branch}{RESET} {cyan}[{changes}]{RESET}"
210
- return f" | {magenta}{branch}{RESET}"
211
- except (subprocess.TimeoutExpired, OSError):
212
- return ""
213
-
214
-
215
- def read_config():
216
- """Read settings from config file"""
217
- config = {
218
- "autocompact": True,
219
- "token_detail": True,
220
- "show_delta": True,
221
- "show_session": True,
222
- "show_io_tokens": True,
223
- "colors": {},
224
- }
225
- config_path = os.path.expanduser("~/.claude/statusline.conf")
226
-
227
- # Create config file with defaults if it doesn't exist
228
- if not os.path.exists(config_path):
229
- try:
230
- os.makedirs(os.path.dirname(config_path), exist_ok=True)
231
- with open(config_path, "w") as f:
232
- f.write(
233
- """# Autocompact setting - sync with Claude Code's /config
234
- autocompact=true
235
-
236
- # Token display format
237
- token_detail=true
238
-
239
- # Show token delta since last refresh (adds file I/O on every refresh)
240
- # Disable if you don't need it to reduce overhead
241
- show_delta=true
242
-
243
- # Show session_id in status line
244
- show_session=true
245
-
246
- # Custom colors - use named colors or hex (#rrggbb)
247
- # Available: color_green, color_yellow, color_red, color_blue, color_magenta, color_cyan
248
- # Examples:
249
- # color_green=#7dcfff
250
- # color_red=#f7768e
251
- """
252
- )
253
- except Exception as e:
254
- sys.stderr.write(f"[statusline] warning: failed to create config: {e}\n")
255
- return config
256
-
257
- try:
258
- with open(config_path) as f:
259
- for line in f:
260
- line = line.strip()
261
- if line.startswith("#") or "=" not in line:
262
- continue
263
- key, value = line.split("=", 1)
264
- key = key.strip()
265
- raw_value = value.strip()
266
- value_lower = raw_value.lower()
267
- if key == "autocompact":
268
- config["autocompact"] = value_lower != "false"
269
- elif key == "token_detail":
270
- config["token_detail"] = value_lower != "false"
271
- elif key == "show_delta":
272
- config["show_delta"] = value_lower != "false"
273
- elif key == "show_session":
274
- config["show_session"] = value_lower != "false"
275
- elif key == "show_io_tokens":
276
- config["show_io_tokens"] = value_lower != "false"
277
- elif key in _COLOR_KEYS:
278
- ansi = _parse_color(raw_value)
279
- if ansi:
280
- config["colors"][_COLOR_KEYS[key]] = ansi
281
- except (OSError, UnicodeDecodeError) as e:
282
- sys.stderr.write(f"[statusline] warning: failed to read config: {e}\n")
283
- return config
284
-
285
-
286
- def main():
287
- try:
288
- data = json.load(sys.stdin)
289
- except json.JSONDecodeError:
290
- print("[Claude] ~")
291
- return
292
-
293
- # Extract data
294
- cwd = data.get("workspace", {}).get("current_dir", "~")
295
- project_dir = data.get("workspace", {}).get("project_dir", cwd)
296
- model = data.get("model", {}).get("display_name", "Claude")
297
- dir_name = os.path.basename(cwd) or "~"
298
-
299
- # Read settings from config file
300
- config = read_config()
301
- autocompact_enabled = config["autocompact"]
302
- token_detail = config["token_detail"]
303
- show_delta = config["show_delta"]
304
- show_session = config["show_session"]
305
- # Note: show_io_tokens setting is read but not yet implemented
306
-
307
- # Apply color overrides from config
308
- c = config.get("colors", {})
309
- c_green = c.get("green", GREEN)
310
- c_yellow = c.get("yellow", YELLOW)
311
- c_red = c.get("red", RED)
312
- c_blue = c.get("blue", BLUE)
313
- c_magenta = c.get("magenta", MAGENTA)
314
- c_cyan = c.get("cyan", CYAN)
315
-
316
- # Git info (pass configurable colors)
317
- git_info = get_git_info(project_dir, magenta=c_magenta, cyan=c_cyan)
318
-
319
- # Extract session_id once for reuse
320
- session_id = data.get("session_id")
321
-
322
- # Context window calculation
323
- context_info = ""
324
- ac_info = ""
325
- delta_info = ""
326
- session_info = ""
327
- total_size = data.get("context_window", {}).get("context_window_size", 0)
328
- current_usage = data.get("context_window", {}).get("current_usage")
329
- total_input_tokens = data.get("context_window", {}).get("total_input_tokens", 0)
330
- total_output_tokens = data.get("context_window", {}).get("total_output_tokens", 0)
331
- cost_usd = data.get("cost", {}).get("total_cost_usd", 0)
332
- lines_added = data.get("cost", {}).get("total_lines_added", 0)
333
- lines_removed = data.get("cost", {}).get("total_lines_removed", 0)
334
- model_id = data.get("model", {}).get("id", "")
335
- workspace_project_dir = data.get("workspace", {}).get("project_dir", "")
336
-
337
- if total_size > 0 and current_usage:
338
- # Get tokens from current_usage (includes cache)
339
- input_tokens = current_usage.get("input_tokens", 0)
340
- cache_creation = current_usage.get("cache_creation_input_tokens", 0)
341
- cache_read = current_usage.get("cache_read_input_tokens", 0)
342
-
343
- # Total used from current request
344
- used_tokens = input_tokens + cache_creation + cache_read
345
-
346
- # Calculate autocompact buffer (22.5% of context window = 45k for 200k)
347
- autocompact_buffer = int(total_size * 0.225)
348
-
349
- # Free tokens calculation depends on autocompact setting
350
- if autocompact_enabled:
351
- # When AC enabled: subtract buffer to show actual usable space
352
- free_tokens = total_size - used_tokens - autocompact_buffer
353
- buffer_k = autocompact_buffer // 1000
354
- ac_info = f" {DIM}[AC:{buffer_k}k]{RESET}"
355
- else:
356
- # When AC disabled: show full free space
357
- free_tokens = total_size - used_tokens
358
- ac_info = f" {DIM}[AC:off]{RESET}"
359
-
360
- if free_tokens < 0:
361
- free_tokens = 0
362
-
363
- # Calculate percentage with one decimal (relative to total size)
364
- free_pct = (free_tokens * 100.0) / total_size
365
- free_pct_int = int(free_pct)
366
-
367
- # Format tokens based on token_detail setting
368
- if token_detail:
369
- free_display = f"{free_tokens:,}"
370
- else:
371
- free_display = f"{free_tokens / 1000:.1f}k"
372
-
373
- # Color based on free percentage
374
- if free_pct_int > 50:
375
- ctx_color = c_green
376
- elif free_pct_int > 25:
377
- ctx_color = c_yellow
378
- else:
379
- ctx_color = c_red
380
-
381
- context_info = f" | {ctx_color}{free_display} free ({free_pct:.1f}%){RESET}"
382
-
383
- # Calculate and display token delta if enabled
384
- if show_delta:
385
- import glob
386
- import shutil
387
- import time
388
-
389
- state_dir = os.path.expanduser("~/.claude/statusline")
390
- os.makedirs(state_dir, exist_ok=True)
391
-
392
- old_state_dir = os.path.expanduser("~/.claude")
393
- for old_file in glob.glob(os.path.join(old_state_dir, "statusline*.state")):
394
- if os.path.isfile(old_file):
395
- new_file = os.path.join(state_dir, os.path.basename(old_file))
396
- if not os.path.exists(new_file):
397
- shutil.move(old_file, new_file)
398
- else:
399
- os.remove(old_file)
400
-
401
- if session_id:
402
- state_file = os.path.join(state_dir, f"statusline.{session_id}.state")
403
- else:
404
- state_file = os.path.join(state_dir, "statusline.state")
405
- has_prev = False
406
- prev_tokens = 0
407
- try:
408
- if os.path.exists(state_file):
409
- has_prev = True
410
- # Read last line to get previous context usage
411
- with open(state_file) as f:
412
- lines = f.readlines()
413
- if lines:
414
- last_line = lines[-1].strip()
415
- if "," in last_line:
416
- parts = last_line.split(",")
417
- # Calculate previous context usage:
418
- # cur_input + cache_creation + cache_read
419
- # CSV indices: cur_in[3], cache_create[5], cache_read[6]
420
- prev_cur_input = int(parts[3]) if len(parts) > 3 else 0
421
- prev_cache_creation = int(parts[5]) if len(parts) > 5 else 0
422
- prev_cache_read = int(parts[6]) if len(parts) > 6 else 0
423
- prev_tokens = prev_cur_input + prev_cache_creation + prev_cache_read
424
- else:
425
- # Old format - single value
426
- prev_tokens = int(last_line or 0)
427
- except (OSError, ValueError) as e:
428
- sys.stderr.write(f"[statusline] warning: failed to read state file: {e}\n")
429
- prev_tokens = 0
430
- # Calculate delta (difference in context window usage)
431
- delta = used_tokens - prev_tokens
432
- # Only show positive delta (and skip first run when no previous state)
433
- if has_prev and delta > 0:
434
- if token_detail:
435
- delta_display = f"{delta:,}"
436
- else:
437
- delta_display = f"{delta / 1000:.1f}k"
438
- delta_info = f" {DIM}[+{delta_display}]{RESET}"
439
- # Only append if context usage changed (avoid duplicates from multiple refreshes)
440
- if not has_prev or used_tokens != prev_tokens:
441
- # Append current usage with comprehensive format
442
- # Format: ts,total_in,total_out,cur_in,cur_out,cache_create,cache_read,
443
- # cost_usd,lines_added,lines_removed,session_id,model_id,project_dir,
444
- # context_window_size
445
- try:
446
- cur_input_tokens = current_usage.get("input_tokens", 0)
447
- cur_output_tokens = current_usage.get("output_tokens", 0)
448
- state_data = ",".join(
449
- str(x)
450
- for x in [
451
- int(time.time()),
452
- total_input_tokens,
453
- total_output_tokens,
454
- cur_input_tokens,
455
- cur_output_tokens,
456
- cache_creation,
457
- cache_read,
458
- cost_usd,
459
- lines_added,
460
- lines_removed,
461
- session_id or "",
462
- model_id,
463
- workspace_project_dir.replace(",", "_"),
464
- total_size,
465
- ]
466
- )
467
- with open(state_file, "a") as f:
468
- f.write(f"{state_data}\n")
469
- maybe_rotate_state_file(state_file)
470
- except OSError as e:
471
- sys.stderr.write(f"[statusline] warning: failed to write state file: {e}\n")
472
-
473
- # Display session_id if enabled
474
- if show_session and session_id:
475
- session_info = f" {DIM}{session_id}{RESET}"
476
-
477
- # Output: [Model] directory | branch [changes] | XXk free (XX%) [+delta] [AC] [S:session_id]
478
- base = f"{DIM}[{model}]{RESET} {c_blue}{dir_name}{RESET}"
479
- max_width = get_terminal_width()
480
- parts = [base, git_info, context_info, delta_info, ac_info, session_info]
481
- print(fit_to_width(parts, max_width))
482
-
483
-
484
- if __name__ == "__main__":
485
- main()
@@ -1,11 +0,0 @@
1
- """Claude Code Context Stats.
2
-
3
- Never run out of context unexpectedly - monitor your session context in real-time.
4
- """
5
-
6
- __version__ = "1.7.0"
7
-
8
- from claude_statusline.core.config import Config
9
- from claude_statusline.core.state import StateFile
10
-
11
- __all__ = ["__version__", "Config", "StateFile"]
@@ -1,6 +0,0 @@
1
- """Enable running as python -m claude_statusline."""
2
-
3
- from claude_statusline.cli.statusline import main
4
-
5
- if __name__ == "__main__":
6
- main()
@@ -1 +0,0 @@
1
- """CLI entry points for claude-statusline."""