Claude/amazing hawking l nqgk#2292
Open
Srimi1 wants to merge 6 commits into
Open
Conversation
Adds `ruflo usage` (also `claude-flow usage`) which surfaces Claude's
"Plan usage limits" in the terminal: current 5-hour session utilization
with time-to-reset, plus weekly all-models / Sonnet-only windows — the
same data Claude Code's `/usage` shows.
Auth reuses Claude Code's existing login (no separate sign-in): the OAuth
token is resolved from CLAUDE_CODE_OAUTH_TOKEN, the macOS Keychain
("Claude Code-credentials"), or ~/.claude/.credentials.json (honoring
CLAUDE_CONFIG_DIR). The token is never logged, printed, or cached.
Data comes from the undocumented GET /api/oauth/usage endpoint, which
rate-limits aggressively, so results are cached for ~180s under
.claude-flow/usage/cache.json and a 429/network failure falls back to the
last-good cached value flagged stale. Friendly messages cover the
not-logged-in and expired-token cases.
- src/usage/credentials.ts — OAuth token resolution (env/keychain/file)
- src/usage/client.ts — fetch + cache + error mapping
- src/commands/usage.ts — usageCommand + pure render helpers
- commands/index.ts — register lazy loader + help category
- __tests__/usage.test.ts — 16 unit tests (mocked fetch + creds)
https://claude.ai/code/session_01U9qENP4GeE5Fx8LUzGKziC
Adds a "Plan usage limits" section to the generated statusline
(.claude/helpers/statusline.cjs) — current 5-hour session + weekly
windows rendered as colored bars with % used and time-to-reset,
appended after the AgentDB line:
Current session [███████░░░░░░░░░░░░░] 33% used · resets in 1h 59m
Weekly (all) [████████░░░░░░░░░░░░] 41% used · resets in 3d 23h
Updated just now
Data source (no token, no network — the statusline re-renders often):
1. Claude Code's documented `rate_limits` stdin field (v2.1.80+):
used_percentage + resets_at (epoch seconds) → footer "Updated just now"
2. fallback to the cache written by `ruflo usage`
(.claude-flow/usage/cache.json) → footer "Updated Xm ago (cached)"
Bars are color-coded (green <50%, yellow 50-75%, red >=75%) and the
Sonnet/Opus weekly windows render when present. The section is hidden
when no usage data is available, or via RUFLO_STATUSLINE_HIDE_USAGE
(mirrors the existing RUFLO_STATUSLINE_HIDE_COST toggle).
- src/init/statusline-generator.ts — usage readers + bar renderer + CONFIG toggle
- .claude/helpers/statusline.cjs — regenerated artifact (drift guard byte-match)
- __tests__/statusline-usage-display.test.ts — 8 tests (live/cache/hidden/absent)
https://claude.ai/code/session_01U9qENP4GeE5Fx8LUzGKziC
…count, test env - client.ts: getUsage() now only falls back to cache for transient failures (network / rate_limited). Unauthenticated and other HTTP/parse errors rethrow so a revoked/expired token surfaces instead of showing stale usage. Matches the documented "fallback on network/429" contract. - credentials.ts: omit the `-a` account filter in the macOS Keychain lookup when $USER/$LOGNAME are unset, so `security` still matches in sanitized envs (launchd, some CI shells) instead of querying `-a ""`. - usage.test.ts: restore process.env by mutating keys (delete added + Object.assign snapshot) instead of replacing the object; add a test asserting 401 rethrows rather than serving stale cache. https://claude.ai/code/session_01U9qENP4GeE5Fx8LUzGKziC
… nits) - client.ts / commands/usage.ts: add JSDoc to the remaining undocumented helpers, types, and the UsageError class to clear CodeRabbit's docstring coverage check (was 60.61%, threshold 80%). - statusline-generator.ts: extract the seconds/ms heuristic (RESET_MS_THRESHOLD) and bar constants (USAGE_BAR_WIDTH, USAGE_PCT_HIGH/MED) from magic numbers, with a comment explaining the epoch heuristic. Behavior unchanged. - regenerate .claude/helpers/statusline.cjs artifact (drift-guard byte-match). The credentials.ts "empty account" nit was already handled in 6d73481 by omitting the `-a` filter when the username is unavailable (keeps the keychain lookup working) rather than early-returning null. https://claude.ai/code/session_01U9qENP4GeE5Fx8LUzGKziC
A project skill that runs a disciplined find → triage → fix → verify → report loop: - scripts/scan.sh: read-only diagnostics collector (tests, tsc, lint, smells) - SKILL.md: severity rubric + rules (don't weaken tests, no scope creep, report env/pre-existing failures honestly) - resources/templates/bug-report-template.md: structured report saved to docs/ Auto-triggers on "find and fix bugs", "clean up the failing build", or "generate a bug report". https://claude.ai/code/session_01U9qENP4GeE5Fx8LUzGKziC
- usage.test.ts: add 4 tests driving usageCommand.action — not-logged-in and expired-token paths (exitCode 1), and the authenticated success + --json paths served from a fresh seeded cache (no network). Closes the wiring gap from the code review. - bug-hunter/scripts/scan.sh: replace `ls *.py **/*.py` (relied on globstar, which is off by default so `**` only matched one level) with a `find`-based check so Python projects are detected reliably. https://claude.ai/code/session_01U9qENP4GeE5Fx8LUzGKziC
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Adds a new V3 CLI usage feature that reuses Claude Code authentication to fetch and cache subscription “plan usage limits”, and surfaces that data both in the terminal and the statusline (via stdin rate_limits or a local cache). Also introduces a “bug-hunter” diagnostic helper script + templates.
Changes:
- Added OAuth token resolution that reuses Claude Code login (env/keychain/file) and expiry detection.
- Added a usage client with caching + stale fallback behavior, and a new
usagecommand that renders a usage panel or JSON. - Updated statusline generator / helper to render usage bars and added Vitest coverage.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| v3/@claude-flow/cli/src/usage/credentials.ts | New Claude Code OAuth token resolution (env/keychain/file) + expiry helper |
| v3/@claude-flow/cli/src/usage/client.ts | New usage fetcher with error mapping, caching, and stale fallback logic |
| v3/@claude-flow/cli/src/commands/usage.ts | New usage CLI command and rendering helpers (panel/JSON) |
| v3/@claude-flow/cli/src/commands/index.ts | Registers new usage command in loader + category list |
| v3/@claude-flow/cli/src/init/statusline-generator.ts | Adds plan-usage bars display sourced from stdin rate_limits or local cache |
| v3/@claude-flow/cli/tests/usage.test.ts | Tests for token resolution, usage client caching, and command rendering |
| v3/@claude-flow/cli/tests/statusline-usage-display.test.ts | Tests statusline plan-usage rendering (stdin + cache + hide toggle) |
| .claude/helpers/statusline.cjs | Mirrors statusline usage rendering logic in checked-in helper |
| .claude/skills/bug-hunter/scripts/scan.sh | Adds read-only diagnostics collector script |
| .claude/skills/bug-hunter/resources/templates/bug-report-template.md | Adds structured bug report template |
| .claude/skills/bug-hunter/SKILL.md | Documents the “bug hunter” workflow and usage |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+100
to
+103
| export function isTokenExpired(resolved: ResolvedToken, now: number = Date.now()): boolean { | ||
| if (!resolved.expiresAt) return false; | ||
| return resolved.expiresAt <= now; | ||
| } |
| // CI shells); otherwise `-a ""` fails to match the real stored account. | ||
| if (account) args.push('-a', account); | ||
| args.push('-w'); | ||
| const out = execFileSync('security', args, { encoding: 'utf-8', stdio: ['ignore', 'pipe', 'ignore'] }); |
| * Resolve a Claude Code OAuth token, or null if the user is not logged in. | ||
| * Precedence: env override → macOS Keychain → credentials file. | ||
| */ | ||
| export async function resolveClaudeOAuthToken(): Promise<ResolvedToken | null> { |
Comment on lines
+375
to
+380
| // Unix timestamps in seconds are ~1.7e9; in milliseconds ~1.7e12. Values below | ||
| // this threshold are treated as seconds and scaled up to milliseconds. | ||
| const RESET_MS_THRESHOLD = 1e12; | ||
| const USAGE_BAR_WIDTH = 20; // characters per usage bar | ||
| const USAGE_PCT_HIGH = 75; // >= this => red | ||
| const USAGE_PCT_MED = 50; // >= this => yellow (else green) |
Comment on lines
+202
to
+218
| } catch (err) { | ||
| const e = err as UsageError; | ||
| if (asJson) { | ||
| output.printJson({ error: e.code ?? 'error', message: e.message }); | ||
| return { success: false, exitCode: 1 }; | ||
| } | ||
| output.writeln(); | ||
| if (e.code === 'unauthenticated') { | ||
| output.printError('Claude rejected the stored token.', 'Re-authenticate in Claude Code (`claude`).'); | ||
| } else if (e.code === 'rate_limited') { | ||
| output.printWarning('Claude usage endpoint is rate-limited and no cached data is available.'); | ||
| output.writeln(output.dim('Wait a few minutes and try again.')); | ||
| } else { | ||
| output.printError('Could not retrieve usage data.', e.message); | ||
| } | ||
| return { success: false, exitCode: 1 }; | ||
| } |
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.