Files
claude-code/dashboard/internal/claude/history_tailer.go
OpenCode Test ae958528a6 Add Claude integration to dashboard
Add comprehensive Claude Code monitoring and realtime streaming to the K8s dashboard.
Includes API endpoints for health, stats, summary, inventory, and live event streaming.
Frontend provides overview, usage, inventory, debug, and live feed views.
2026-01-03 10:54:48 -08:00

106 lines
1.9 KiB
Go

package claude
import (
"bufio"
"encoding/json"
"os"
"time"
)
func TailHistoryFile(stop <-chan struct{}, hub *EventHub, path string) {
var offset int64
for {
select {
case <-stop:
return
default:
}
stat, err := os.Stat(path)
if err != nil {
if !os.IsNotExist(err) {
hub.Publish(Event{
TS: time.Now(),
Type: EventTypeServerError,
Data: map[string]any{"error": err.Error()},
})
}
time.Sleep(1 * time.Second)
continue
}
size := stat.Size()
if size > offset {
if err := processNewBytes(path, offset, size, hub); err != nil {
hub.Publish(Event{
TS: time.Now(),
Type: EventTypeServerError,
Data: map[string]any{"error": err.Error()},
})
}
offset = size
} else if size < offset {
offset = 0
hub.Publish(Event{
TS: time.Now(),
Type: EventTypeServerNotice,
Data: map[string]any{"msg": "file truncated, resetting offset"},
})
}
time.Sleep(500 * time.Millisecond)
}
}
func processNewBytes(path string, oldSize, newSize int64, hub *EventHub) error {
f, err := os.Open(path)
if err != nil {
return err
}
defer f.Close()
if _, err := f.Seek(oldSize, 0); err != nil {
return err
}
scanner := bufio.NewScanner(f)
for scanner.Scan() {
line := scanner.Text()
if line == "" {
continue
}
data := map[string]any{
"rawLine": line,
}
var jsonData map[string]any
if err := json.Unmarshal([]byte(line), &jsonData); err != nil {
data["parseError"] = err.Error()
} else {
data["json"] = jsonData
summary := map[string]string{}
if v, ok := jsonData["sessionId"].(string); ok {
summary["sessionId"] = v
}
if v, ok := jsonData["project"].(string); ok {
summary["project"] = v
}
if v, ok := jsonData["display"].(string); ok {
summary["display"] = v
}
data["summary"] = summary
}
hub.Publish(Event{
TS: time.Now(),
Type: EventTypeHistoryAppend,
Data: data,
})
}
return scanner.Err()
}