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 +4 -4
- data/README.md +21 -3
- data/lib/token_lens/cli.rb +5 -1
- data/lib/token_lens/commands/record.rb +3 -2
- data/lib/token_lens/session.rb +17 -4
- data/lib/token_lens/sources/jsonl.rb +2 -2
- data/lib/token_lens/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5df4aa9d712d04ae90513777b2b34b541bb3b77038fadd637725f1bf1599db3f
|
|
4
|
+
data.tar.gz: 52f773f6c7bfd677a29bef81ba14bb23e2b01ec54071468ee6ba7be2e4632b9a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
|
data/lib/token_lens/cli.rb
CHANGED
|
@@ -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(
|
|
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) }
|
data/lib/token_lens/session.rb
CHANGED
|
@@ -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
|
data/lib/token_lens/version.rb
CHANGED