claude-scope 0.8.33 → 0.8.35
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/dist/claude-scope.cjs +221 -17
- package/package.json +1 -1
package/dist/claude-scope.cjs
CHANGED
|
@@ -2413,6 +2413,173 @@ var init_widget_types = __esm({
|
|
|
2413
2413
|
}
|
|
2414
2414
|
});
|
|
2415
2415
|
|
|
2416
|
+
// src/providers/usage-parser.ts
|
|
2417
|
+
var import_fs, import_readline, UsageParser;
|
|
2418
|
+
var init_usage_parser = __esm({
|
|
2419
|
+
"src/providers/usage-parser.ts"() {
|
|
2420
|
+
"use strict";
|
|
2421
|
+
import_fs = require("fs");
|
|
2422
|
+
import_readline = require("readline");
|
|
2423
|
+
UsageParser = class {
|
|
2424
|
+
/**
|
|
2425
|
+
* Parse the last assistant message with usage data from transcript
|
|
2426
|
+
* Reads file in reverse to find the most recent data quickly
|
|
2427
|
+
*
|
|
2428
|
+
* @param transcriptPath - Path to the JSONL transcript file
|
|
2429
|
+
* @returns ContextUsage or null if not found
|
|
2430
|
+
*/
|
|
2431
|
+
async parseLastUsage(transcriptPath) {
|
|
2432
|
+
if (!(0, import_fs.existsSync)(transcriptPath)) {
|
|
2433
|
+
return null;
|
|
2434
|
+
}
|
|
2435
|
+
try {
|
|
2436
|
+
const lines = await this.readAllLines(transcriptPath);
|
|
2437
|
+
let mostRecentUsage = null;
|
|
2438
|
+
let mostRecentTimestamp = null;
|
|
2439
|
+
let hasAnyTimestamp = false;
|
|
2440
|
+
for (const line of lines) {
|
|
2441
|
+
const entry = this.parseLineForUsage(line);
|
|
2442
|
+
if (entry) {
|
|
2443
|
+
const entryTime = this.parseTimestamp(line);
|
|
2444
|
+
if (entryTime) {
|
|
2445
|
+
hasAnyTimestamp = true;
|
|
2446
|
+
if (!mostRecentTimestamp || entryTime > mostRecentTimestamp) {
|
|
2447
|
+
mostRecentUsage = entry;
|
|
2448
|
+
mostRecentTimestamp = entryTime;
|
|
2449
|
+
}
|
|
2450
|
+
} else if (!hasAnyTimestamp) {
|
|
2451
|
+
mostRecentUsage = entry;
|
|
2452
|
+
}
|
|
2453
|
+
}
|
|
2454
|
+
}
|
|
2455
|
+
return mostRecentUsage;
|
|
2456
|
+
} catch {
|
|
2457
|
+
return null;
|
|
2458
|
+
}
|
|
2459
|
+
}
|
|
2460
|
+
/**
|
|
2461
|
+
* Parse timestamp from a transcript line
|
|
2462
|
+
*/
|
|
2463
|
+
parseTimestamp(line) {
|
|
2464
|
+
try {
|
|
2465
|
+
const entry = JSON.parse(line);
|
|
2466
|
+
if (entry.timestamp) {
|
|
2467
|
+
return new Date(entry.timestamp);
|
|
2468
|
+
}
|
|
2469
|
+
} catch {
|
|
2470
|
+
}
|
|
2471
|
+
return null;
|
|
2472
|
+
}
|
|
2473
|
+
/**
|
|
2474
|
+
* Read all lines from transcript file
|
|
2475
|
+
*/
|
|
2476
|
+
async readAllLines(transcriptPath) {
|
|
2477
|
+
const lines = [];
|
|
2478
|
+
try {
|
|
2479
|
+
const fileStream = (0, import_fs.createReadStream)(transcriptPath, { encoding: "utf-8" });
|
|
2480
|
+
const rl = (0, import_readline.createInterface)({
|
|
2481
|
+
input: fileStream,
|
|
2482
|
+
crlfDelay: Infinity
|
|
2483
|
+
});
|
|
2484
|
+
for await (const line of rl) {
|
|
2485
|
+
if (line.trim()) {
|
|
2486
|
+
lines.push(line);
|
|
2487
|
+
}
|
|
2488
|
+
}
|
|
2489
|
+
} catch {
|
|
2490
|
+
return [];
|
|
2491
|
+
}
|
|
2492
|
+
return lines;
|
|
2493
|
+
}
|
|
2494
|
+
/**
|
|
2495
|
+
* Parse cumulative cache tokens from all assistant messages in transcript
|
|
2496
|
+
* Sums ALL cache_read and cache_creation tokens across the entire session
|
|
2497
|
+
*
|
|
2498
|
+
* @param transcriptPath - Path to the JSONL transcript file
|
|
2499
|
+
* @returns Object with cumulative cacheRead and cacheCreation, or null if not found
|
|
2500
|
+
*/
|
|
2501
|
+
async parseCumulativeCache(transcriptPath) {
|
|
2502
|
+
if (!(0, import_fs.existsSync)(transcriptPath)) {
|
|
2503
|
+
return null;
|
|
2504
|
+
}
|
|
2505
|
+
try {
|
|
2506
|
+
const lines = await this.readAllLines(transcriptPath);
|
|
2507
|
+
let cumulativeCacheRead = 0;
|
|
2508
|
+
let cumulativeCacheCreation = 0;
|
|
2509
|
+
for (const line of lines) {
|
|
2510
|
+
const entry = this.parseLineForCache(line);
|
|
2511
|
+
if (entry) {
|
|
2512
|
+
cumulativeCacheRead += entry.cacheRead;
|
|
2513
|
+
cumulativeCacheCreation += entry.cacheCreation;
|
|
2514
|
+
}
|
|
2515
|
+
}
|
|
2516
|
+
if (cumulativeCacheRead === 0 && cumulativeCacheCreation === 0) {
|
|
2517
|
+
return null;
|
|
2518
|
+
}
|
|
2519
|
+
return {
|
|
2520
|
+
cacheRead: cumulativeCacheRead,
|
|
2521
|
+
cacheCreation: cumulativeCacheCreation
|
|
2522
|
+
};
|
|
2523
|
+
} catch {
|
|
2524
|
+
return null;
|
|
2525
|
+
}
|
|
2526
|
+
}
|
|
2527
|
+
/**
|
|
2528
|
+
* Parse a single transcript line for cache data
|
|
2529
|
+
* Returns null if line is not an assistant message with usage
|
|
2530
|
+
*/
|
|
2531
|
+
parseLineForCache(line) {
|
|
2532
|
+
try {
|
|
2533
|
+
const entry = JSON.parse(line);
|
|
2534
|
+
if (entry.type !== "assistant") {
|
|
2535
|
+
return null;
|
|
2536
|
+
}
|
|
2537
|
+
const usage = entry.message?.usage;
|
|
2538
|
+
if (!usage) {
|
|
2539
|
+
return null;
|
|
2540
|
+
}
|
|
2541
|
+
const cacheRead = usage.cache_read_input_tokens ?? 0;
|
|
2542
|
+
const cacheCreation = usage.cache_creation_input_tokens ?? 0;
|
|
2543
|
+
if (cacheRead === 0 && cacheCreation === 0) {
|
|
2544
|
+
return null;
|
|
2545
|
+
}
|
|
2546
|
+
return { cacheRead, cacheCreation };
|
|
2547
|
+
} catch {
|
|
2548
|
+
return null;
|
|
2549
|
+
}
|
|
2550
|
+
}
|
|
2551
|
+
/**
|
|
2552
|
+
* Parse a single transcript line for usage data
|
|
2553
|
+
* Returns null if line is not an assistant message with usage
|
|
2554
|
+
*/
|
|
2555
|
+
parseLineForUsage(line) {
|
|
2556
|
+
try {
|
|
2557
|
+
const entry = JSON.parse(line);
|
|
2558
|
+
if (entry.type !== "assistant") {
|
|
2559
|
+
return null;
|
|
2560
|
+
}
|
|
2561
|
+
const usage = entry.message?.usage;
|
|
2562
|
+
if (!usage) {
|
|
2563
|
+
return null;
|
|
2564
|
+
}
|
|
2565
|
+
if (typeof usage.input_tokens !== "number" || typeof usage.output_tokens !== "number") {
|
|
2566
|
+
return null;
|
|
2567
|
+
}
|
|
2568
|
+
return {
|
|
2569
|
+
input_tokens: usage.input_tokens,
|
|
2570
|
+
output_tokens: usage.output_tokens,
|
|
2571
|
+
cache_creation_input_tokens: usage.cache_creation_input_tokens ?? 0,
|
|
2572
|
+
cache_read_input_tokens: usage.cache_read_input_tokens ?? 0
|
|
2573
|
+
// Default to 0 if missing
|
|
2574
|
+
};
|
|
2575
|
+
} catch {
|
|
2576
|
+
return null;
|
|
2577
|
+
}
|
|
2578
|
+
}
|
|
2579
|
+
};
|
|
2580
|
+
}
|
|
2581
|
+
});
|
|
2582
|
+
|
|
2416
2583
|
// src/storage/cache-manager.ts
|
|
2417
2584
|
var import_node_fs, import_node_os2, import_node_path2, DEFAULT_CACHE_PATH, DEFAULT_EXPIRY_MS, CacheManager;
|
|
2418
2585
|
var init_cache_manager = __esm({
|
|
@@ -2665,6 +2832,7 @@ var init_cache_metrics_widget = __esm({
|
|
|
2665
2832
|
"src/widgets/cache-metrics/cache-metrics-widget.ts"() {
|
|
2666
2833
|
"use strict";
|
|
2667
2834
|
init_widget_types();
|
|
2835
|
+
init_usage_parser();
|
|
2668
2836
|
init_cache_manager();
|
|
2669
2837
|
init_theme();
|
|
2670
2838
|
init_stdin_data_widget();
|
|
@@ -2684,11 +2852,17 @@ var init_cache_metrics_widget = __esm({
|
|
|
2684
2852
|
style = "balanced";
|
|
2685
2853
|
renderData;
|
|
2686
2854
|
cacheManager;
|
|
2855
|
+
usageParser;
|
|
2687
2856
|
lastSessionId;
|
|
2857
|
+
cachedUsage;
|
|
2858
|
+
// Cache parsed usage within render cycle
|
|
2859
|
+
cachedCumulativeCache;
|
|
2860
|
+
// Cumulative cache for session
|
|
2688
2861
|
constructor(theme) {
|
|
2689
2862
|
super();
|
|
2690
2863
|
this.theme = theme ?? DEFAULT_THEME;
|
|
2691
2864
|
this.cacheManager = new CacheManager();
|
|
2865
|
+
this.usageParser = new UsageParser();
|
|
2692
2866
|
}
|
|
2693
2867
|
/**
|
|
2694
2868
|
* Set display style
|
|
@@ -2705,16 +2879,14 @@ var init_cache_metrics_widget = __esm({
|
|
|
2705
2879
|
/**
|
|
2706
2880
|
* Calculate cache metrics from context usage data
|
|
2707
2881
|
* Returns zero metrics if no usage data is available (widget should always be visible)
|
|
2882
|
+
*
|
|
2883
|
+
* @param usage - Current usage data (for total tokens calculation)
|
|
2884
|
+
* @param cumulativeCache - Cumulative cache data for the session (optional)
|
|
2708
2885
|
*/
|
|
2709
|
-
calculateMetrics(
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
if (cached) {
|
|
2714
|
-
usage = cached.usage;
|
|
2715
|
-
}
|
|
2716
|
-
}
|
|
2717
|
-
if (!usage) {
|
|
2886
|
+
calculateMetrics(usage, cumulativeCache) {
|
|
2887
|
+
const cacheRead = cumulativeCache?.cacheRead ?? usage?.cache_read_input_tokens ?? 0;
|
|
2888
|
+
const cacheWrite = cumulativeCache?.cacheCreation ?? usage?.cache_creation_input_tokens ?? 0;
|
|
2889
|
+
if (!usage && !cumulativeCache) {
|
|
2718
2890
|
return {
|
|
2719
2891
|
cacheRead: 0,
|
|
2720
2892
|
cacheWrite: 0,
|
|
@@ -2723,10 +2895,8 @@ var init_cache_metrics_widget = __esm({
|
|
|
2723
2895
|
savings: 0
|
|
2724
2896
|
};
|
|
2725
2897
|
}
|
|
2726
|
-
const
|
|
2727
|
-
const
|
|
2728
|
-
const inputTokens = usage.input_tokens ?? 0;
|
|
2729
|
-
const outputTokens = usage.output_tokens ?? 0;
|
|
2898
|
+
const inputTokens = usage?.input_tokens ?? 0;
|
|
2899
|
+
const outputTokens = usage?.output_tokens ?? 0;
|
|
2730
2900
|
const totalInputTokens = cacheRead + cacheWrite + inputTokens;
|
|
2731
2901
|
const totalTokens = totalInputTokens + outputTokens;
|
|
2732
2902
|
const hitRate = totalInputTokens > 0 ? Math.min(100, Math.round(cacheRead / totalInputTokens * 100)) : 0;
|
|
@@ -2763,16 +2933,35 @@ var init_cache_metrics_widget = __esm({
|
|
|
2763
2933
|
});
|
|
2764
2934
|
}
|
|
2765
2935
|
}
|
|
2766
|
-
const
|
|
2767
|
-
|
|
2936
|
+
const hasRealUsage = usage && ((usage.input_tokens ?? 0) > 0 || (usage.output_tokens ?? 0) > 0 || (usage.cache_read_input_tokens ?? 0) > 0 || (usage.cache_creation_input_tokens ?? 0) > 0);
|
|
2937
|
+
if (!usage || !hasRealUsage) {
|
|
2938
|
+
this.cachedUsage = await this.usageParser.parseLastUsage(data.transcript_path);
|
|
2939
|
+
} else {
|
|
2940
|
+
this.cachedUsage = void 0;
|
|
2941
|
+
}
|
|
2942
|
+
this.cachedCumulativeCache = await this.usageParser.parseCumulativeCache(data.transcript_path);
|
|
2768
2943
|
}
|
|
2769
2944
|
/**
|
|
2770
2945
|
* Render the cache metrics display
|
|
2771
2946
|
*/
|
|
2772
|
-
renderWithData(
|
|
2773
|
-
|
|
2947
|
+
renderWithData(data, _context) {
|
|
2948
|
+
let usage = data.context_window?.current_usage;
|
|
2949
|
+
const hasRealUsage = usage && ((usage.input_tokens ?? 0) > 0 || (usage.output_tokens ?? 0) > 0 || (usage.cache_read_input_tokens ?? 0) > 0 || (usage.cache_creation_input_tokens ?? 0) > 0);
|
|
2950
|
+
if ((!usage || !hasRealUsage) && this.cachedUsage) {
|
|
2951
|
+
usage = this.cachedUsage;
|
|
2952
|
+
}
|
|
2953
|
+
if (!usage) {
|
|
2954
|
+
const cached = this.cacheManager.getCachedUsage(data.session_id);
|
|
2955
|
+
if (cached) {
|
|
2956
|
+
usage = cached.usage;
|
|
2957
|
+
}
|
|
2958
|
+
}
|
|
2959
|
+
const cumulativeCacheToUse = this.cachedCumulativeCache;
|
|
2960
|
+
const metrics = this.calculateMetrics(usage, cumulativeCacheToUse);
|
|
2961
|
+
if (!metrics) {
|
|
2774
2962
|
return null;
|
|
2775
2963
|
}
|
|
2964
|
+
this.renderData = metrics;
|
|
2776
2965
|
const styleFn = cacheMetricsStyles[this.style] ?? cacheMetricsStyles.balanced;
|
|
2777
2966
|
if (!styleFn) {
|
|
2778
2967
|
return null;
|
|
@@ -3259,6 +3448,7 @@ var init_context_widget = __esm({
|
|
|
3259
3448
|
"src/widgets/context-widget.ts"() {
|
|
3260
3449
|
"use strict";
|
|
3261
3450
|
init_widget_types();
|
|
3451
|
+
init_usage_parser();
|
|
3262
3452
|
init_cache_manager();
|
|
3263
3453
|
init_theme();
|
|
3264
3454
|
init_styles4();
|
|
@@ -3277,11 +3467,15 @@ var init_context_widget = __esm({
|
|
|
3277
3467
|
_lineOverride;
|
|
3278
3468
|
styleFn = contextStyles.balanced;
|
|
3279
3469
|
cacheManager;
|
|
3470
|
+
usageParser;
|
|
3280
3471
|
lastSessionId;
|
|
3472
|
+
cachedUsage;
|
|
3473
|
+
// Cache parsed usage within render cycle
|
|
3281
3474
|
constructor(colors2) {
|
|
3282
3475
|
super();
|
|
3283
3476
|
this.colors = colors2 ?? DEFAULT_THEME;
|
|
3284
3477
|
this.cacheManager = new CacheManager();
|
|
3478
|
+
this.usageParser = new UsageParser();
|
|
3285
3479
|
}
|
|
3286
3480
|
setStyle(style = "balanced") {
|
|
3287
3481
|
const fn = contextStyles[style];
|
|
@@ -3314,10 +3508,20 @@ var init_context_widget = __esm({
|
|
|
3314
3508
|
});
|
|
3315
3509
|
}
|
|
3316
3510
|
}
|
|
3511
|
+
const hasRealUsage = current_usage && ((current_usage.input_tokens ?? 0) > 0 || (current_usage.output_tokens ?? 0) > 0 || (current_usage.cache_read_input_tokens ?? 0) > 0 || (current_usage.cache_creation_input_tokens ?? 0) > 0);
|
|
3512
|
+
if (!current_usage || !hasRealUsage) {
|
|
3513
|
+
this.cachedUsage = await this.usageParser.parseLastUsage(data.transcript_path);
|
|
3514
|
+
} else {
|
|
3515
|
+
this.cachedUsage = void 0;
|
|
3516
|
+
}
|
|
3317
3517
|
}
|
|
3318
3518
|
renderWithData(data, _context) {
|
|
3319
3519
|
const { current_usage, context_window_size } = data.context_window;
|
|
3320
3520
|
let usage = current_usage;
|
|
3521
|
+
const hasRealUsage = usage && ((usage.input_tokens ?? 0) > 0 || (usage.output_tokens ?? 0) > 0 || (usage.cache_read_input_tokens ?? 0) > 0 || (usage.cache_creation_input_tokens ?? 0) > 0);
|
|
3522
|
+
if ((!usage || !hasRealUsage) && this.cachedUsage) {
|
|
3523
|
+
usage = this.cachedUsage;
|
|
3524
|
+
}
|
|
3321
3525
|
if (!usage) {
|
|
3322
3526
|
const cached = this.cacheManager.getCachedUsage(data.session_id);
|
|
3323
3527
|
if (cached) {
|