Feat/usage command - #500
Closed
shidevil wants to merge 19 commits into
Closed
Conversation
…viders Adds tokscale usage CLI command and TUI tab for monitoring subscription quotas across Claude, Codex, and Z.ai. Supports --json and --light output modes, token refresh, and keychain credential fallback. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…odule directory Refactor usage.rs into commands/usage/ directory with per-provider modules for better maintainability. Add four new subscription quota providers: - Amp: reads API key from ~/.local/share/amp/secrets.json, parses displayText from ampcode.com/api/internal - GitHub Copilot: reads token from macOS keychain or ~/.config/gh/hosts.yml, fetches quota from api.github.com/copilot_internal/user - Kimi: reads OAuth credentials from ~/.kimi/credentials/kimi-code.json, fetches usage from api.kimi.com/coding/v1/usages with token refresh - MiniMax: reads API key from MINIMAX_API_KEY env var, fetches from api.minimax.io/v1/api/openplatform/coding_plan/remains Update README.md with subscription usage documentation and provider table. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
current_interval_usage_count is a remaining count despite its name. Prefer explicit current_interval_used_count when available, and treat usage_count as remaining in the fallback path. Also adds: - remains_time fallback for reset timestamps - data-level plan fields (data.current_subscribe_title, data.plan_name) - Plan inference that divides total by MODEL_CALLS_PER_PROMPT (15) - Separate is_auth_error() detection (status 1004) - epoch_to_ms() helper for proper timestamp normalization - normalize_plan_name() that strips "MiniMax Coding Plan" prefix Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The OAuth server rotates refresh tokens on each refresh, but the old code only updated the in-memory access_token and discarded the new refresh_token/expires_in from the response. This meant the on-disk refresh token would go stale after one rotation, forcing re-login. Add save_credentials() that writes the full credential JSON back to ~/.kimi/credentials/kimi-code.json after a successful token refresh. Both the proactive (near-expiry) and reactive (401 fallback) refresh paths now persist the updated tokens. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The gh CLI supports GH_CONFIG_DIR to override its config directory, but read_token_from_hosts() hardcoded ~/.config/gh/hosts.yml. Users with a custom GH_CONFIG_DIR would fail to find the token. Extract gh_config_dir() that checks GH_CONFIG_DIR first, then falls back to ~/.config/gh — matching the gh CLI own resolution logic. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…ng it The usage command accepted the global --home flag but did nothing with it, silently ignoring the override. Add reject_unsupported_home_override() to match the pattern used by other commands that don't support --home. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…OME/keychain read_credentials() accepted the first file with any tokens value, even if access_token was null inside. This meant a stale primary auth file (Codex nulls out access_token when switching to keyring storage) would prevent falling back to a valid secondary one. Now only accepts a credential source if tokens.access_token is present. Also adds: - CODEX_HOME env var as first path to check (matches Codex CLI) - macOS keychain fallback for service "Codex Auth" (matches openusage) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1. README: correct tab count from 6 to 7, remove non-existent 1-6 numeric shortcut claim 2. app.rs tests: update tab assertions for 7 tabs (Usage added at index 1), fixing test_tab_all/next/prev expectations 3. usage.rs: add empty-state rendering so a successful no-data fetch shows "No subscription data available" instead of the loading prompt 4. helpers.rs: guard read_keychain with cfg!(not(target_os = "macos")) so it fails cleanly on non-macOS instead of spawning a missing binary 5. kimi.rs + codex.rs: use reqwest .form() for OAuth refresh payloads instead of manual string formatting, ensuring proper URL encoding of refresh tokens that may contain reserved characters 6. copilot.rs: fix hosts.yml parsing to handle other fields (user, git_protocol) appearing before oauth_token under github.com: — only exit the section on a non-indented top-level key All 451 tests pass. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Previously fetch_all() tried all 7 providers sequentially, causing slow tab switches and noisy error messages for providers the user does not have credentials for. Add has_credentials() fast local checks to each provider (file exists, env var set, keychain lookup) that skip providers entirely when no credentials are on disk. Active providers now run in parallel via std::thread::scope, so multiple providers fetch simultaneously. Also fix remaining tab navigation tests (backtab, left/right) that missed the Usage tab insertion. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Subscription usage now persists to the same cache directory as other TUI data (~/.cache/tokscale/subscription-usage-cache.json). On startup the cached data is loaded instantly, making the Usage tab appear immediately on first switch. A fresh fetch is triggered when the cache is older than 5 minutes or when the user presses u/r to refresh. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…column Rename Monthly to Weekly and Web Searches to Web Search. Collect metrics into named variables instead of pushing in API order, so the output is always Session → Weekly → Web Search regardless of API response ordering. Widen label column to 14 chars for cleaner bar alignment across all providers. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Persist OAuth refresh tokens to disk (Claude, Codex, Kimi) - Atomic credential writes with 0o600 permissions - Fix copilot has_credentials() to properly parse hosts.yml - Fix copilot percent_remaining to use f64 not i64 - Fix minimax epoch_to_ms() heuristic for 2026 timestamps - Add is_finite() guards on f64 arithmetic (amp.rs) - Make helpers module public for TUI import - Remove duplicate helpers from tui/ui/usage.rs - Remove eprintln! error spam from worker threads - Add provider name header + truncation to light-mode cards - Fix README Usage tab shortcut instruction - Make TUI tests hermetic (skip real cache in test builds) - Remove auto-fetch on tab switch (cache + u key) - Clear cache when fetch returns empty results - Fix codex CredentialSource Copy derive (PathBuf not Copy) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Move atomic_write_secret to shared helpers with mode(0o600) at open time (P1) - Add temp file cleanup on rename failure - Check Amp ok field instead of silently returning empty metrics - Persist Codex access token even when no new refresh token returned - Fix TUI empty state to distinguish never-fetched from fetched-empty - Fix truncate() off-by-one with ellipsis - Fix light-mode card width consistency across header/metrics/border - Deduplicate copilot hosts.yml parsing into shared helper Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Pressing 'u' now spawns fetch_all() on a background thread and shows a spinner while waiting, instead of blocking the event loop. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Switch all 7 providers to current-thread Tokio runtime to reduce thread count when fetched in parallel - Claude: fallback from stale/corrupt credentials file to keychain - Claude: always persist refreshed tokens (not just file-sourced) - atomic_write_secret: use PID-scoped temp file to avoid concurrent write collisions Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The reactive retry path was using the original cached refresh token instead of the freshly rotated one from the proactive refresh. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Kimi: use window duration metadata instead of index for labels - Kimi: include label in dedup key to avoid collapsing distinct windows - TUI: handle Disconnected from background fetch thread (prevents stuck spinner) - Copilot: compute pct from remaining/entitlement when percent_remaining missing - Light-mode: truncate metric labels to prevent column overflow Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
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.
Summary by cubic
Adds a
tokscale usagecommand and a TUI Usage tab to show live subscription quotas across providers, with fast loads via caching and parallel fetching.New Features
tokscale usagewith--jsonand--light.u/rto refresh; loads from~/.cache/tokscale/subscription-usage-cache.json(5‑min TTL).commands/usage/module per provider, background fetch in TUI, parallel requests, light-mode card output.Bug Fixes
current_interval_usage_countas remaining; prefercurrent_interval_used_count; better reset time handling and plan inference.GH_CONFIG_DIR; robusthosts.ymlparsing; compute percent from remaining/entitlement; support Windows/XDG paths.rrefresh includes Usage; reject unsupported--home; Z.ai metrics ordered and relabeled.Written for commit dcf8c25. Summary will update on new commits.