cc-dev-template 0.1.103 → 0.1.104
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/package.json +1 -1
- package/src/scripts/statusline.js +61 -37
package/package.json
CHANGED
|
@@ -21,9 +21,10 @@ const { homedir } = require('os');
|
|
|
21
21
|
// Usage API cache
|
|
22
22
|
const USAGE_CACHE_PATH = join(homedir(), '.claude', '.usage-cache.json');
|
|
23
23
|
const USAGE_LOCK_PATH = join(homedir(), '.claude', '.usage-cache.lock');
|
|
24
|
-
const USAGE_CACHE_TTL =
|
|
25
|
-
const
|
|
26
|
-
const
|
|
24
|
+
const USAGE_CACHE_TTL = 30000; // 30s normal refresh interval
|
|
25
|
+
const USAGE_ERROR_TTL = 300000; // 5 min backoff on errors (rate limit, network, etc.)
|
|
26
|
+
const USAGE_LOCK_TTL = 15000; // 15s lock (curl timeout is 5s, 15s is generous)
|
|
27
|
+
const USAGE_HISTORY_MAX = 20; // ~10 min of readings at 30s intervals
|
|
27
28
|
|
|
28
29
|
// Background refresh mode: fetch usage data and write cache, then exit
|
|
29
30
|
if (process.argv.includes('--refresh')) {
|
|
@@ -307,13 +308,33 @@ function getOAuthToken() {
|
|
|
307
308
|
}
|
|
308
309
|
}
|
|
309
310
|
|
|
311
|
+
/**
|
|
312
|
+
* Write error backoff to cache — preserves existing data/history,
|
|
313
|
+
* but delays next refresh attempt by USAGE_ERROR_TTL.
|
|
314
|
+
*/
|
|
315
|
+
function writeErrorBackoff() {
|
|
316
|
+
const now = Date.now();
|
|
317
|
+
try {
|
|
318
|
+
const existing = JSON.parse(readFileSync(USAGE_CACHE_PATH, 'utf-8'));
|
|
319
|
+
existing.nextRefreshAfter = now + USAGE_ERROR_TTL;
|
|
320
|
+
writeFileSync(USAGE_CACHE_PATH, JSON.stringify(existing));
|
|
321
|
+
} catch {
|
|
322
|
+
writeFileSync(USAGE_CACHE_PATH, JSON.stringify({
|
|
323
|
+
timestamp: now,
|
|
324
|
+
nextRefreshAfter: now + USAGE_ERROR_TTL,
|
|
325
|
+
data: null,
|
|
326
|
+
history: [],
|
|
327
|
+
}));
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
310
331
|
/**
|
|
311
332
|
* Fetch usage data from API and write to cache (runs in background)
|
|
312
333
|
*/
|
|
313
334
|
function refreshUsageCache() {
|
|
314
335
|
try {
|
|
315
336
|
const token = getOAuthToken();
|
|
316
|
-
if (!token) return;
|
|
337
|
+
if (!token) { writeErrorBackoff(); return; }
|
|
317
338
|
|
|
318
339
|
const result = spawnSync('curl', [
|
|
319
340
|
'-s', '--max-time', '3',
|
|
@@ -323,59 +344,62 @@ function refreshUsageCache() {
|
|
|
323
344
|
'-H', 'Content-Type: application/json',
|
|
324
345
|
], { encoding: 'utf-8', timeout: 5000 });
|
|
325
346
|
|
|
326
|
-
if (result.status
|
|
327
|
-
const data = JSON.parse(result.stdout.trim());
|
|
328
|
-
if (data.five_hour && data.seven_day) {
|
|
329
|
-
// Load existing history and append new reading
|
|
330
|
-
let history = [];
|
|
331
|
-
try {
|
|
332
|
-
const existing = JSON.parse(readFileSync(USAGE_CACHE_PATH, 'utf-8'));
|
|
333
|
-
if (Array.isArray(existing.history)) history = existing.history;
|
|
334
|
-
} catch {}
|
|
335
|
-
|
|
336
|
-
const now = Date.now();
|
|
337
|
-
history.push({
|
|
338
|
-
t: now,
|
|
339
|
-
five_hour: data.five_hour.utilization,
|
|
340
|
-
seven_day: data.seven_day.utilization,
|
|
341
|
-
});
|
|
347
|
+
if (result.status !== 0 || !result.stdout) { writeErrorBackoff(); return; }
|
|
342
348
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
history = history.slice(-USAGE_HISTORY_MAX);
|
|
346
|
-
}
|
|
349
|
+
let responseData;
|
|
350
|
+
try { responseData = JSON.parse(result.stdout.trim()); } catch { writeErrorBackoff(); return; }
|
|
347
351
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
352
|
+
if (!responseData.five_hour || !responseData.seven_day) { writeErrorBackoff(); return; }
|
|
353
|
+
|
|
354
|
+
// --- Success path ---
|
|
355
|
+
let history = [];
|
|
356
|
+
try {
|
|
357
|
+
const existing = JSON.parse(readFileSync(USAGE_CACHE_PATH, 'utf-8'));
|
|
358
|
+
if (Array.isArray(existing.history)) history = existing.history;
|
|
359
|
+
} catch {}
|
|
360
|
+
|
|
361
|
+
const now = Date.now();
|
|
362
|
+
history.push({
|
|
363
|
+
t: now,
|
|
364
|
+
five_hour: responseData.five_hour.utilization,
|
|
365
|
+
seven_day: responseData.seven_day.utilization,
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
if (history.length > USAGE_HISTORY_MAX) {
|
|
369
|
+
history = history.slice(-USAGE_HISTORY_MAX);
|
|
355
370
|
}
|
|
371
|
+
|
|
372
|
+
writeFileSync(USAGE_CACHE_PATH, JSON.stringify({
|
|
373
|
+
timestamp: now,
|
|
374
|
+
nextRefreshAfter: now + USAGE_CACHE_TTL,
|
|
375
|
+
data: responseData,
|
|
376
|
+
history,
|
|
377
|
+
}));
|
|
356
378
|
} catch {
|
|
357
|
-
|
|
379
|
+
writeErrorBackoff();
|
|
380
|
+
} finally {
|
|
381
|
+
try { unlinkSync(USAGE_LOCK_PATH); } catch {}
|
|
358
382
|
}
|
|
359
383
|
}
|
|
360
384
|
|
|
361
385
|
/**
|
|
362
|
-
* Read cached usage data, trigger background refresh if
|
|
386
|
+
* Read cached usage data, trigger background refresh if scheduled time has passed.
|
|
387
|
+
* All instances share the same nextRefreshAfter timestamp — only one refresh per cycle.
|
|
363
388
|
*/
|
|
364
389
|
function getUsageData() {
|
|
365
390
|
let cacheData = null;
|
|
366
391
|
let cacheHistory = null;
|
|
367
|
-
let
|
|
392
|
+
let shouldRefresh = true; // refresh if no cache exists
|
|
368
393
|
|
|
369
394
|
try {
|
|
370
395
|
const raw = readFileSync(USAGE_CACHE_PATH, 'utf-8');
|
|
371
396
|
const cache = JSON.parse(raw);
|
|
372
397
|
cacheData = cache.data;
|
|
373
398
|
cacheHistory = cache.history || null;
|
|
374
|
-
|
|
399
|
+
shouldRefresh = Date.now() > (cache.nextRefreshAfter || 0);
|
|
375
400
|
} catch {}
|
|
376
401
|
|
|
377
|
-
|
|
378
|
-
if (cacheAge > USAGE_CACHE_TTL) {
|
|
402
|
+
if (shouldRefresh) {
|
|
379
403
|
let lockHeld = false;
|
|
380
404
|
try {
|
|
381
405
|
const lockTime = parseInt(readFileSync(USAGE_LOCK_PATH, 'utf-8'), 10);
|