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.
This commit is contained in:
100
dashboard/internal/claude/loader.go
Normal file
100
dashboard/internal/claude/loader.go
Normal file
@@ -0,0 +1,100 @@
|
||||
package claude
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Loader reads Claude Code state files from a local claude directory (typically ~/.claude).
|
||||
//
|
||||
// Keep this minimal for now; more helpers (e.g. ListDir / FileInfo) can be added later.
|
||||
type Loader struct {
|
||||
claudeDir string
|
||||
}
|
||||
|
||||
type DirEntry struct {
|
||||
Name string `json:"name"`
|
||||
IsDir bool `json:"isDir"`
|
||||
}
|
||||
|
||||
type FileMeta struct {
|
||||
Path string `json:"path"`
|
||||
Exists bool `json:"exists"`
|
||||
Size int64 `json:"size"`
|
||||
ModTime string `json:"modTime"`
|
||||
}
|
||||
|
||||
func NewLoader(claudeDir string) *Loader {
|
||||
return &Loader{claudeDir: claudeDir}
|
||||
}
|
||||
|
||||
func (l *Loader) ClaudeDir() string { return l.claudeDir }
|
||||
|
||||
func (l *Loader) LoadStatsCache() (*StatsCache, error) {
|
||||
if l.claudeDir == "" {
|
||||
return nil, fmt.Errorf("claude dir is empty")
|
||||
}
|
||||
|
||||
p := filepath.Join(l.claudeDir, "stats-cache.json")
|
||||
b, err := os.ReadFile(p)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read stats cache %q: %w", p, err)
|
||||
}
|
||||
|
||||
var stats StatsCache
|
||||
if err := json.Unmarshal(b, &stats); err != nil {
|
||||
return nil, fmt.Errorf("parse stats cache %q: %w", p, err)
|
||||
}
|
||||
|
||||
return &stats, nil
|
||||
}
|
||||
|
||||
func (l *Loader) ListDir(name string) ([]DirEntry, error) {
|
||||
if l.claudeDir == "" {
|
||||
return nil, fmt.Errorf("claude dir is empty")
|
||||
}
|
||||
|
||||
entries, err := os.ReadDir(filepath.Join(l.claudeDir, name))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read dir %q: %w", name, err)
|
||||
}
|
||||
|
||||
out := make([]DirEntry, 0, len(entries))
|
||||
for _, e := range entries {
|
||||
out = append(out, DirEntry{Name: e.Name(), IsDir: e.IsDir()})
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (l *Loader) PathExists(relPath string) bool {
|
||||
if l.claudeDir == "" {
|
||||
return false
|
||||
}
|
||||
_, err := os.Stat(filepath.Join(l.claudeDir, relPath))
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func (l *Loader) FileMeta(relPath string) (FileMeta, error) {
|
||||
if l.claudeDir == "" {
|
||||
return FileMeta{}, fmt.Errorf("claude dir is empty")
|
||||
}
|
||||
|
||||
p := filepath.Join(l.claudeDir, relPath)
|
||||
st, err := os.Stat(p)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return FileMeta{Path: relPath, Exists: false}, nil
|
||||
}
|
||||
return FileMeta{}, fmt.Errorf("stat %q: %w", p, err)
|
||||
}
|
||||
|
||||
return FileMeta{
|
||||
Path: relPath,
|
||||
Exists: true,
|
||||
Size: st.Size(),
|
||||
ModTime: st.ModTime().UTC().Format(time.RFC3339),
|
||||
}, nil
|
||||
}
|
||||
Reference in New Issue
Block a user