token-lens 0.1.0 → 0.3.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fc58978bdc3f4759309ded99d65da22be12a01287ea79acdb43ab873e7cb8771
4
- data.tar.gz: 34c54363d13e72ed669e3f27bbf1fc8af2d3665e958d977baabfaac9ab80f849
3
+ metadata.gz: 5df4aa9d712d04ae90513777b2b34b541bb3b77038fadd637725f1bf1599db3f
4
+ data.tar.gz: 52f773f6c7bfd677a29bef81ba14bb23e2b01ec54071468ee6ba7be2e4632b9a
5
5
  SHA512:
6
- metadata.gz: 3f3c35dedc0cd0efd6e12b8d136aab7f4328ba4619f912f07c94727e3bd6c4c2bb4184d07a9e3bbb117dd0eaeec28edd27c5f7100f140a79b12043773a066881
7
- data.tar.gz: d0767d26c77b4ba6dfec6f3a40b70c7d1dde3b3a58094fa8707b4bf57bc860612ed1af91c161b31fc3f3faa78f3db25ed6f5ddc3ae2f9422ca351084e3d5ec41
6
+ metadata.gz: 0b271f96c07b9c74db5ca42e4ffff7a7259e5a63893e949a9ab0fc3dd2bc4761df0c783151769a42cd320dc6e5574ae408a5b2dbfe2133cc839bab60d12f638a
7
+ data.tar.gz: 8f296614fd7f957189e07961223fea18a2242fee5f090860a2b49d6f69daf90f92dadc87a289ce4b22cbaf739d0d25cfdfbd2c2cac062fe4ed7e23f952db156c
data/README.md CHANGED
@@ -10,9 +10,27 @@ Record Data --> Interpret Data --> Render Data
10
10
 
11
11
  ## Data Sources
12
12
 
13
- 1. Tap OTEL console output
14
- 2. Tail session JSONL
15
- 3. Local API proxy
13
+ 1. [unsupported] Tap OTEL console output
14
+ 2. [supported] Tail session JSONL
15
+ 3. [unsupported] Local API proxy
16
+
17
+ ## Quick Start
18
+
19
+
20
+ **Locally**:
21
+ ```
22
+ bin/token-lens record --duration-in-seconds=30 > capture.json
23
+ bin/token-lens render --file-path=capture.json
24
+ open flame.html
25
+ ```
26
+
27
+ **Via gem**:
28
+ ```
29
+ gem install token-lens
30
+ token-lens record --duration-in-seconds=30 > capture.json
31
+ token-lens render --file-path=capture.json
32
+ open flame.html
33
+ ```
16
34
 
17
35
  ## Contributing
18
36
 
@@ -8,8 +8,12 @@ module TokenLens
8
8
  class CLI < Thor
9
9
  desc "record", "Tail the active session and capture events to stdout"
10
10
  option :duration_in_seconds, type: :numeric, default: 30, desc: "Seconds to record"
11
+ option :project_dir, type: :string, desc: "Working directory of the Claude Code session to record (default: auto-detect)"
11
12
  def record
12
- Commands::Record.new(duration_in_seconds: options[:duration_in_seconds]).run
13
+ Commands::Record.new(
14
+ duration_in_seconds: options[:duration_in_seconds],
15
+ project_dir: options[:project_dir]
16
+ ).run
13
17
  end
14
18
 
15
19
  desc "render", "Render a captured session as a flame graph"
@@ -6,8 +6,9 @@ require "token_lens/sources/jsonl"
6
6
  module TokenLens
7
7
  module Commands
8
8
  class Record
9
- def initialize(duration_in_seconds:)
9
+ def initialize(duration_in_seconds:, project_dir: nil)
10
10
  @duration_in_seconds = duration_in_seconds
11
+ @project_dir = project_dir
11
12
  end
12
13
 
13
14
  def run
@@ -16,7 +17,7 @@ module TokenLens
16
17
  queue = Queue.new
17
18
  events = []
18
19
 
19
- thread = Thread.new { Sources::Jsonl.new(queue).start }
20
+ thread = Thread.new { Sources::Jsonl.new(queue, project_dir: @project_dir).start }
20
21
  drain_thread = Thread.new { loop { events << queue.pop } }
21
22
 
22
23
  trap("INT") { finish(thread, drain_thread, queue, events) }
@@ -16,15 +16,28 @@ module TokenLens
16
16
 
17
17
  def self.active_jsonl(dir = Dir.pwd)
18
18
  project_dir = CLAUDE_DIR / encoded_cwd(dir)
19
-
20
- # find all *.jsonl files in the project directory
21
19
  jsonl_files = project_dir.glob("*.jsonl")
22
20
  raise "No session files found in #{project_dir}" if jsonl_files.empty?
23
-
24
- # get most recently modified file
25
21
  jsonl_files.max_by(&:mtime)
26
22
  end
27
23
 
24
+ # Returns the most recently modified session file across ALL projects.
25
+ def self.latest_jsonl
26
+ all = CLAUDE_DIR.glob("*/*.jsonl")
27
+ raise "No session files found in #{CLAUDE_DIR}" if all.empty?
28
+ all.max_by(&:mtime)
29
+ end
30
+
31
+ # Like active_jsonl but falls back to latest_jsonl with a warning when
32
+ # the current directory has no sessions (e.g. running from ~/Desktop).
33
+ def self.active_or_latest_jsonl(dir = Dir.pwd)
34
+ active_jsonl(dir)
35
+ rescue RuntimeError
36
+ path = latest_jsonl
37
+ warn " [session] no sessions for #{dir}, using most recent: #{path}"
38
+ path
39
+ end
40
+
28
41
  def self.tail(path, &block)
29
42
  last_pos = File.size(path)
30
43
  loop do
@@ -6,9 +6,9 @@ require "token_lens/session"
6
6
  module TokenLens
7
7
  module Sources
8
8
  class Jsonl
9
- def initialize(queue)
9
+ def initialize(queue, project_dir: nil)
10
10
  @queue = queue
11
- @path = Session.active_jsonl
11
+ @path = project_dir ? Session.active_jsonl(project_dir) : Session.active_or_latest_jsonl
12
12
  end
13
13
 
14
14
  def start
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TokenLens
4
- VERSION = "0.1.0"
4
+ VERSION = "0.3.0"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: token-lens
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - rob durst