55 lines
1.1 KiB
Go
55 lines
1.1 KiB
Go
|
|
package session
|
||
|
|
|
||
|
|
import (
|
||
|
|
"path/filepath"
|
||
|
|
"strings"
|
||
|
|
"time"
|
||
|
|
)
|
||
|
|
|
||
|
|
// SearchResult represents a match found in a session transcript.
|
||
|
|
type SearchResult struct {
|
||
|
|
SessionID string
|
||
|
|
Timestamp time.Time
|
||
|
|
Tool string
|
||
|
|
Match string
|
||
|
|
}
|
||
|
|
|
||
|
|
// Search finds events matching the query across all sessions in the directory.
|
||
|
|
func Search(projectsDir, query string) ([]SearchResult, error) {
|
||
|
|
matches, err := filepath.Glob(filepath.Join(projectsDir, "*.jsonl"))
|
||
|
|
if err != nil {
|
||
|
|
return nil, err
|
||
|
|
}
|
||
|
|
|
||
|
|
var results []SearchResult
|
||
|
|
query = strings.ToLower(query)
|
||
|
|
|
||
|
|
for _, path := range matches {
|
||
|
|
sess, err := ParseTranscript(path)
|
||
|
|
if err != nil {
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
|
||
|
|
for _, evt := range sess.Events {
|
||
|
|
if evt.Type != "tool_use" {
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
text := strings.ToLower(evt.Input + " " + evt.Output)
|
||
|
|
if strings.Contains(text, query) {
|
||
|
|
matchCtx := evt.Input
|
||
|
|
if matchCtx == "" {
|
||
|
|
matchCtx = truncate(evt.Output, 120)
|
||
|
|
}
|
||
|
|
results = append(results, SearchResult{
|
||
|
|
SessionID: sess.ID,
|
||
|
|
Timestamp: evt.Timestamp,
|
||
|
|
Tool: evt.Tool,
|
||
|
|
Match: matchCtx,
|
||
|
|
})
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return results, nil
|
||
|
|
}
|