Add Claude Code usage tracking - #1
Conversation
Greptile Summary
Important Files Changed
Confidence score: 2/5
Sequence DiagramsequenceDiagram
participant User
participant Monitor
participant UsageWatcher
participant TmuxClient
participant ClaudeDetector
participant UsageParser
participant FileSystem
User->>Monitor: "Start monitoring"
Monitor->>UsageWatcher: "Start()"
Monitor->>Monitor: "Start poll loop"
loop Every poll interval
Monitor->>TmuxClient: "ListSessions()"
TmuxClient-->>Monitor: "tmux sessions"
loop For each tmux session
Monitor->>TmuxClient: "CapturePane()"
TmuxClient-->>Monitor: "pane content"
Monitor->>ClaudeDetector: "IsClaudeSession(content)"
ClaudeDetector-->>Monitor: "true/false"
alt Claude session found
Monitor->>TmuxClient: "GetSessionPath()"
TmuxClient-->>Monitor: "working directory"
Monitor->>UsageWatcher: "WatchSession(name, workingDir)"
UsageWatcher->>FileSystem: "FindProjectDir(workingDir)"
FileSystem-->>UsageWatcher: "Claude project path"
UsageWatcher->>FileSystem: "FindSessionFiles()"
FileSystem-->>UsageWatcher: "JSONL files"
end
end
alt Usage update cycle
Monitor->>Monitor: "updateUsage()"
loop For each session
Monitor->>UsageParser: "GetMostRecentSession(workingDir)"
UsageParser->>FileSystem: "FindActiveSessionFile()"
FileSystem-->>UsageParser: "latest JSONL file"
UsageParser->>FileSystem: "ParseSessionFile()"
FileSystem-->>UsageParser: "token usage data"
UsageParser->>UsageParser: "CalculateCost()"
UsageParser-->>Monitor: "SessionUsage with cost"
end
end
end
Monitor-->>User: "Display usage in TUI"
|
There was a problem hiding this comment.
Additional Comments (1)
-
.github/workflows/release.yml, line 149 (link)syntax: Same Go version issue - 1.25.0 doesn't exist yet
10 files reviewed, 3 comments
| - name: Set up Go | ||
| uses: actions/setup-go@v5 | ||
| with: | ||
| go-version: "1.25.0" |
There was a problem hiding this comment.
syntax: Go 1.25.0 has not been released. Latest stable is 1.23.x. Change to "1.23" or "stable"
| go-version: "1.25.0" | |
| go-version: "1.23" |
Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/ci.yml
Line: 19:19
Comment:
**syntax:** Go 1.25.0 has not been released. Latest stable is 1.23.x. Change to `"1.23"` or `"stable"`
```suggestion
go-version: "1.23"
```
How can I resolve this? If you propose a fix, please make it concise.| func ParseSessionFileTail(path string, tailBytes int64) (*SessionUsage, error) { | ||
| file, err := os.Open(path) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| defer file.Close() | ||
|
|
||
| info, err := file.Stat() | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| // If file is small enough, parse the whole thing | ||
| if info.Size() <= tailBytes { | ||
| return ParseSessionFile(path) | ||
| } | ||
|
|
||
| // Seek to near the end | ||
| _, err = file.Seek(-tailBytes, 2) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| usage := &SessionUsage{ | ||
| SessionID: filepath.Base(strings.TrimSuffix(path, ".jsonl")), | ||
| ProjectPath: filepath.Dir(path), | ||
| LastUpdated: time.Now(), | ||
| } | ||
|
|
||
| scanner := bufio.NewScanner(file) | ||
| buf := make([]byte, 0, 1024*1024) | ||
| scanner.Buffer(buf, 10*1024*1024) | ||
|
|
||
| first := true | ||
| for scanner.Scan() { | ||
| line := scanner.Bytes() | ||
| // Skip partial first line when reading from middle | ||
| if first { | ||
| first = false | ||
| continue | ||
| } | ||
| if len(line) == 0 { | ||
| continue | ||
| } | ||
|
|
||
| var msg jsonlMessage | ||
| if err := json.Unmarshal(line, &msg); err != nil { | ||
| continue | ||
| } | ||
|
|
||
| if msg.Type == "assistant" { | ||
| usage.TotalUsage.Add(TokenUsage{ | ||
| InputTokens: msg.Message.Usage.InputTokens, | ||
| OutputTokens: msg.Message.Usage.OutputTokens, | ||
| CacheCreationInputTokens: msg.Message.Usage.CacheCreationInputTokens, | ||
| CacheReadInputTokens: msg.Message.Usage.CacheReadInputTokens, | ||
| }) | ||
| if msg.Message.Model != "" { | ||
| usage.Model = msg.Message.Model | ||
| } | ||
| } | ||
| } | ||
|
|
||
| return usage, nil | ||
| } |
There was a problem hiding this comment.
logic: ParseSessionFileTail only counts tokens from the tail portion of the file, missing tokens from earlier in the session. This will underreport usage for long sessions.
If you want to use tail for efficiency, you need to parse the entire file at least once and cache it, or document that this function gives partial results. Currently it's misleading because it returns *SessionUsage which implies complete session data.
Prompt To Fix With AI
This is a comment left during a code review.
Path: internal/usage/parser.go
Line: 76:140
Comment:
**logic:** `ParseSessionFileTail` only counts tokens from the tail portion of the file, missing tokens from earlier in the session. This will underreport usage for long sessions.
If you want to use tail for efficiency, you need to parse the entire file at least once and cache it, or document that this function gives partial results. Currently it's misleading because it returns `*SessionUsage` which implies complete session data.
How can I resolve this? If you propose a fix, please make it concise.| if _, exists := w.sessions[sessionName]; !exists { | ||
| w.sessions[sessionName] = &sessionWatch{ | ||
| sessionFile: mostRecent, | ||
| } | ||
| } |
There was a problem hiding this comment.
logic: If a session already exists, this silently ignores the new workingDir and keeps watching the old file. This could cause missed updates if the session moves to a different project directory. Should existing sessions be updated to watch the new working directory, or is it intentional to keep watching the original file?
Prompt To Fix With AI
This is a comment left during a code review.
Path: internal/usage/watcher.go
Line: 88:92
Comment:
**logic:** If a session already exists, this silently ignores the new `workingDir` and keeps watching the old file. This could cause missed updates if the session moves to a different project directory. Should existing sessions be updated to watch the new working directory, or is it intentional to keep watching the original file?
How can I resolve this? If you propose a fix, please make it concise.4f3f8a2 to
c0452e5
Compare
c0452e5 to
7c3d3fb
Compare
Summary
~/.claude/projects/<project>/*.jsonl) to display usage metricsChanges
internal/usage/package with types, parser, pricing, and watcherinternal/daemon/monitor.goto track usage per sessioninternal/tui/view.goto render usage infoToken Pricing (per 1M tokens)
Test plan
🤖 Generated with Claude Code