token-usage-sync 1.3.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/index.js +134 -10
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -20,6 +20,7 @@ const flags = {
20
20
  help: args.includes('--help') || args.includes('-h'),
21
21
  json: args.includes('--json'),
22
22
  send: args.includes('--send'),
23
+ fetchApi: args.includes('--fetch-api'),
23
24
  verbose: args.includes('--verbose') || args.includes('-v'),
24
25
  };
25
26
 
@@ -27,6 +28,10 @@ const flags = {
27
28
  const API_URL = process.env.SYNC_API_URL || getArgValue('api-url');
28
29
  const USER_ID = process.env.SYNC_USER_ID || getArgValue('user-id') || 'default-user';
29
30
 
31
+ // Claude API認証情報
32
+ const CLAUDE_SESSION_KEY = process.env.CLAUDE_SESSION_KEY || getArgValue('session-key');
33
+ const CLAUDE_ORG_ID = process.env.CLAUDE_ORG_ID || getArgValue('org-id');
34
+
30
35
  // ヘルプ表示
31
36
  if (flags.help) {
32
37
  console.log(`
@@ -38,30 +43,34 @@ token-usage-sync - Claude Code使用量をダッシュボードに同期
38
43
  オプション:
39
44
  --json JSON形式で出力
40
45
  --send ダッシュボードに送信(--api-url必須)
46
+ --fetch-api Claude APIから使用率を取得(--session-key, --org-id必須)
41
47
  --api-url=URL 送信先APIのURL
42
48
  --user-id=ID ユーザーID(デフォルト: default-user)
49
+ --session-key=KEY Claude セッションキー(ブラウザCookieから取得)
50
+ --org-id=ID Claude 組織ID(ブラウザCookieから取得)
43
51
  --verbose 詳細ログ出力
44
52
  --help このヘルプを表示
45
53
 
46
54
  環境変数:
47
55
  SYNC_API_URL 送信先URL(--api-urlの代わり)
48
56
  SYNC_USER_ID ユーザーID(--user-idの代わり)
57
+ CLAUDE_SESSION_KEY Claudeセッションキー(--session-keyの代わり)
58
+ CLAUDE_ORG_ID Claude組織ID(--org-idの代わり)
49
59
 
50
60
  例:
51
- # 使用量を表示
61
+ # 使用量を表示(ローカルJSONLから計算)
52
62
  npx token-usage-sync
53
63
 
54
- # 自分のダッシュボードに送信
55
- npx token-usage-sync --send --api-url=https://your-worker.workers.dev/api/sync-usage
64
+ # Claude APIから使用率を取得して表示
65
+ npx token-usage-sync --fetch-api --session-key=sk-xxx --org-id=xxx
56
66
 
57
- # 環境変数を使用
58
- export SYNC_API_URL=https://your-worker.workers.dev/api/sync-usage
59
- npx token-usage-sync --send
67
+ # APIから取得してダッシュボードに送信
68
+ npx token-usage-sync --fetch-api --send
60
69
 
61
- セットアップ:
62
- 1. リポジトリをフォーク: https://github.com/your-repo/token-usage-dashboard
63
- 2. Cloudflare Workersにデプロイ
64
- 3. 上記コマンドで同期
70
+ セッションキー/組織IDの取得方法:
71
+ 1. claude.ai にログイン
72
+ 2. 開発者ツール > Application > Cookies
73
+ 3. sessionKey と lastActiveOrg の値をコピー
65
74
  `);
66
75
  process.exit(0);
67
76
  }
@@ -331,8 +340,123 @@ function aggregateUsage(entries) {
331
340
  };
332
341
  }
333
342
 
343
+ // Claude APIから使用率を取得
344
+ async function fetchClaudeApiUsage(sessionKey, orgId) {
345
+ const url = `https://claude.ai/api/organizations/${orgId}/usage`;
346
+
347
+ const response = await fetch(url, {
348
+ method: 'GET',
349
+ headers: {
350
+ 'Accept': 'application/json',
351
+ 'Cookie': `sessionKey=${sessionKey}`,
352
+ },
353
+ });
354
+
355
+ if (!response.ok) {
356
+ throw new Error(`Claude API error: ${response.status} ${response.statusText}`);
357
+ }
358
+
359
+ const data = await response.json();
360
+
361
+ // APIレスポンスをパース
362
+ // utilization は 0.0〜1.0 の値(0%〜100%)
363
+ const fiveHour = data.five_hour || {};
364
+ const sevenDay = data.seven_day || {};
365
+
366
+ return {
367
+ fiveHourPercent: fiveHour.utilization != null ? Math.round(fiveHour.utilization * 100) : null,
368
+ fiveHourResetAt: fiveHour.resets_at || null,
369
+ weeklyPercent: sevenDay.utilization != null ? Math.round(sevenDay.utilization * 100) : null,
370
+ weeklyResetAt: sevenDay.resets_at || null,
371
+ raw: data,
372
+ };
373
+ }
374
+
334
375
  // メイン処理
335
376
  async function main() {
377
+ // --fetch-api モード: Claude APIから使用率を取得
378
+ if (flags.fetchApi) {
379
+ if (!CLAUDE_SESSION_KEY || !CLAUDE_ORG_ID) {
380
+ console.error('✗ --fetch-api requires --session-key and --org-id');
381
+ console.error('');
382
+ console.error('Usage:');
383
+ console.error(' npx token-usage-sync --fetch-api --session-key=YOUR_KEY --org-id=YOUR_ORG');
384
+ console.error('');
385
+ console.error('Or set environment variables:');
386
+ console.error(' export CLAUDE_SESSION_KEY=YOUR_KEY');
387
+ console.error(' export CLAUDE_ORG_ID=YOUR_ORG');
388
+ process.exit(1);
389
+ }
390
+
391
+ if (flags.verbose) {
392
+ console.error('Fetching usage from Claude API...');
393
+ }
394
+
395
+ try {
396
+ const apiUsage = await fetchClaudeApiUsage(CLAUDE_SESSION_KEY, CLAUDE_ORG_ID);
397
+
398
+ if (flags.json) {
399
+ console.log(JSON.stringify(apiUsage, null, 2));
400
+ return;
401
+ }
402
+
403
+ // 表示
404
+ console.log('\n📊 Claude Code Usage (from API)\n');
405
+ console.log('=== Usage Limits ===');
406
+ console.log(`5-Hour: ${apiUsage.fiveHourPercent ?? '--'}%`);
407
+ console.log(`Weekly: ${apiUsage.weeklyPercent ?? '--'}%`);
408
+
409
+ if (apiUsage.fiveHourResetAt) {
410
+ const resetTime = new Date(apiUsage.fiveHourResetAt);
411
+ const remaining = Math.max(0, Math.round((resetTime - new Date()) / 60000));
412
+ console.log(`\n5H Reset: ${Math.floor(remaining / 60)}h ${remaining % 60}m remaining`);
413
+ }
414
+
415
+ // 送信
416
+ if (flags.send) {
417
+ if (!API_URL) {
418
+ console.error('\n✗ --api-url is required for --send');
419
+ process.exit(1);
420
+ }
421
+
422
+ const payload = {
423
+ source: 'api',
424
+ apiUsage: {
425
+ fiveHourPercent: apiUsage.fiveHourPercent,
426
+ fiveHourResetAt: apiUsage.fiveHourResetAt,
427
+ weeklyPercent: apiUsage.weeklyPercent,
428
+ weeklyResetAt: apiUsage.weeklyResetAt,
429
+ },
430
+ syncedAt: new Date().toISOString(),
431
+ };
432
+
433
+ const response = await fetch(API_URL, {
434
+ method: 'POST',
435
+ headers: {
436
+ 'Content-Type': 'application/json',
437
+ 'X-User-Id': USER_ID,
438
+ },
439
+ body: JSON.stringify(payload),
440
+ });
441
+
442
+ if (response.ok) {
443
+ console.log('\n✓ Usage data synced successfully!');
444
+ } else {
445
+ console.error(`\n✗ Failed to sync: ${response.status} ${response.statusText}`);
446
+ process.exit(1);
447
+ }
448
+ } else {
449
+ console.log('\n💡 Run with --send to sync to dashboard');
450
+ }
451
+
452
+ return;
453
+ } catch (e) {
454
+ console.error(`✗ Failed to fetch from Claude API: ${e.message}`);
455
+ process.exit(1);
456
+ }
457
+ }
458
+
459
+ // ローカルJSONLモード(デフォルト)
336
460
  // ファイル検索
337
461
  if (flags.verbose) {
338
462
  console.error(`Searching for JSONL files in: ${PROJECTS_DIR}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "token-usage-sync",
3
- "version": "1.3.0",
3
+ "version": "1.5.0",
4
4
  "description": "Sync Claude Code token usage to your self-hosted dashboard",
5
5
  "type": "module",
6
6
  "bin": {