feat: Claude usage API + multi-account dashboard display

- Replace expect/CLI hack with direct HTTP API call
  (GET api.anthropic.com/api/oauth/usage with OAuth token)
- Add fetchAllClaudeUsage() for per-token usage fetching
- Export getAllTokens() from token-rotation for usage queries
- Dashboard shows each account separately (Claude1, Claude2)
  with  for active token, 🚫 for rate-limited
This commit is contained in:
Eyejoker
2026-03-23 22:15:06 +09:00
parent d378598f2e
commit 83b25fb7bd
4 changed files with 181 additions and 218 deletions

View File

@@ -1,53 +1,28 @@
import { describe, expect, it } from 'vitest';
import { parseClaudeUsagePanel } from './claude-usage.js';
import type { ClaudeUsageData } from './claude-usage.js';
describe('parseClaudeUsagePanel', () => {
it('parses session and weekly usage from Claude CLI panel output', () => {
const sample = `
Settings: Status Config Usage
Loading usage data...
describe('ClaudeUsageData', () => {
it('represents the API response structure correctly', () => {
const data: ClaudeUsageData = {
five_hour: { utilization: 45.2, resets_at: '2026-03-23T17:00:00Z' },
seven_day: { utilization: 72.1, resets_at: '2026-03-29T00:00:00Z' },
seven_day_sonnet: { utilization: 60.0, resets_at: '2026-03-29T00:00:00Z' },
seven_day_opus: { utilization: 80.0, resets_at: '2026-03-29T00:00:00Z' },
};
Current session
████ 4% used
Resets in 8m (Asia/Seoul)
Current week (all models)
███████████████████████████████████████ 78% used
Resets Mar 17 at 10pm (Asia/Seoul)
Current week (Sonnet only)
███ 6% used
Resets Mar 17 at 11pm (Asia/Seoul)
Extra usage
Extra usage not enabled • /extra-usage to enable
`;
expect(parseClaudeUsagePanel(sample)).toEqual({
five_hour: {
utilization: 4,
resets_at: 'Resets in 8m (Asia/Seoul)',
},
seven_day: {
utilization: 78,
resets_at: 'Resets Mar 17 at 10pm (Asia/Seoul)',
},
});
expect(data.five_hour?.utilization).toBe(45.2);
expect(data.seven_day?.utilization).toBe(72.1);
expect(data.seven_day_sonnet?.utilization).toBe(60.0);
expect(data.seven_day_opus?.utilization).toBe(80.0);
});
it('converts percent left into used percent', () => {
const sample = `
Current session
60% left
Resets in 1h
`;
it('allows partial data (only five_hour)', () => {
const data: ClaudeUsageData = {
five_hour: { utilization: 10, resets_at: '2026-03-23T17:00:00Z' },
};
expect(parseClaudeUsagePanel(sample)).toEqual({
five_hour: {
utilization: 40,
resets_at: 'Resets in 1h',
},
});
expect(data.five_hour?.utilization).toBe(10);
expect(data.seven_day).toBeUndefined();
});
});