Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@ uv run pytest -m integration # Integration tests only
uv run pytest -m performance # Performance benchmarks (opt-in)

# CLI testing (local development)
uv run claude-statusline # Test with stdin
echo '{"transcript_path": "..."}' | uv run claude-statusline
uv run claude-statusline install # Install local version to Claude Code
uv run claude-statusline doctor # Verify installation health
uv run claude-statusline --version # Show version
uv run claude-code-statusline # Test with stdin
echo '{"transcript_path": "..."}' | uv run claude-code-statusline
uv run claude-code-statusline install # Install local version to Claude Code
uv run claude-code-statusline doctor # Verify installation health
uv run claude-code-statusline --version # Show version

# Installation scripts (for end users)
curl -fsSL https://raw.githubusercontent.com/wpfleger96/claude-code-status-line/main/scripts/install.sh | bash
Expand Down Expand Up @@ -111,10 +111,10 @@ Fixtures in `tests/conftest.py`: `mock_stdin`, `sample_input_payload`, `basic_se

## Common Gotchas

1. **Local dev vs installed tool** - **CRITICAL**: Always use `uv run claude-statusline` when developing locally:
- **Local dev (from repo)**: `uv run claude-statusline <args>` → runs YOUR local code changes
- **Installed tool (any directory)**: `claude-statusline <args>` → runs installed version from `~/.local/share/uv/tools/`
- Running `claude-statusline` without `uv run` will NOT reflect local changes
1. **Local dev vs installed tool** - **CRITICAL**: Always use `uv run claude-code-statusline` when developing locally:
- **Local dev (from repo)**: `uv run claude-code-statusline <args>` → runs YOUR local code changes
- **Installed tool (any directory)**: `claude-code-statusline <args>` → runs installed version from `~/.local/share/uv/tools/`
- Running `claude-code-statusline` without `uv run` will NOT reflect local changes
- **NEVER use editable install** (`uv pip install -e .`) - risks conflicts, unnecessary complexity

2. **Context window priority** (Claude Code 2.0.70+): `context_window` field from payload takes priority over transcript parsing for token counts. Falls back to transcript if `context_window` missing/null. This is the authoritative source.
Expand All @@ -129,7 +129,7 @@ Fixtures in `tests/conftest.py`: `mock_stdin`, `sample_input_payload`, `basic_se

7. **Performance tests opt-in**: Excluded by default. Run with `uv run pytest -m performance`.

8. **Installation scripts handle both uv and pipx**: `scripts/install.sh` checks for uv first, falls back to pipx. Auto-configures Claude Code with `claude-statusline install --yes`.
8. **Installation scripts handle both uv and pipx**: `scripts/install.sh` checks for uv first, falls back to pipx. Auto-configures Claude Code with `claude-code-statusline install --yes`.

9. **Debug logging per-session**: Set `CLAUDE_CODE_STATUSLINE_DEBUG=1` → creates `logs/statusline_debug_<session_id>.log` with token breakdown, compact boundaries, parsing errors.

Expand Down
38 changes: 24 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,20 +59,28 @@ This will:

**Requirements:** Either `uv` or `pipx`

Or, if you have [`uv`](https://docs.astral.sh/uv/), install and configure in a single command:

```bash
uvx claude-code-statusline install
```

This installs the tool persistently (via `uv tool`) and then writes the `statusLine` config to `~/.claude/settings.json`.

### Manual Installation

#### Option 1: Using uv tool

```bash
uv tool install claude-code-statusline
claude-statusline install
claude-code-statusline install
```

#### Option 2: Using pipx

```bash
pipx install claude-code-statusline
claude-statusline install
claude-code-statusline install
```

### Upgrading
Expand All @@ -87,6 +95,8 @@ uv tool upgrade claude-code-statusline
pipx upgrade claude-code-statusline
```

> **Upgrading from a version that used the `claude-statusline` command?** The command was renamed to `claude-code-statusline`. After upgrading, re-run `claude-code-statusline install` to update `~/.claude/settings.json` — your `~/.config` widget config is migrated automatically. If a stale `claude-statusline` command lingers on your `PATH`, run `uv tool uninstall claude-code-statusline` (or `pipx uninstall claude-code-statusline`) and reinstall.

### Uninstalling

To uninstall:
Expand All @@ -96,26 +106,26 @@ To uninstall:
curl -fsSL https://raw.githubusercontent.com/wpfleger96/claude-code-status-line/main/scripts/uninstall.sh | bash

# Or manually
claude-statusline uninstall
claude-code-statusline uninstall
uv tool uninstall claude-code-statusline # or: pipx uninstall claude-code-statusline
```

## CLI Commands

```bash
claude-statusline # Output statusline (reads JSON from stdin)
claude-statusline install # Configure Claude Code integration
claude-statusline uninstall # Remove Claude Code configuration
claude-statusline doctor # Verify installation health
claude-statusline --version # Show version
claude-code-statusline # Output statusline (reads JSON from stdin)
claude-code-statusline install # Configure Claude Code integration
claude-code-statusline uninstall # Remove Claude Code configuration
claude-code-statusline doctor # Verify installation health
claude-code-statusline --version # Show version
```

### Health Check

Verify your installation is working correctly:

```bash
claude-statusline doctor
claude-code-statusline doctor
```

This checks:
Expand All @@ -128,7 +138,7 @@ This checks:

### Widget Customization

Customize your status line by creating `~/.config/claude-statusline/config.yaml`:
Customize your status line by creating `~/.config/claude-code-statusline/config.yaml`:

```yaml
version: 2
Expand Down Expand Up @@ -156,12 +166,12 @@ widgets:
**Color Options:** `white`, `black`, `red`, `green`, `yellow`, `blue`, `magenta`, `cyan`, `dim`, `auto`, `none`

**Default Config:**
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.
If no config file exists, all default widgets are shown with built-in defaults. Create `~/.config/claude-code-statusline/config.yaml` to customize colors, ordering, or disable specific widgets.

## Features

### Customizable Widget System
- **Configurable Layout**: Customize which widgets appear and in what order via `~/.config/claude-statusline/config.yaml`
- **Configurable Layout**: Customize which widgets appear and in what order via `~/.config/claude-code-statusline/config.yaml`
- **Built-in Widgets**: 14 widgets including model, directory, git status, context, cost, session info
- **Flexible Styling**: Per-widget color customization and bold formatting
- **Automatic Fallback**: Missing config uses sensible defaults with all widgets enabled
Expand Down Expand Up @@ -341,14 +351,14 @@ Debug logs are written to **per-session files** in the `logs/` directory:

2. **Configure Claude Code to use local version:**
```bash
uv run claude-statusline install
uv run claude-code-statusline install
```

### Testing Changes

```bash
# Test statusline output
echo '{"workspace": {"current_dir": "/test"}, "transcript_path": "", "model": {"id": "test", "display_name": "Test"}, "cost": {}, "version": "test"}' | uv run claude-statusline
echo '{"workspace": {"current_dir": "/test"}, "transcript_path": "", "model": {"id": "test", "display_name": "Test"}, "cost": {}, "version": "test"}' | uv run claude-code-statusline

# Run test suite
uv run pytest
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Documentation = "https://github.com/wpfleger96/claude-code-status-line#readme"
Changelog = "https://github.com/wpfleger96/claude-code-status-line/blob/main/CHANGELOG.md"

[project.scripts]
claude-statusline = "claude_code_statusline.statusline:main"
claude-code-statusline = "claude_code_statusline.statusline:main"

[dependency-groups]
dev = [
Expand Down
6 changes: 3 additions & 3 deletions scripts/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,10 @@ echo "Package installed successfully!"
echo ""
echo "Configuring Claude Code..."

if ! claude-statusline install --yes; then
if ! claude-code-statusline install --yes; then
echo ""
echo "Error: Configuration failed"
echo "You can try manually running: claude-statusline install"
echo "You can try manually running: claude-code-statusline install"
exit 1
fi

Expand All @@ -58,7 +58,7 @@ echo ""
echo "Next steps:"
echo "1. Restart Claude Code or start a new session"
echo "2. The statusline should appear automatically"
echo "3. Customize via ~/.config/claude-statusline/config.yaml"
echo "3. Customize via ~/.config/claude-code-statusline/config.yaml"
echo ""
echo "For more information, visit:"
echo " https://github.com/wpfleger96/claude-code-status-line"
8 changes: 4 additions & 4 deletions scripts/uninstall.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
set -e

PACKAGE_NAME="claude-code-statusline"
CONFIG_DIR="$HOME/.config/claude-statusline"
CONFIG_DIR="$HOME/.config/claude-code-statusline"

echo "Uninstalling $PACKAGE_NAME..."
echo ""
Expand All @@ -13,17 +13,17 @@ if [ "$1" = "--purge" ]; then
PURGE=1
fi

if command -v claude-statusline &> /dev/null; then
if command -v claude-code-statusline &> /dev/null; then
echo "Removing statusLine configuration..."
if claude-statusline uninstall; then
if claude-code-statusline uninstall; then
echo ""
else
echo "Warning: Failed to remove statusLine configuration"
echo "You may need to manually edit ~/.claude/settings.json"
echo ""
fi
else
echo "claude-statusline command not found"
echo "claude-code-statusline command not found"
echo "Skipping configuration cleanup"
echo ""
fi
Expand Down
2 changes: 1 addition & 1 deletion src/claude_code_statusline/cli/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""CLI commands for claude-statusline."""
"""CLI commands for claude-code-statusline."""

from .commands import cmd_doctor, cmd_install, cmd_uninstall

Expand Down
49 changes: 49 additions & 0 deletions src/claude_code_statusline/cli/bootstrap.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
"""Persistent-install bootstrap for the statusline command.

When invoked ephemerally (e.g. ``uvx claude-code-statusline install``) the console
script is not on the user's PATH, so the ``statusLine`` command written into
settings.json would point at a missing binary. ``ensure_command_installed`` installs
the tool persistently (via ``uv tool`` or ``pipx``) before Claude Code is configured,
mirroring the detection in scripts/install.sh.
"""

import shutil
import subprocess

NAME = "claude-code-statusline"


def ensure_command_installed() -> tuple[bool, str]:
"""Ensure the ``claude-code-statusline`` command is persistently on PATH.

Returns a ``(ok, message)`` pair. ``ok`` is False only for hard failures (no
installer found, or the install command failed); callers should abort before
writing settings.json. A successful no-op returns ``(True, "")``. If the tool
was installed but is not yet visible on PATH, returns ``(True, warning)`` so the
caller can still write the config (a fresh shell/session resolves it).
"""
if shutil.which(NAME):
return True, ""

if shutil.which("uv"):
installer, command = "uv", ["uv", "tool", "install", NAME]
elif shutil.which("pipx"):
installer, command = "pipx", ["pipx", "install", NAME]
else:
return False, (
f"'{NAME}' is not on PATH and neither 'uv' nor 'pipx' was found.\n"
f"Install uv (https://astral.sh/uv) or run: pipx install {NAME}"
)

print(f"Installing {NAME} with {installer}...")
try:
subprocess.run(command, check=True)
except (subprocess.CalledProcessError, OSError) as e:
return False, f"Failed to install {NAME} via {installer}: {e}"

if shutil.which(NAME):
return True, f"Installed {NAME} via {installer}."
return True, (
f"Installed {NAME} via {installer}, but '{NAME}' is not yet on PATH. "
f"Restart your shell (or run 'uv tool update-shell') so Claude Code can find it."
)
Loading