Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion cmd/capytrace/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,10 @@ func handleEnd() {
case "sqlite":
home, _ := os.UserHomeDir()
dataDir := filepath.Join(home, ".local", "share", "capytrace")
os.MkdirAll(dataDir, 0755)
if err := os.MkdirAll(dataDir, 0755); err != nil {
fmt.Fprintf(os.Stderr, "Failed to create data directory: %v\n", err)
os.Exit(1)
}
exp = exporter.NewSQLiteExporter(dataDir)
default:
exp = &exporter.MarkdownExporter{}
Expand Down
25 changes: 21 additions & 4 deletions internal/exporter/sqlite.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package exporter
import (
"database/sql"
"fmt"
"os"
"path/filepath"
"time"

Expand Down Expand Up @@ -30,7 +31,11 @@ func (e *SQLiteExporter) Export(session *models.Session, savePath string) error
if err != nil {
return fmt.Errorf("failed to open database: %w", err)
}
defer db.Close()
defer func() {
if closeErr := db.Close(); closeErr != nil {
fmt.Fprintf(os.Stderr, "Failed to close database: %v\n", closeErr)
}
}()

// Create tables if they don't exist
if err := e.createTables(db); err != nil {
Expand All @@ -42,7 +47,11 @@ func (e *SQLiteExporter) Export(session *models.Session, savePath string) error
if err != nil {
return fmt.Errorf("failed to begin transaction: %w", err)
}
defer tx.Rollback()
defer func() {
if rollbackErr := tx.Rollback(); rollbackErr != nil && rollbackErr != sql.ErrTxDone {
fmt.Fprintf(os.Stderr, "Failed to rollback transaction: %v\n", rollbackErr)
}
}()

// Insert or update session
_, err = tx.Exec(`
Expand Down Expand Up @@ -151,7 +160,11 @@ func (e *SQLiteExporter) GetSessionStats(sessionID string) (*models.SessionSumma
if err != nil {
return nil, err
}
defer db.Close()
defer func() {
if closeErr := db.Close(); closeErr != nil {
fmt.Fprintf(os.Stderr, "Failed to close database: %v\n", closeErr)
}
}()

var summary models.SessionSummary
var startTime, endTime time.Time
Expand All @@ -177,7 +190,11 @@ func (e *SQLiteExporter) GetSessionStats(sessionID string) (*models.SessionSumma
if err != nil {
return nil, err
}
defer rows.Close()
defer func() {
if closeErr := rows.Close(); closeErr != nil {
fmt.Fprintf(os.Stderr, "Failed to close rows: %v\n", closeErr)
}
}()

for rows.Next() {
var eventType string
Expand Down
1 change: 0 additions & 1 deletion internal/filter/cursor_filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import (
// remains idle or when followed by significant events like text changes.
type CursorFilter struct {
mu sync.Mutex
lastCursorEvent *models.Event
lastEventTime time.Time
pendingEvent *models.Event
debounceTimer *time.Timer
Expand Down
26 changes: 17 additions & 9 deletions internal/recorder/session.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,13 +105,15 @@ func (s *Session) Start() error {
activeSessionsMu.Unlock()

// Record initial event
s.addEvent(models.Event{
if err := s.addEvent(models.Event{
Type: "session_start",
Timestamp: s.StartTime,
Data: models.EventData{
Note: fmt.Sprintf("Started debugging session in %s", s.ProjectPath),
},
})
}); err != nil {
return fmt.Errorf("failed to add initial event: %w", err)
}

return s.save()
}
Expand All @@ -126,15 +128,15 @@ func (s *Session) End() error {

// Flush any pending cursor events
if pendingEvent := s.cursorFilter.FlushPending(); pendingEvent != nil {
s.Session.Events = append(s.Session.Events, *pendingEvent)
s.Events = append(s.Events, *pendingEvent)
}

s.cursorFilter.Stop()
s.EndTime = time.Now()
s.Active = false

// Record end event
s.Session.Events = append(s.Session.Events, models.Event{
s.Events = append(s.Events, models.Event{
Type: "session_end",
Timestamp: s.EndTime,
Data: models.EventData{
Expand Down Expand Up @@ -191,7 +193,9 @@ func (s *Session) RecordEdit(filename, line, col, lineCount, changedTick string)

// File edits are context triggers - process through filter first
if filteredEvent := s.cursorFilter.ProcessEvent(&event); filteredEvent != nil {
s.addEvent(*filteredEvent)
if err := s.addEvent(*filteredEvent); err != nil {
return fmt.Errorf("failed to add filtered event: %w", err)
}
}

return s.addEvent(event)
Expand All @@ -209,7 +213,9 @@ func (s *Session) RecordTerminalCommand(command string) error {

// Terminal commands are context triggers
if filteredEvent := s.cursorFilter.ProcessEvent(&event); filteredEvent != nil {
s.addEvent(*filteredEvent)
if err := s.addEvent(*filteredEvent); err != nil {
return fmt.Errorf("failed to add filtered event: %w", err)
}
}

return s.addEvent(event)
Expand Down Expand Up @@ -276,7 +282,7 @@ func (s *Session) RecordLSPDiagnostic(filename, line, col, message, level string
// addEvent appends an event to the session and persists it.
func (s *Session) addEvent(event models.Event) error {
s.mu.Lock()
s.Session.Events = append(s.Session.Events, event)
s.Events = append(s.Events, event)
s.mu.Unlock()

return s.save()
Expand Down Expand Up @@ -410,13 +416,15 @@ func ResumeSession(sessionName, savePath string, filterConfig *filter.FilterConf
session.startPeriodicAggregation(5 * time.Minute)

// Record resume event
session.addEvent(models.Event{
if err := session.addEvent(models.Event{
Type: "session_resume",
Timestamp: time.Now(),
Data: models.EventData{
Note: "Session resumed",
},
})
}); err != nil {
return nil, fmt.Errorf("failed to add resume event: %w", err)
}

return session, session.save()
}
6 changes: 3 additions & 3 deletions lua/capytrace/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ local default_config = {
record_git_diff = true,
auto_save_on_exit = true,
max_cursor_events = 100, -- Limit cursor movement recordings

-- Smart Filter configuration (Anti-Spam Cursor Filter)
filter_threshold = 500, -- Idle threshold in milliseconds (default: 500ms)
debounce_interval = 200, -- Debounce interval for cursor movements (default: 200ms)

-- Smart Aggregation configuration (Activity Block Builder)
aggregation = {
merge_window = 2000, -- Time window for merging file_edit events in milliseconds (default: 2s)
Expand All @@ -28,7 +28,7 @@ local default_config = {
},
periodic_update_interval = 300000, -- Update SESSION_SUMMARY.md every N milliseconds (default: 5min)
},

log_events = {
terminal_commands = true,
file_open = true,
Expand Down
Loading