claude-scope 0.8.32 → 0.8.34

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/dist/claude-scope.cjs +151 -38
  2. package/package.json +1 -1
@@ -2413,12 +2413,96 @@ var init_widget_types = __esm({
2413
2413
  }
2414
2414
  });
2415
2415
 
2416
+ // src/providers/usage-parser.ts
2417
+ var import_node_fs, import_node_readline, UsageParser;
2418
+ var init_usage_parser = __esm({
2419
+ "src/providers/usage-parser.ts"() {
2420
+ "use strict";
2421
+ import_node_fs = require("node:fs");
2422
+ import_node_readline = require("node: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_node_fs.existsSync)(transcriptPath)) {
2433
+ return null;
2434
+ }
2435
+ try {
2436
+ const lines = await this.readAllLines(transcriptPath);
2437
+ for (let i = lines.length - 1; i >= 0; i--) {
2438
+ const usage = this.parseLineForUsage(lines[i]);
2439
+ if (usage) {
2440
+ return usage;
2441
+ }
2442
+ }
2443
+ return null;
2444
+ } catch {
2445
+ return null;
2446
+ }
2447
+ }
2448
+ /**
2449
+ * Read all lines from transcript file
2450
+ */
2451
+ async readAllLines(transcriptPath) {
2452
+ const lines = [];
2453
+ try {
2454
+ const fileStream = (0, import_node_fs.createReadStream)(transcriptPath, { encoding: "utf-8" });
2455
+ const rl = (0, import_node_readline.createInterface)({
2456
+ input: fileStream,
2457
+ crlfDelay: Infinity
2458
+ });
2459
+ for await (const line of rl) {
2460
+ if (line.trim()) {
2461
+ lines.push(line);
2462
+ }
2463
+ }
2464
+ } catch {
2465
+ return [];
2466
+ }
2467
+ return lines;
2468
+ }
2469
+ /**
2470
+ * Parse a single transcript line for usage data
2471
+ * Returns null if line is not an assistant message with usage
2472
+ */
2473
+ parseLineForUsage(line) {
2474
+ try {
2475
+ const entry = JSON.parse(line);
2476
+ if (entry.type !== "assistant") {
2477
+ return null;
2478
+ }
2479
+ const usage = entry.message?.usage;
2480
+ if (!usage) {
2481
+ return null;
2482
+ }
2483
+ if (typeof usage.input_tokens !== "number" || typeof usage.output_tokens !== "number" || typeof usage.cache_read_input_tokens !== "number") {
2484
+ return null;
2485
+ }
2486
+ return {
2487
+ input_tokens: usage.input_tokens,
2488
+ output_tokens: usage.output_tokens,
2489
+ cache_creation_input_tokens: usage.cache_creation_input_tokens ?? 0,
2490
+ cache_read_input_tokens: usage.cache_read_input_tokens
2491
+ };
2492
+ } catch {
2493
+ return null;
2494
+ }
2495
+ }
2496
+ };
2497
+ }
2498
+ });
2499
+
2416
2500
  // src/storage/cache-manager.ts
2417
- var import_node_fs, import_node_os2, import_node_path2, DEFAULT_CACHE_PATH, DEFAULT_EXPIRY_MS, CacheManager;
2501
+ var import_node_fs2, import_node_os2, import_node_path2, DEFAULT_CACHE_PATH, DEFAULT_EXPIRY_MS, CacheManager;
2418
2502
  var init_cache_manager = __esm({
2419
2503
  "src/storage/cache-manager.ts"() {
2420
2504
  "use strict";
2421
- import_node_fs = require("node:fs");
2505
+ import_node_fs2 = require("node:fs");
2422
2506
  import_node_os2 = require("node:os");
2423
2507
  import_node_path2 = require("node:path");
2424
2508
  DEFAULT_CACHE_PATH = `${(0, import_node_os2.homedir)()}/.config/claude-scope/cache.json`;
@@ -2491,11 +2575,11 @@ var init_cache_manager = __esm({
2491
2575
  * Load cache from file
2492
2576
  */
2493
2577
  loadCache() {
2494
- if (!(0, import_node_fs.existsSync)(this.cachePath)) {
2578
+ if (!(0, import_node_fs2.existsSync)(this.cachePath)) {
2495
2579
  return { sessions: {}, version: 1 };
2496
2580
  }
2497
2581
  try {
2498
- const content = (0, import_node_fs.readFileSync)(this.cachePath, "utf-8");
2582
+ const content = (0, import_node_fs2.readFileSync)(this.cachePath, "utf-8");
2499
2583
  return JSON.parse(content);
2500
2584
  } catch {
2501
2585
  return { sessions: {}, version: 1 };
@@ -2506,7 +2590,7 @@ var init_cache_manager = __esm({
2506
2590
  */
2507
2591
  saveCache(cache) {
2508
2592
  try {
2509
- (0, import_node_fs.writeFileSync)(this.cachePath, JSON.stringify(cache, null, 2), "utf-8");
2593
+ (0, import_node_fs2.writeFileSync)(this.cachePath, JSON.stringify(cache, null, 2), "utf-8");
2510
2594
  } catch {
2511
2595
  }
2512
2596
  }
@@ -2516,8 +2600,8 @@ var init_cache_manager = __esm({
2516
2600
  ensureCacheDir() {
2517
2601
  try {
2518
2602
  const dir = (0, import_node_path2.dirname)(this.cachePath);
2519
- if (!(0, import_node_fs.existsSync)(dir)) {
2520
- (0, import_node_fs.mkdirSync)(dir, { recursive: true });
2603
+ if (!(0, import_node_fs2.existsSync)(dir)) {
2604
+ (0, import_node_fs2.mkdirSync)(dir, { recursive: true });
2521
2605
  }
2522
2606
  } catch {
2523
2607
  }
@@ -2665,6 +2749,7 @@ var init_cache_metrics_widget = __esm({
2665
2749
  "src/widgets/cache-metrics/cache-metrics-widget.ts"() {
2666
2750
  "use strict";
2667
2751
  init_widget_types();
2752
+ init_usage_parser();
2668
2753
  init_cache_manager();
2669
2754
  init_theme();
2670
2755
  init_stdin_data_widget();
@@ -2684,11 +2769,15 @@ var init_cache_metrics_widget = __esm({
2684
2769
  style = "balanced";
2685
2770
  renderData;
2686
2771
  cacheManager;
2772
+ usageParser;
2687
2773
  lastSessionId;
2774
+ cachedUsage;
2775
+ // Cache parsed usage within render cycle
2688
2776
  constructor(theme) {
2689
2777
  super();
2690
2778
  this.theme = theme ?? DEFAULT_THEME;
2691
2779
  this.cacheManager = new CacheManager();
2780
+ this.usageParser = new UsageParser();
2692
2781
  }
2693
2782
  /**
2694
2783
  * Set display style
@@ -2706,14 +2795,7 @@ var init_cache_metrics_widget = __esm({
2706
2795
  * Calculate cache metrics from context usage data
2707
2796
  * Returns zero metrics if no usage data is available (widget should always be visible)
2708
2797
  */
2709
- calculateMetrics(data) {
2710
- let usage = data.context_window?.current_usage;
2711
- if (!usage) {
2712
- const cached = this.cacheManager.getCachedUsage(data.session_id);
2713
- if (cached) {
2714
- usage = cached.usage;
2715
- }
2716
- }
2798
+ calculateMetrics(usage) {
2717
2799
  if (!usage) {
2718
2800
  return {
2719
2801
  cacheRead: 0,
@@ -2752,24 +2834,42 @@ var init_cache_metrics_widget = __esm({
2752
2834
  }
2753
2835
  this.lastSessionId = data.session_id;
2754
2836
  const usage = data.context_window?.current_usage;
2755
- if (usage && usage.input_tokens > 0 && !sessionChanged) {
2756
- this.cacheManager.setCachedUsage(data.session_id, {
2757
- input_tokens: usage.input_tokens,
2758
- output_tokens: usage.output_tokens,
2759
- cache_creation_input_tokens: usage.cache_creation_input_tokens,
2760
- cache_read_input_tokens: usage.cache_read_input_tokens
2761
- });
2837
+ if (usage && !sessionChanged) {
2838
+ const hasAnyTokens = (usage.input_tokens ?? 0) > 0 || (usage.output_tokens ?? 0) > 0 || (usage.cache_creation_input_tokens ?? 0) > 0 || (usage.cache_read_input_tokens ?? 0) > 0;
2839
+ if (hasAnyTokens) {
2840
+ this.cacheManager.setCachedUsage(data.session_id, {
2841
+ input_tokens: usage.input_tokens,
2842
+ output_tokens: usage.output_tokens,
2843
+ cache_creation_input_tokens: usage.cache_creation_input_tokens,
2844
+ cache_read_input_tokens: usage.cache_read_input_tokens
2845
+ });
2846
+ }
2847
+ }
2848
+ if (!usage) {
2849
+ this.cachedUsage = await this.usageParser.parseLastUsage(data.transcript_path);
2850
+ } else {
2851
+ this.cachedUsage = void 0;
2762
2852
  }
2763
- const metrics = this.calculateMetrics(data);
2764
- this.renderData = metrics ?? void 0;
2765
2853
  }
2766
2854
  /**
2767
2855
  * Render the cache metrics display
2768
2856
  */
2769
- renderWithData(_data, _context) {
2770
- if (!this.renderData) {
2857
+ renderWithData(data, _context) {
2858
+ let usage = data.context_window?.current_usage;
2859
+ if (!usage && this.cachedUsage) {
2860
+ usage = this.cachedUsage;
2861
+ }
2862
+ if (!usage) {
2863
+ const cached = this.cacheManager.getCachedUsage(data.session_id);
2864
+ if (cached) {
2865
+ usage = cached.usage;
2866
+ }
2867
+ }
2868
+ const metrics = this.calculateMetrics(usage);
2869
+ if (!metrics) {
2771
2870
  return null;
2772
2871
  }
2872
+ this.renderData = metrics;
2773
2873
  const styleFn = cacheMetricsStyles[this.style] ?? cacheMetricsStyles.balanced;
2774
2874
  if (!styleFn) {
2775
2875
  return null;
@@ -3256,6 +3356,7 @@ var init_context_widget = __esm({
3256
3356
  "src/widgets/context-widget.ts"() {
3257
3357
  "use strict";
3258
3358
  init_widget_types();
3359
+ init_usage_parser();
3259
3360
  init_cache_manager();
3260
3361
  init_theme();
3261
3362
  init_styles4();
@@ -3274,11 +3375,15 @@ var init_context_widget = __esm({
3274
3375
  _lineOverride;
3275
3376
  styleFn = contextStyles.balanced;
3276
3377
  cacheManager;
3378
+ usageParser;
3277
3379
  lastSessionId;
3380
+ cachedUsage;
3381
+ // Cache parsed usage within render cycle
3278
3382
  constructor(colors2) {
3279
3383
  super();
3280
3384
  this.colors = colors2 ?? DEFAULT_THEME;
3281
3385
  this.cacheManager = new CacheManager();
3386
+ this.usageParser = new UsageParser();
3282
3387
  }
3283
3388
  setStyle(style = "balanced") {
3284
3389
  const fn = contextStyles[style];
@@ -3311,10 +3416,18 @@ var init_context_widget = __esm({
3311
3416
  });
3312
3417
  }
3313
3418
  }
3419
+ if (!current_usage) {
3420
+ this.cachedUsage = await this.usageParser.parseLastUsage(data.transcript_path);
3421
+ } else {
3422
+ this.cachedUsage = void 0;
3423
+ }
3314
3424
  }
3315
3425
  renderWithData(data, _context) {
3316
3426
  const { current_usage, context_window_size } = data.context_window;
3317
3427
  let usage = current_usage;
3428
+ if (!usage && this.cachedUsage) {
3429
+ usage = this.cachedUsage;
3430
+ }
3318
3431
  if (!usage) {
3319
3432
  const cached = this.cacheManager.getCachedUsage(data.session_id);
3320
3433
  if (cached) {
@@ -26146,8 +26259,8 @@ init_renderer();
26146
26259
  init_widget_registry();
26147
26260
 
26148
26261
  // src/providers/transcript-provider.ts
26149
- var import_node_fs2 = require("node:fs");
26150
- var import_node_readline = require("node:readline");
26262
+ var import_node_fs3 = require("node:fs");
26263
+ var import_node_readline2 = require("node:readline");
26151
26264
  var TranscriptProvider = class {
26152
26265
  MAX_TOOLS = 20;
26153
26266
  /**
@@ -26156,13 +26269,13 @@ var TranscriptProvider = class {
26156
26269
  * @returns Array of tool entries, limited to last 20
26157
26270
  */
26158
26271
  async parseTools(transcriptPath) {
26159
- if (!(0, import_node_fs2.existsSync)(transcriptPath)) {
26272
+ if (!(0, import_node_fs3.existsSync)(transcriptPath)) {
26160
26273
  return [];
26161
26274
  }
26162
26275
  const toolMap = /* @__PURE__ */ new Map();
26163
26276
  try {
26164
- const fileStream = (0, import_node_fs2.createReadStream)(transcriptPath, { encoding: "utf-8" });
26165
- const rl = (0, import_node_readline.createInterface)({
26277
+ const fileStream = (0, import_node_fs3.createReadStream)(transcriptPath, { encoding: "utf-8" });
26278
+ const rl = (0, import_node_readline2.createInterface)({
26166
26279
  input: fileStream,
26167
26280
  crlfDelay: Infinity
26168
26281
  });
@@ -26441,13 +26554,13 @@ async function routeCommand(command) {
26441
26554
  }
26442
26555
 
26443
26556
  // src/config/config-loader.ts
26444
- var import_node_fs4 = require("node:fs");
26557
+ var import_node_fs5 = require("node:fs");
26445
26558
  var import_promises2 = require("node:fs/promises");
26446
26559
  var import_node_os4 = require("node:os");
26447
26560
  var import_node_path4 = require("node:path");
26448
26561
 
26449
26562
  // src/config/default-config-generator.ts
26450
- var import_node_fs3 = require("node:fs");
26563
+ var import_node_fs4 = require("node:fs");
26451
26564
  var import_node_os3 = require("node:os");
26452
26565
  var import_node_path3 = require("node:path");
26453
26566
  function getDefaultConfigPath() {
@@ -26455,15 +26568,15 @@ function getDefaultConfigPath() {
26455
26568
  }
26456
26569
  async function ensureDefaultConfig() {
26457
26570
  const configPath = getDefaultConfigPath();
26458
- if ((0, import_node_fs3.existsSync)(configPath)) {
26571
+ if ((0, import_node_fs4.existsSync)(configPath)) {
26459
26572
  return;
26460
26573
  }
26461
26574
  const configDir = (0, import_node_path3.join)((0, import_node_os3.homedir)(), ".claude-scope");
26462
- if (!(0, import_node_fs3.existsSync)(configDir)) {
26463
- (0, import_node_fs3.mkdirSync)(configDir, { recursive: true });
26575
+ if (!(0, import_node_fs4.existsSync)(configDir)) {
26576
+ (0, import_node_fs4.mkdirSync)(configDir, { recursive: true });
26464
26577
  }
26465
26578
  const defaultConfig = generateRichLayout("balanced", "dracula");
26466
- (0, import_node_fs3.writeFileSync)(configPath, JSON.stringify(defaultConfig, null, 2), "utf-8");
26579
+ (0, import_node_fs4.writeFileSync)(configPath, JSON.stringify(defaultConfig, null, 2), "utf-8");
26467
26580
  }
26468
26581
 
26469
26582
  // src/config/config-loader.ts
@@ -26476,7 +26589,7 @@ function getConfigPath() {
26476
26589
  async function loadWidgetConfig() {
26477
26590
  const configPath = getConfigPath();
26478
26591
  await ensureDefaultConfig();
26479
- if (!(0, import_node_fs4.existsSync)(configPath)) {
26592
+ if (!(0, import_node_fs5.existsSync)(configPath)) {
26480
26593
  return null;
26481
26594
  }
26482
26595
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-scope",
3
- "version": "0.8.32",
3
+ "version": "0.8.34",
4
4
  "description": "Claude Code plugin for session status and analytics",
5
5
  "license": "MIT",
6
6
  "type": "module",