token-usage-sync 1.5.1 → 1.5.2

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 CHANGED
@@ -25,7 +25,7 @@ const flags = {
25
25
 
26
26
  // API URL(環境変数 or コマンドライン引数)
27
27
  const API_URL = process.env.SYNC_API_URL || getArgValue('api-url');
28
- const USER_ID = process.env.SYNC_USER_ID || getArgValue('user-id') || 'default-user';
28
+ const USER_ID = process.env.SYNC_USER_ID || getArgValue('user-id') || 'msgmacbookair';
29
29
 
30
30
  // ヘルプ表示
31
31
  if (flags.help) {
@@ -125,12 +125,67 @@ function calculateUsageForPeriod(entries, hoursAgo) {
125
125
  }
126
126
 
127
127
  // 重み付けトークン計算(Claude Code実測ベース)
128
- // Cache Read は無料(0x)、Cache Create は 1.0x
128
+ // Cache Read は 0.1x、Cache Create は 1.25x
129
129
  const weightedTokens = Math.round(
130
130
  inputTokens * 1.0 +
131
131
  outputTokens * 1.0 +
132
- cacheCreationTokens * 1.0 +
133
- cacheReadTokens * 0
132
+ cacheCreationTokens * 1.25 +
133
+ cacheReadTokens * 0.1
134
+ );
135
+
136
+ return {
137
+ inputTokens,
138
+ outputTokens,
139
+ cacheCreationTokens,
140
+ cacheReadTokens,
141
+ totalTokens: inputTokens + outputTokens + cacheCreationTokens + cacheReadTokens,
142
+ weightedTokens,
143
+ };
144
+ }
145
+
146
+ const WEEKLY_RESET = { weekday: 6, hour: 8, minute: 59 }; // Saturday 08:59 (local time)
147
+
148
+ function getLastWeeklyReset(now = new Date()) {
149
+ const reset = new Date(now);
150
+ const day = reset.getDay();
151
+ const diff = (day - WEEKLY_RESET.weekday + 7) % 7;
152
+ reset.setDate(reset.getDate() - diff);
153
+ reset.setHours(WEEKLY_RESET.hour, WEEKLY_RESET.minute, 0, 0);
154
+
155
+ if (now < reset) {
156
+ reset.setDate(reset.getDate() - 7);
157
+ }
158
+
159
+ return reset;
160
+ }
161
+
162
+ function calculateUsageSince(entries, startTime, now = new Date()) {
163
+ let inputTokens = 0;
164
+ let outputTokens = 0;
165
+ let cacheCreationTokens = 0;
166
+ let cacheReadTokens = 0;
167
+
168
+ for (const entry of entries) {
169
+ const timestamp = entry.timestamp || entry.message?.timestamp;
170
+ if (!timestamp) continue;
171
+
172
+ const entryTime = new Date(timestamp);
173
+ if (entryTime < startTime || entryTime > now) continue;
174
+
175
+ const usage = entry.message?.usage || entry.usage;
176
+ if (!usage) continue;
177
+
178
+ inputTokens += usage.input_tokens || 0;
179
+ outputTokens += usage.output_tokens || 0;
180
+ cacheCreationTokens += usage.cache_creation_input_tokens || 0;
181
+ cacheReadTokens += usage.cache_read_input_tokens || 0;
182
+ }
183
+
184
+ const weightedTokens = Math.round(
185
+ inputTokens * 1.0 +
186
+ outputTokens * 1.0 +
187
+ cacheCreationTokens * 1.25 +
188
+ cacheReadTokens * 0.1
134
189
  );
135
190
 
136
191
  return {
@@ -225,8 +280,8 @@ function calculateActiveBlockUsage(entries, now = new Date()) {
225
280
  const weightedTokens = Math.round(
226
281
  inputTokens * 1.0 +
227
282
  outputTokens * 1.0 +
228
- cacheCreationTokens * 1.0 +
229
- cacheReadTokens * 0
283
+ cacheCreationTokens * 1.25 +
284
+ cacheReadTokens * 0.1
230
285
  );
231
286
 
232
287
  const elapsedMinutes = Math.round((nowTime - activeBlock.startTime) / 60000);
@@ -305,7 +360,7 @@ function aggregateUsage(entries) {
305
360
  // ローリングウィンドウの使用量を計算
306
361
  const last5Hours = calculateUsageForPeriod(entries, 5);
307
362
  const last24Hours = calculateUsageForPeriod(entries, 24);
308
- const lastWeek = calculateUsageForPeriod(entries, 24 * 7);
363
+ const lastWeek = calculateUsageSince(entries, getLastWeeklyReset());
309
364
 
310
365
  return {
311
366
  summary: {
@@ -416,9 +471,10 @@ async function main() {
416
471
  console.log('\n📊 Claude Code Usage Summary\n');
417
472
 
418
473
  // 制限値
419
- const LIMIT_WEEK_RAW = 195_000_000; // 週間制限: 195M raw tokens
474
+ const LIMIT_WEEK_RAW = 180_000_000; // 週間制限: 180M raw tokens
420
475
 
421
- const pctWeek = Math.round((usage.limits.lastWeek.totalTokens / LIMIT_WEEK_RAW) * 100);
476
+ const lastWeekWeighted = usage.limits.lastWeek.weightedTokens ?? usage.limits.lastWeek.totalTokens;
477
+ const pctWeek = Math.round((lastWeekWeighted / LIMIT_WEEK_RAW) * 100);
422
478
 
423
479
  // アクティブブロック(Claude Code準拠のセッションブロック方式)
424
480
  console.log('=== Active Session Block ===');
@@ -429,7 +485,8 @@ async function main() {
429
485
  const remainingStr = `${Math.floor(remaining / 60)}h ${remaining % 60}m`;
430
486
 
431
487
  console.log(`Status: ACTIVE (${elapsedStr} elapsed, ${remainingStr} remaining)`);
432
- console.log(`Tokens: ${usage.activeBlock.totalTokens.toLocaleString()}`);
488
+ const activeBlockWeighted = usage.activeBlock.weightedTokens ?? usage.activeBlock.totalTokens;
489
+ console.log(`Tokens: ${activeBlockWeighted.toLocaleString()}`);
433
490
  console.log(` Input: ${usage.activeBlock.inputTokens.toLocaleString()}`);
434
491
  console.log(` Output: ${usage.activeBlock.outputTokens.toLocaleString()}`);
435
492
  console.log(` Cache: ${usage.activeBlock.cacheCreationTokens.toLocaleString()} (create) + ${usage.activeBlock.cacheReadTokens.toLocaleString()} (read)`);
@@ -438,7 +495,7 @@ async function main() {
438
495
  }
439
496
 
440
497
  console.log('\n=== Weekly Limit ===');
441
- console.log(`Weekly: ${usage.limits.lastWeek.totalTokens.toLocaleString()} / ${LIMIT_WEEK_RAW.toLocaleString()} (${pctWeek}%)`);
498
+ console.log(`Weekly: ${lastWeekWeighted.toLocaleString()} / ${LIMIT_WEEK_RAW.toLocaleString()} (${pctWeek}%)`);
442
499
 
443
500
  console.log('\n=== All Time Total ===');
444
501
  console.log(`Total Tokens: ${usage.summary.totalTokens.toLocaleString()}`);
@@ -87,8 +87,8 @@ export function calculateActiveBlockUsage(entries, now = new Date()) {
87
87
  const weightedTokens = Math.round(
88
88
  inputTokens * 1.0 +
89
89
  outputTokens * 1.0 +
90
- cacheCreationTokens * 1.0 +
91
- cacheReadTokens * 0
90
+ cacheCreationTokens * 1.25 +
91
+ cacheReadTokens * 0.1
92
92
  );
93
93
 
94
94
  const elapsedMinutes = Math.round((nowTime - activeBlock.startTime) / 60000);
@@ -134,12 +134,67 @@ export function calculateUsageForPeriod(entries, hoursAgo, now = new Date()) {
134
134
  }
135
135
 
136
136
  // 重み付けトークン計算(Claude Code実測ベース)
137
- // Cache Read は無料(0x)、Cache Create は 1.0x
137
+ // Cache Read は 0.1x、Cache Create は 1.25x
138
138
  const weightedTokens = Math.round(
139
139
  inputTokens * 1.0 +
140
140
  outputTokens * 1.0 +
141
- cacheCreationTokens * 1.0 +
142
- cacheReadTokens * 0
141
+ cacheCreationTokens * 1.25 +
142
+ cacheReadTokens * 0.1
143
+ );
144
+
145
+ return {
146
+ inputTokens,
147
+ outputTokens,
148
+ cacheCreationTokens,
149
+ cacheReadTokens,
150
+ totalTokens: inputTokens + outputTokens + cacheCreationTokens + cacheReadTokens,
151
+ weightedTokens,
152
+ };
153
+ }
154
+
155
+ const WEEKLY_RESET = { weekday: 6, hour: 8, minute: 59 }; // Saturday 08:59 (local time)
156
+
157
+ function getLastWeeklyReset(now = new Date()) {
158
+ const reset = new Date(now);
159
+ const day = reset.getDay();
160
+ const diff = (day - WEEKLY_RESET.weekday + 7) % 7;
161
+ reset.setDate(reset.getDate() - diff);
162
+ reset.setHours(WEEKLY_RESET.hour, WEEKLY_RESET.minute, 0, 0);
163
+
164
+ if (now < reset) {
165
+ reset.setDate(reset.getDate() - 7);
166
+ }
167
+
168
+ return reset;
169
+ }
170
+
171
+ function calculateUsageSince(entries, startTime, now = new Date()) {
172
+ let inputTokens = 0;
173
+ let outputTokens = 0;
174
+ let cacheCreationTokens = 0;
175
+ let cacheReadTokens = 0;
176
+
177
+ for (const entry of entries) {
178
+ const timestamp = entry.timestamp || entry.message?.timestamp;
179
+ if (!timestamp) continue;
180
+
181
+ const entryTime = new Date(timestamp);
182
+ if (entryTime < startTime || entryTime > now) continue;
183
+
184
+ const usage = entry.message?.usage || entry.usage;
185
+ if (!usage) continue;
186
+
187
+ inputTokens += usage.input_tokens || 0;
188
+ outputTokens += usage.output_tokens || 0;
189
+ cacheCreationTokens += usage.cache_creation_input_tokens || 0;
190
+ cacheReadTokens += usage.cache_read_input_tokens || 0;
191
+ }
192
+
193
+ const weightedTokens = Math.round(
194
+ inputTokens * 1.0 +
195
+ outputTokens * 1.0 +
196
+ cacheCreationTokens * 1.25 +
197
+ cacheReadTokens * 0.1
143
198
  );
144
199
 
145
200
  return {
@@ -210,7 +265,7 @@ export function aggregateUsage(entries, now = new Date()) {
210
265
  // ローリングウィンドウの使用量を計算(後方互換性)
211
266
  const last5Hours = calculateUsageForPeriod(entries, 5, now);
212
267
  const last24Hours = calculateUsageForPeriod(entries, 24, now);
213
- const lastWeek = calculateUsageForPeriod(entries, 24 * 7, now);
268
+ const lastWeek = calculateUsageSince(entries, getLastWeeklyReset(now), now);
214
269
 
215
270
  return {
216
271
  summary: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "token-usage-sync",
3
- "version": "1.5.1",
3
+ "version": "1.5.2",
4
4
  "description": "Sync Claude Code token usage to your self-hosted dashboard",
5
5
  "type": "module",
6
6
  "bin": {