Take upstream changes#1
Open
simoncoles wants to merge 164 commits into
Open
Conversation
Add modern Python packaging with uv tool installation support: - Add pyproject.toml with console script entry points (ccusage-monitor, claude-monitor) - Update README.md to prioritize uv installation over legacy methods - Add CLAUDE.md development documentation - Add comprehensive .gitignore for Python project Users can now install with: uv tool install claude-usage-monitor Maintains full backwards compatibility with existing installation methods
Update installation docs to use local directory instead of PyPI: - Change from 'uv tool install claude-usage-monitor' to 'uv tool install .' - Add git clone step since package not yet published to PyPI - Clarify platform-specific uv installation commands Fixes installation errors for users trying to install from PyPI
feat: add uv package manager support
- Add comprehensive .ruff.toml configuration with essential linting rules - Set up pre-commit hooks for automated code quality checks - Create GitHub Actions CI workflow for ruff validation - Configure VS Code settings for real-time ruff integration - Format existing codebase to comply with ruff standards - Update documentation with ruff usage instructions - Update Python requirement from 3.6+ to 3.7+ (ruff minimum) - Replace outdated tools (black, flake8) with modern ruff tooling Resolves #15
feat: integrate ruff for code quality and formatting
Information about CLAUDE_CONFIG_DIR added
Update README.md with CLAUDE_CONFIG_DIR path
Hi there, I noticed that many popular open-source projects include a star history chart in their README to visualize community growth and engagement. I thought it would be a great addition to this project as well. This PR adds a dynamic Star History chart to the end of the `README.md`.
Docs: Add Star History chart to README.md
Uv refactor
New CLI flag to hide the model distribution bar in the live view. Threaded as a pydantic Settings field through to_namespace and the display controller; both render sites (Model Distribution and Model Usage) honor it. Closes #161
Two new CLI flags for the live view: --no-header hides the header banner, --no-emoji renders plain output with emoji stripped. Implemented as positive pydantic Settings fields (header/emoji, default on) so pydantic-settings' BooleanOptionalAction generates the --no-* forms; mapped to the renderer through the display controller. Closes #57
The opus family fallback was $15/$75 (Opus-3 era), so current Opus 4.5+ usage was billed 3x too high, and Haiku 4.5 was billed at the old $0.25 Haiku-3 rate. Family fallbacks now reflect current rates (Opus $5/$25, Haiku $1/$5, Sonnet $3/$15, Fable 5 $10/$50); models priced differently by version (Opus 3/4.0/4.1, Haiku 3/3.5) are pinned as explicit overrides. Rates verified against Anthropic's published pricing. Closes #182
- settings: recognize the --flag=value form so an explicit --plan=pro is no longer overwritten by a saved last_used.json plan (regression from persisting plan). - settings: persist the 'auto' theme intent instead of the resolved light/dark value, so background auto-detection keeps running on each launch (the 'light/jasna' fix). - pricing: price the claude-opus-4-1 / claude-opus-4-0 aliases as legacy ($15/$75) instead of falling through to the current $5/$25 Opus rate. - cli: include CLAUDE_CONFIG_DIR-derived paths in the no-data diagnostic so the configured location is shown.
One-shot machine-readable usage output for hooks/CI/companions: --once measures usage once, prints a versioned snapshot (schema_version/source/confidence/limits/local/local_history/forecast, all local_estimate), and exits with automation codes (0/10/11/20/30). New output/snapshots.py is the single shared builder (#184 --write-state will reuse it) plus json/text formatters; the limits block mirrors the official statusline rate_limits shape so the trust keystone can fill it later without breaking consumers. Hardened via a Codex (xhigh) adversarial review: forecast now uses an input+output burn rate matching tokens_remaining (was dimensionally invalid against the cache-inclusive rate), exit codes use the raw unrounded ratio, no-limit reports indeterminate, --custom-limit-tokens is honored, seven_day is no longer mislabeled with the local window sum, and tokenCounts=None no longer crashes. Closes #126
New --write-state flag writes the same versioned snapshot (the one-shot builder) to a state file companions can poll — default ~/.claude-monitor/state/latest.json, override with --state-file. Writes are atomic (temp file + os.replace) so a reader never sees a partial file, and the parent directory is created. Wired into both the live loop (every refresh) and one-shot mode; a write failure is logged and never breaks monitoring. Closes #184
Adds --compact for tmux/status-bar use: one line with usage percent, tokens used/limit, burn rate, reset time, and session cost. Works both live (updates in place) and one-shot via --once, built from the same snapshot as --once so the numbers never diverge from the full views. Also resolve the displayed token limit through a single helper so an explicit --custom-limit-tokens is honored in the live loop too, not just one-shot; previously the orchestrator's P90 recalculation masked it.
v4.0.0 feat: usage ops protocol, trust layer, and warehouse
Adds a Claude Code statusline hook (`claude-monitor --statusline`) that reads the session JSON on stdin, captures the official rate_limits (5h/7d used_percentage + resets_at) to ~/.claude-monitor/statusline/latest.json, and prints a one-line status. When a capture is present the snapshot uses the official percentage and reset as the source of truth (confidence: official) and the five-hour figure drives the --once exit code; without it every number stays a labeled local estimate. Guards the known leak where used_percentage can carry the reset epoch, drops a window once its reset has passed, tombstones the capture when rate_limits disappears (plan downgrade), and keeps the hook crash-proof since it runs on every status refresh.
The --reset-hour flag was accepted, validated, and persisted but never read by any calculation. Wire it into the daily/monthly aggregator so the usage day rolls over at the chosen hour (e.g. --reset-hour 4 counts 02:00 toward the previous day) instead of always at midnight. It intentionally does not move the rolling 5-hour window, whose reset comes from the session or official data.
When a session block contains a rate-limit message with a reset time, prefer it over the start-plus-5h estimate for the displayed reset, so the reset matches what Claude actually told the user. Carried on SessionBlock as usage_limit_reset_time and emitted as usageLimitResetTime; the snapshot prefers it for the local five-hour window, while official statusline limits still win. Also fix the epoch parser: a numeric 'limit reached|<epoch>' timestamp was read as local wall time and then labeled UTC, shifting the reset by the host offset on non-UTC machines. Epochs are absolute instants and are now parsed as UTC.
…te data - A stale official capture (older than the freshness TTL) no longer drives the exit status, confidence label, or display as current truth; it falls back to the local estimate with the stale flag kept only as a transparency signal. Previously only an expired window was guarded, so a stale-but-unreset capture at 96% still showed up as official truth. - An official percentage now drives the exit status even when there is no local active block: a 98% official reading reports near_limit instead of being masked as 'no active session'. - Non-finite values (JSON permits NaN/Infinity) in resets_at, captured_at, or used_percentage are rejected rather than crashing the reader or rendering as a real percentage; the --json output uses allow_nan=False so it can never emit invalid JSON to a consumer.
Models routed through Claude Code Router (e.g. GPT or DeepSeek) were falling through the pricing fallback to the Sonnet rate, inflating reported cost with a fabricated Claude price. A model that is not recognizably Anthropic now resolves to an explicit unknown (/usr/bin/zsh) price instead; unknown but clearly-Claude models still use the family fallback. Also backfills the changelog for the prior official-limit hardening.
--filter-models anthropic drops entries for non-Claude models (e.g. GPT or DeepSeek routed through Claude Code Router) at the single load chokepoint, so they no longer count toward the Claude session's tokens, cost, or limit. It is threaded through the live, one-shot, P90, and daily/monthly paths and defaults to 'all' (no change). The predicate matches on claude/anthropic only, so a foreign name like gpt-4-opus is not mistaken for Claude. Also fix the daily reset boundary to honor the configured timezone: --reset-hour is a local-time concept, so the rollover is now computed in the display timezone rather than raw UTC.
local_history.total_tokens summed the per-block display-utilization value (input + output only), so cache-heavy sessions were undercounted and disagreed with local.tokens.total_tokens. Sum the cache-inclusive token counts instead. Also make the environment-abort test patch through the imported module object rather than the dotted string: claude_monitor.cli.main is shadowed by the main function, so the string form resolves to the function (not the module) under Python 3.9/3.10's mock and raised AttributeError.
pre-commit-uv's uv-created hook environments fail pre-commit's virtualenv health check on Python patch versions (the runner reports 3.9.25 where 3.9 is expected), failing the Pre-commit job for an environment reason unrelated to the hooks. Drop the accelerator so pre-commit uses the standard virtualenv backend; all hooks still run and pass.
- state file: write to a pid-unique temp so concurrent writers can't clobber it. - official reader: expire a window at the reset instant (>=, not >), and guard capture_statusline against a non-object stdin payload. - snapshot: emit tokens_used=null (not 0) when there is no active session, since utilization is unknown. - limit reset: take the reset from the most recent limit message (latest timestamp), not the largest reset value. - live loop: fall back to the last known token limit when the monitor reports token_limit as an explicit null. - text protocol: escape control characters so a value with a newline cannot split into a second, malformed key=value line. - one-shot --write-state: surface a failed write (exit 30) instead of silently swallowing it; the live loop still ignores transient write errors. - no-active-session screen now honors --no-header and --no-emoji.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.