Skip to content

Commit ea99ba3

Browse files
authored
refactor: remove dead code, deprecated v1 schema, and fix stale docs (#6)
* refactor: remove dead code, deprecated v1 schema, and fix stale docs Remove 4 dead functions from legacy character-based parser (jsonl.py), dead get_all_widgets(), 8 dead dataclass fields across TokenMetrics/ ContextWindow/RenderContext, deprecated StatusLineConfig v1 schema class, and 2 dead constants. Simplify vestigial UUID guard in debug.py. Fix extensive README/AGENTS.md documentation rot: remove nonexistent subscription widget, calibration tool section, v1 config examples, and stale field/worker claims. Consolidate script/ into scripts/. * fix: address review feedback on dead code cleanup Fix benchmark.sh self-references after script→scripts rename. Strengthen test assertions for image token counting and compact boundary behavior. * fix: add PSR build_command to sync lockfile on release
1 parent 9ac5564 commit ea99ba3

22 files changed

Lines changed: 91 additions & 443 deletions

AGENTS.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,9 @@ tests/
9090

9191
**Widget System**: All widgets extend `Widget` base class with `render(context: RenderContext) -> Optional[str]`. Register with `@register_widget(display_name, default_color, description, fallback_text)`.
9292

93-
**RenderContext**: Dataclass passed to all widgets containing `data`, `token_metrics`, `git_status`, `session_metrics`, `subscription_info`, `context_window`.
93+
**RenderContext**: Dataclass passed to all widgets containing `data`, `token_metrics`, `git_status`, `duration_seconds`, `terminal_width`, `context_window`.
9494

95-
**Parallel I/O**: `statusline.py` uses `ThreadPoolExecutor(max_workers=3)` for transcript parsing, subscription loading, and model prefetch.
95+
**Parallel I/O**: `statusline.py` uses `ThreadPoolExecutor(max_workers=2)` for transcript parsing and model prefetch.
9696

9797
**Config Caching**: `config/loader.py` caches config files by mtime to avoid re-reading unchanged files.
9898

@@ -141,7 +141,7 @@ Fixtures in `tests/conftest.py`: `mock_stdin`, `sample_input_payload`, `basic_se
141141
| Modify token counting | `parsers/tokens.py`, `tests/unit/test_token_counting.py` |
142142
| Context window handling | `types.py`, `statusline.py`, `utils/models.py`, `tests/unit/test_context_window.py` |
143143
| Status line rendering | `renderer.py`, `config/defaults.py` |
144-
| Config schema changes | `config/schema.py`, `config/loader.py`, `tests/integration/test_config.py` |
144+
| Config schema changes | `config/schema.py`, `config/loader.py`, `tests/integration/test_config_system.py` |
145145
| CLI commands (install/doctor) | `cli/commands.py`, `statusline.py` (argparse setup) |
146146
| Git status display | `utils/git.py`, `widgets/builtin/git.py` |
147147
| Installation automation | `scripts/install.sh`, `scripts/uninstall.sh` |

README.md

Lines changed: 19 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -131,25 +131,20 @@ This checks:
131131
Customize your status line by creating `~/.config/claude-statusline/config.yaml`:
132132

133133
```yaml
134-
version: 1
135-
lines:
136-
- - type: model
137-
color: cyan
138-
- type: separator
139-
- type: directory
140-
color: blue
141-
- type: separator
142-
- type: git-branch
143-
color: magenta
144-
- type: separator
145-
- type: context-percentage
146-
color: auto # auto-colors based on usage
147-
- type: separator
148-
- type: cost
149-
color: auto # auto-colors based on amount
150-
- type: separator
151-
- type: session-clock
152-
color: white
134+
version: 2
135+
widgets:
136+
model:
137+
color: cyan
138+
directory:
139+
color: blue
140+
git-branch:
141+
color: magenta
142+
context-percentage:
143+
color: auto # auto-colors based on usage
144+
cost:
145+
color: auto # auto-colors based on amount
146+
session-clock:
147+
color: white
153148
```
154149
155150
**Widget Options:**
@@ -160,15 +155,8 @@ lines:
160155

161156
**Color Options:** `white`, `black`, `red`, `green`, `yellow`, `blue`, `magenta`, `cyan`, `dim`, `auto`, `none`
162157

163-
**Auto-Generated Config:**
164-
If no config file exists, one is automatically created with all widgets enabled. Delete `~/.config/claude-statusline/config.yaml` to regenerate defaults.
165-
166-
**Stale Config Warning:**
167-
When new widgets are added, the script warns you:
168-
```
169-
Warning: Config is missing widgets from defaults: session-clock.
170-
Delete ~/.config/claude-statusline/config.yaml to regenerate with new defaults.
171-
```
158+
**Default Config:**
159+
If no config file exists, all default widgets are shown with built-in defaults. Create `~/.config/claude-statusline/config.yaml` to customize colors, ordering, or disable specific widgets.
172160

173161
## Features
174162

@@ -177,11 +165,9 @@ Delete ~/.config/claude-statusline/config.yaml to regenerate with new defaults.
177165
- **Built-in Widgets**: 14 widgets including model, directory, git status, context, cost, session info
178166
- **Flexible Styling**: Per-widget color customization and bold formatting
179167
- **Automatic Fallback**: Missing config uses sensible defaults with all widgets enabled
180-
- **Stale Config Detection**: Warns when config is missing newly-added widgets
181168

182169
**Available Widgets:**
183170
- `model` - Claude model name (e.g., "Sonnet 4.5")
184-
- `subscription` - Subscription type (Pro/Max) or API usage indicator
185171
- `directory` - Current working directory
186172
- `git-branch` - Active git branch name
187173
- `git-changes` - Staged/unstaged changes count
@@ -207,7 +193,6 @@ Delete ~/.config/claude-statusline/config.yaml to regenerate with new defaults.
207193
- **Priority-Based Sources**: Prefers `context_window` payload data → transcript parsing → model lookups
208194
- **Session Metrics**: Continues parsing transcripts for session duration and compact boundary detection
209195
- **Backwards Compatible**: Gracefully handles missing or null `context_window` data from older Claude Code versions
210-
- **Calibration Tool**: Includes `calibrate_token_counting.py` to validate and improve accuracy
211196

212197
### Token Calculation
213198

@@ -343,60 +328,6 @@ Debug logs are written to **per-session files** in the `logs/` directory:
343328

344329
---
345330

346-
## Token Counting Calibration Tool
347-
348-
The project includes `claude-calibrate`, a command-line tool to verify and improve token counting accuracy against Claude's official measurements.
349-
350-
### Purpose
351-
- Compare script calculations against Claude's official `/context` command output
352-
- Identify discrepancies and suggest calibration factors
353-
- Validate token counting accuracy when new Claude Code versions are released
354-
355-
### Usage
356-
357-
#### Semi-Automated Mode (Default)
358-
```bash
359-
uv run --no-config claude-calibrate session1.jsonl session2.jsonl --verbose
360-
```
361-
The tool provides precise instructions for resuming each session and prompts you to enter the official token counts.
362-
363-
#### Manual Override Mode
364-
```bash
365-
uv run --no-config claude-calibrate session1.jsonl session2.jsonl \
366-
--known-tokens 17.5k 68k --verbose
367-
```
368-
Provide known token counts to skip automatic session resumption (useful for sessions that can't be resumed).
369-
370-
#### Auto-Discovery Mode
371-
```bash
372-
uv run --no-config claude-calibrate --max-sessions 3 --verbose
373-
```
374-
Automatically finds recent session files from all Claude Code project directories and provides instructions for manual calibration.
375-
376-
### Example Calibration Report
377-
```
378-
📊 Successfully calibrated 2 session(s)
379-
380-
INDIVIDUAL RESULTS:
381-
❌ session1.jsonl: Script 46,520 vs Claude 68,000 tokens (+31.6% difference)
382-
✅ session2.jsonl: Script 17,470 vs Claude 17,500 tokens (+0.2% difference)
383-
384-
SUMMARY:
385-
Average discrepancy: +15.9% | Suggested calibration factor: 1.231
386-
⚠️ Token counting has moderate accuracy - consider adjusting CHARS_PER_TOKEN ratio
387-
```
388-
389-
### Features
390-
- **Auto-discovery**: Finds recent sessions from all Claude Code project directories
391-
- **Semi-automated**: Provides precise resumption instructions for manual token collection
392-
- **Directory decoding**: Handles hyphenated paths (`-Users-name-Project``/Users/name/Project`)
393-
- **Flexible input**: Accepts raw numbers, K-suffixed values, or full `/context` output
394-
- **Accuracy validation**: Compares against Claude's official measurements
395-
- **Calibration recommendations**: Suggests specific improvements and correction factors
396-
- **uv compatibility**: Uses `uv run` for portable execution across Python environments
397-
398-
---
399-
400331
## Development
401332

402333
### Setup
@@ -405,19 +336,19 @@ Average discrepancy: +15.9% | Suggested calibration factor: 1.231
405336
```bash
406337
git clone https://github.com/wpfleger96/claude-code-status-line.git
407338
cd claude-code-status-line
408-
uv sync --no-config
339+
uv sync
409340
```
410341

411342
2. **Configure Claude Code to use local version:**
412343
```bash
413-
uv run --no-config claude-statusline install
344+
uv run claude-statusline install
414345
```
415346

416347
### Testing Changes
417348

418349
```bash
419350
# Test statusline output
420-
echo '{"workspace": {"current_dir": "/test"}, "transcript_path": "", "model": {"id": "test", "display_name": "Test"}, "cost": {}, "version": "test"}' | uv run --no-config claude-statusline
351+
echo '{"workspace": {"current_dir": "/test"}, "transcript_path": "", "model": {"id": "test", "display_name": "Test"}, "cost": {}, "version": "test"}' | uv run claude-statusline
421352

422353
# Run test suite
423354
uv run pytest

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ branch = "main"
5454
commit_parser = "conventional"
5555
commit_message = "chore(release): {version}"
5656
allow_zero_version = true
57+
build_command = "uv sync"
5758

5859
[tool.semantic_release.commit_parser_opts]
5960
allowed_types = ["feat", "fix", "chore", "ci", "docs", "style", "refactor", "test"]
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,10 @@ Commands:
5656
help - Show this help message
5757
5858
Typical workflow:
59-
1. ./script/benchmark.sh save # Initial baseline
59+
1. ./scripts/benchmark.sh save # Initial baseline
6060
2. [make changes]
61-
3. ./script/benchmark.sh compare # See if faster (iterate)
62-
4. ./script/benchmark.sh record # Save the good result
61+
3. ./scripts/benchmark.sh compare # See if faster (iterate)
62+
4. ./scripts/benchmark.sh record # Save the good result
6363
EOF
6464
;;
6565
esac
Lines changed: 13 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,17 @@
11
"""Default configuration for Claude Code Status Line."""
22

3-
from .schema import StatusLineConfig, WidgetConfigModel
3+
from .schema import WidgetConfigModel
44

55

6-
def get_default_config() -> StatusLineConfig:
7-
"""Generate the default status line configuration."""
8-
return StatusLineConfig(
9-
version=1,
10-
lines=[
11-
[
12-
WidgetConfigModel(type="model", color="cyan"),
13-
WidgetConfigModel(type="separator"),
14-
WidgetConfigModel(type="directory", color="blue"),
15-
WidgetConfigModel(type="separator"),
16-
WidgetConfigModel(type="git-branch", color="magenta"),
17-
WidgetConfigModel(type="separator"),
18-
WidgetConfigModel(type="context-percentage"),
19-
WidgetConfigModel(type="separator"),
20-
WidgetConfigModel(type="cost"),
21-
WidgetConfigModel(type="separator"),
22-
WidgetConfigModel(type="lines-changed"),
23-
WidgetConfigModel(type="separator"),
24-
WidgetConfigModel(type="session-id"),
25-
WidgetConfigModel(type="separator"),
26-
WidgetConfigModel(type="session-clock"),
27-
]
28-
],
29-
)
6+
def get_default_widgets() -> list[WidgetConfigModel]:
7+
"""Return the default ordered widget list (separators excluded)."""
8+
return [
9+
WidgetConfigModel(type="model", color="cyan"),
10+
WidgetConfigModel(type="directory", color="blue"),
11+
WidgetConfigModel(type="git-branch", color="magenta"),
12+
WidgetConfigModel(type="context-percentage"),
13+
WidgetConfigModel(type="cost"),
14+
WidgetConfigModel(type="lines-changed"),
15+
WidgetConfigModel(type="session-id"),
16+
WidgetConfigModel(type="session-clock"),
17+
]

src/claude_code_statusline/config/loader.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
from pydantic import ValidationError
1111

12-
from .defaults import get_default_config
12+
from .defaults import get_default_widgets
1313
from .schema import StatusLineConfigV2, WidgetConfigModel, WidgetOverride
1414

1515
_cached_config: Optional[StatusLineConfigV2] = None
@@ -92,20 +92,20 @@ def get_effective_widgets() -> list[WidgetConfigModel]:
9292
List of widgets with separators interleaved, ready for rendering
9393
"""
9494
config = load_config_file()
95-
defaults = get_default_config()
95+
default_widgets = get_default_widgets()
9696

9797
if config.order:
9898
widget_types = config.order
9999
else:
100-
widget_types = [w.type for w in defaults.lines[0] if w.type != "separator"]
100+
widget_types = [w.type for w in default_widgets]
101101

102102
widgets = []
103103
for wtype in widget_types:
104104
override = config.widgets.get(wtype, WidgetOverride())
105105
if not override.enabled:
106106
continue
107107

108-
default = next((w for w in defaults.lines[0] if w.type == wtype), None)
108+
default = next((w for w in default_widgets if w.type == wtype), None)
109109
if default:
110110
widget = default.model_copy()
111111
if override.color:

src/claude_code_statusline/config/schema.py

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,6 @@ class WidgetConfigModel(BaseModel):
1717
metadata: dict[str, str] = Field(default_factory=dict)
1818

1919

20-
class StatusLineConfig(BaseModel):
21-
"""Complete status line configuration (v1 - deprecated)."""
22-
23-
version: int = 1
24-
lines: list[list[WidgetConfigModel]] = Field(default_factory=list)
25-
26-
model_config = {"extra": "forbid"}
27-
28-
2920
class WidgetOverride(BaseModel):
3021
"""Override settings for a single widget."""
3122

0 commit comments

Comments
 (0)