feat: add session replay with terminal playback via xterm.js
Persist byte-level I/O events from SSH sessions to SQLite and add a web
UI to replay them with original timing. Events are buffered in memory
and flushed every 2s to avoid blocking SSH I/O on database writes.
- Add session_events table (migration 002)
- Add SessionEvent type and storage methods (SQLite + MemoryStore)
- Change RecordingChannel to support multiple callbacks
- Add EventRecorder for buffered event persistence
- Add session detail page with xterm.js terminal replay
- Add /api/sessions/{id}/events JSON endpoint
- Linkify session IDs in dashboard and active sessions
- Vendor xterm.js v5.3.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -36,6 +36,14 @@ type SessionLog struct {
|
||||
Output string
|
||||
}
|
||||
|
||||
// SessionEvent represents a single I/O event recorded during a session.
|
||||
type SessionEvent struct {
|
||||
SessionID string
|
||||
Timestamp time.Time
|
||||
Direction int // 0=input (client→server), 1=output (server→client)
|
||||
Data []byte
|
||||
}
|
||||
|
||||
// DashboardStats holds aggregate counts for the web dashboard.
|
||||
type DashboardStats struct {
|
||||
TotalAttempts int64
|
||||
@@ -88,6 +96,18 @@ type Store interface {
|
||||
// If activeOnly is true, only sessions with no disconnected_at are returned.
|
||||
GetRecentSessions(ctx context.Context, limit int, activeOnly bool) ([]Session, error)
|
||||
|
||||
// GetSession returns a single session by ID.
|
||||
GetSession(ctx context.Context, sessionID string) (*Session, error)
|
||||
|
||||
// GetSessionLogs returns all log entries for a session ordered by timestamp.
|
||||
GetSessionLogs(ctx context.Context, sessionID string) ([]SessionLog, error)
|
||||
|
||||
// AppendSessionEvents batch-inserts session events.
|
||||
AppendSessionEvents(ctx context.Context, events []SessionEvent) error
|
||||
|
||||
// GetSessionEvents returns all events for a session ordered by id.
|
||||
GetSessionEvents(ctx context.Context, sessionID string) ([]SessionEvent, error)
|
||||
|
||||
// Close releases any resources held by the store.
|
||||
Close() error
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user