token-usage-sync 1.5.0 → 1.5.1
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.
- package/index.js +8 -133
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -20,7 +20,6 @@ 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'),
|
|
24
23
|
verbose: args.includes('--verbose') || args.includes('-v'),
|
|
25
24
|
};
|
|
26
25
|
|
|
@@ -28,10 +27,6 @@ const flags = {
|
|
|
28
27
|
const API_URL = process.env.SYNC_API_URL || getArgValue('api-url');
|
|
29
28
|
const USER_ID = process.env.SYNC_USER_ID || getArgValue('user-id') || 'default-user';
|
|
30
29
|
|
|
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
|
-
|
|
35
30
|
// ヘルプ表示
|
|
36
31
|
if (flags.help) {
|
|
37
32
|
console.log(`
|
|
@@ -43,34 +38,28 @@ token-usage-sync - Claude Code使用量をダッシュボードに同期
|
|
|
43
38
|
オプション:
|
|
44
39
|
--json JSON形式で出力
|
|
45
40
|
--send ダッシュボードに送信(--api-url必須)
|
|
46
|
-
--fetch-api Claude APIから使用率を取得(--session-key, --org-id必須)
|
|
47
41
|
--api-url=URL 送信先APIのURL
|
|
48
42
|
--user-id=ID ユーザーID(デフォルト: default-user)
|
|
49
|
-
--session-key=KEY Claude セッションキー(ブラウザCookieから取得)
|
|
50
|
-
--org-id=ID Claude 組織ID(ブラウザCookieから取得)
|
|
51
43
|
--verbose 詳細ログ出力
|
|
52
44
|
--help このヘルプを表示
|
|
53
45
|
|
|
54
46
|
環境変数:
|
|
55
47
|
SYNC_API_URL 送信先URL(--api-urlの代わり)
|
|
56
48
|
SYNC_USER_ID ユーザーID(--user-idの代わり)
|
|
57
|
-
CLAUDE_SESSION_KEY Claudeセッションキー(--session-keyの代わり)
|
|
58
|
-
CLAUDE_ORG_ID Claude組織ID(--org-idの代わり)
|
|
59
49
|
|
|
60
50
|
例:
|
|
61
51
|
# 使用量を表示(ローカルJSONLから計算)
|
|
62
52
|
npx token-usage-sync
|
|
63
53
|
|
|
64
|
-
#
|
|
65
|
-
npx token-usage-sync --
|
|
54
|
+
# ダッシュボードに送信
|
|
55
|
+
npx token-usage-sync --send
|
|
66
56
|
|
|
67
|
-
#
|
|
68
|
-
npx token-usage-sync --
|
|
57
|
+
# JSON形式で出力
|
|
58
|
+
npx token-usage-sync --json
|
|
69
59
|
|
|
70
|
-
|
|
71
|
-
1.
|
|
72
|
-
2.
|
|
73
|
-
3. sessionKey と lastActiveOrg の値をコピー
|
|
60
|
+
推奨ワークフロー:
|
|
61
|
+
1. npx ccusage blocks → セッションブロックの詳細を確認
|
|
62
|
+
2. npx token-usage-sync --send → ダッシュボードに同期
|
|
74
63
|
`);
|
|
75
64
|
process.exit(0);
|
|
76
65
|
}
|
|
@@ -340,123 +329,9 @@ function aggregateUsage(entries) {
|
|
|
340
329
|
};
|
|
341
330
|
}
|
|
342
331
|
|
|
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
|
-
|
|
375
332
|
// メイン処理
|
|
376
333
|
async function main() {
|
|
377
|
-
//
|
|
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モード(デフォルト)
|
|
334
|
+
// ローカルJSONLモード
|
|
460
335
|
// ファイル検索
|
|
461
336
|
if (flags.verbose) {
|
|
462
337
|
console.error(`Searching for JSONL files in: ${PROJECTS_DIR}`);
|