Documentation
¶
Overview ¶
Package web provides HTTP server and SSE streaming for real-time dashboard output.
Index ¶
- Constants
- func IsActive(path string) (bool, error)
- func ResolveWatchDirs(cliDirs, configDirs []string) []string
- type BroadcastLogger
- func (b *BroadcastLogger) LogAnswer(answer string)
- func (b *BroadcastLogger) LogDraftReview(action, feedback string)
- func (b *BroadcastLogger) LogQuestion(question string, options []string)
- func (b *BroadcastLogger) Path() string
- func (b *BroadcastLogger) Print(format string, args ...any)
- func (b *BroadcastLogger) PrintAligned(text string)
- func (b *BroadcastLogger) PrintRaw(format string, args ...any)
- func (b *BroadcastLogger) PrintSection(section status.Section)
- type Checkbox
- type Dashboard
- type DashboardConfig
- type DiffStats
- type Event
- func NewIterationStartEvent(phase status.Phase, iterationNum int, text string) Event
- func NewOutputEvent(phase status.Phase, text string) Event
- func NewSectionEvent(phase status.Phase, name string) Event
- func NewSignalEvent(phase status.Phase, signal string) Event
- func NewTaskEndEvent(phase status.Phase, taskNum int, text string) Event
- func NewTaskStartEvent(phase status.Phase, taskNum int, text string) Event
- type EventType
- type Logger
- type ParsedLine
- type ParsedLineType
- type Plan
- type Server
- type ServerConfig
- type Session
- func (s *Session) Close()
- func (s *Session) GetDiffStats() *DiffStats
- func (s *Session) GetLastModified() time.Time
- func (s *Session) GetMetadata() SessionMetadata
- func (s *Session) GetState() SessionState
- func (s *Session) IsLoaded() bool
- func (s *Session) IsTailing() bool
- func (s *Session) MarkLoadedIfNot() bool
- func (s *Session) Publish(event Event) error
- func (s *Session) SetDiffStats(stats DiffStats)
- func (s *Session) SetLastModified(t time.Time)
- func (s *Session) SetMetadata(meta SessionMetadata)
- func (s *Session) SetState(state SessionState)
- func (s *Session) StartTailing(fromStart bool) error
- func (s *Session) StopTailing()
- type SessionInfo
- type SessionManager
- func (m *SessionManager) All() []*Session
- func (m *SessionManager) Close()
- func (m *SessionManager) Discover(dir string) ([]string, error)
- func (m *SessionManager) DiscoverRecursive(root string) ([]string, error)
- func (m *SessionManager) Get(id string) *Session
- func (m *SessionManager) RefreshStates()
- func (m *SessionManager) Register(session *Session)
- func (m *SessionManager) Remove(id string)
- func (m *SessionManager) StartTailingActive()
- type SessionMetadata
- type SessionState
- type Tailer
- type TailerConfig
- type Task
- type TaskStatus
- type Watcher
Constants ¶
const DefaultReplayerSize = 10000
DefaultReplayerSize is the maximum number of events to keep for replay to late-joining clients.
const MaxCompletedSessions = 100
MaxCompletedSessions is the maximum number of completed sessions to retain. active sessions are never evicted. oldest completed sessions are removed when this limit is exceeded to prevent unbounded memory growth.
Variables ¶
This section is empty.
Functions ¶
func IsActive ¶
IsActive checks if a progress file is locked by another process or the current one. returns true if the file is locked (session is running), false otherwise. uses flock with LOCK_EX|LOCK_NB to test without blocking.
func ResolveWatchDirs ¶
ResolveWatchDirs determines the directories to watch based on precedence: CLI flags > config file > current directory (default). returns at least one directory (current directory if nothing else specified).
Types ¶
type BroadcastLogger ¶
type BroadcastLogger struct {
// contains filtered or unexported fields
}
BroadcastLogger wraps a Logger and broadcasts events to SSE clients. implements the decorator pattern - all calls are forwarded to the inner logger while also being converted to events for web streaming.
Thread safety: BroadcastLogger is NOT goroutine-safe. All methods must be called from a single goroutine (typically the main execution loop). The SSE server it writes to handles concurrent access from SSE clients.
func NewBroadcastLogger ¶
func NewBroadcastLogger(inner Logger, session *Session, holder *status.PhaseHolder) *BroadcastLogger
NewBroadcastLogger creates a logger that wraps inner and broadcasts to the session's SSE server. registers an OnChange callback on the holder for phase transition events.
func (*BroadcastLogger) LogAnswer ¶
func (b *BroadcastLogger) LogAnswer(answer string)
LogAnswer logs the user's answer for plan creation mode.
func (*BroadcastLogger) LogDraftReview ¶ added in v0.6.0
func (b *BroadcastLogger) LogDraftReview(action, feedback string)
LogDraftReview logs the user's draft review action and optional feedback.
func (*BroadcastLogger) LogQuestion ¶
func (b *BroadcastLogger) LogQuestion(question string, options []string)
LogQuestion logs a question and its options for plan creation mode.
func (*BroadcastLogger) Path ¶
func (b *BroadcastLogger) Path() string
Path returns the progress file path.
func (*BroadcastLogger) Print ¶
func (b *BroadcastLogger) Print(format string, args ...any)
Print writes a timestamped message and broadcasts it.
func (*BroadcastLogger) PrintAligned ¶
func (b *BroadcastLogger) PrintAligned(text string)
PrintAligned writes text with timestamp on each line and broadcasts it.
func (*BroadcastLogger) PrintRaw ¶
func (b *BroadcastLogger) PrintRaw(format string, args ...any)
PrintRaw writes without timestamp and broadcasts it.
func (*BroadcastLogger) PrintSection ¶
func (b *BroadcastLogger) PrintSection(section status.Section)
PrintSection writes a section header and broadcasts it. emits task/iteration boundary events based on section type.
type Dashboard ¶ added in v0.6.0
type Dashboard struct {
// contains filtered or unexported fields
}
Dashboard manages web server and file watching for progress monitoring.
func NewDashboard ¶ added in v0.6.0
func NewDashboard(cfg DashboardConfig, holder *status.PhaseHolder) *Dashboard
NewDashboard creates a new dashboard with the given configuration.
func (*Dashboard) RunWatchOnly ¶ added in v0.6.0
RunWatchOnly runs the web dashboard in watch-only mode without plan execution. monitors directories for progress files and serves the multi-session dashboard.
func (*Dashboard) Start ¶ added in v0.6.0
func (d *Dashboard) Start(ctx context.Context) (*BroadcastLogger, error)
Start creates the web server and broadcast logger, starting the server in background. returns the broadcast logger to use for execution, or error if server fails to start. when watchDirs is non-empty, creates multi-session mode with file watching.
type DashboardConfig ¶ added in v0.6.0
type DashboardConfig struct {
BaseLog Logger // base progress logger
Port int // web server port
PlanFile string // path to plan file (empty for watch-only mode)
Branch string // current git branch
WatchDirs []string // CLI watch directories
ConfigWatchDirs []string // config file watch directories
Colors *progress.Colors // colors for output
}
DashboardConfig holds configuration for dashboard initialization.
type DiffStats ¶ added in v0.10.0
type DiffStats struct {
Files int `json:"files"`
Additions int `json:"additions"`
Deletions int `json:"deletions"`
}
DiffStats holds git diff statistics for a session.
type Event ¶
type Event struct {
Type EventType `json:"type"`
Phase status.Phase `json:"phase"`
Section string `json:"section,omitempty"`
Text string `json:"text"`
Timestamp time.Time `json:"timestamp"`
Signal string `json:"signal,omitempty"`
TaskNum int `json:"task_num,omitempty"` // 1-based task index from plan (matches plan.tasks[].number)
IterationNum int `json:"iteration_num,omitempty"` // 1-based iteration index for review/codex phases
}
Event represents a single event to be streamed to web clients.
func NewIterationStartEvent ¶
NewIterationStartEvent creates an iteration start event.
func NewOutputEvent ¶
NewOutputEvent creates an output event with current timestamp.
func NewSectionEvent ¶
NewSectionEvent creates a section header event.
func NewSignalEvent ¶
NewSignalEvent creates a signal event.
func NewTaskEndEvent ¶
NewTaskEndEvent creates a task end boundary event.
func NewTaskStartEvent ¶
NewTaskStartEvent creates a task start boundary event.
func (Event) MarshalJSON ¶
MarshalJSON implements json.Marshaler for SSE streaming. this allows Event to be used directly with json.Marshal.
func (Event) ToSSEMessage ¶
ToSSEMessage converts the event to a go-sse Message for streaming. the event is serialized as JSON in the data field. we don't set the SSE event type because browsers' onmessage handler only catches typeless events (or type "message"). the event type is already in the JSON payload for client-side processing.
type EventType ¶
type EventType string
EventType represents the type of event being streamed.
const ( EventTypeOutput EventType = "output" // regular output line EventTypeSection EventType = "section" // section header EventTypeError EventType = "error" // error message EventTypeWarn EventType = "warn" // warning message EventTypeSignal EventType = "signal" // completion/failure signal EventTypeTaskStart EventType = "task_start" // task execution started EventTypeTaskEnd EventType = "task_end" // task execution ended EventTypeIterationStart EventType = "iteration_start" // review/codex iteration started )
event type constants for SSE streaming.
type Logger ¶ added in v0.9.0
type Logger interface {
Print(format string, args ...any)
PrintRaw(format string, args ...any)
PrintSection(section status.Section)
PrintAligned(text string)
LogQuestion(question string, options []string)
LogAnswer(answer string)
LogDraftReview(action string, feedback string)
Path() string
}
Logger provides progress logging for web dashboard wrapping.
type ParsedLine ¶ added in v0.9.0
type ParsedLine struct {
Type ParsedLineType
Text string // content text (without timestamp prefix for timestamped lines)
Section string // section name (only for ParsedLineSection)
Timestamp time.Time // parsed timestamp (only for ParsedLineTimestamp)
EventType EventType // detected event type (output, error, warn, signal)
Signal string // extracted signal name, if any
Phase status.Phase // phase derived from section name (only for ParsedLineSection)
}
ParsedLine is the result of parsing a single progress file line. callers convert this to Event objects with their own context (phase, pending section logic, etc.).
type ParsedLineType ¶ added in v0.9.0
type ParsedLineType int
ParsedLineType indicates what kind of progress line was parsed.
const ( ParsedLineSkip ParsedLineType = iota // header line or separator, should be skipped ParsedLineSection // section header (--- name ---) ParsedLineTimestamp // timestamped content line ParsedLinePlain // plain text without timestamp )
parsed line type constants.
type Plan ¶
Plan represents a parsed plan file.
func ParsePlanFile ¶
ParsePlanFile reads and parses a plan file from disk.
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server provides HTTP server for the real-time dashboard.
func NewServer ¶
func NewServer(cfg ServerConfig, session *Session) (*Server, error)
NewServer creates a new web server for single-session mode (direct execution). returns an error if the embedded template fails to parse.
func NewServerWithSessions ¶
func NewServerWithSessions(cfg ServerConfig, sm *SessionManager) (*Server, error)
NewServerWithSessions creates a new web server for multi-session mode (dashboard). returns an error if the embedded template fails to parse.
type ServerConfig ¶
type ServerConfig struct {
Port int // port to listen on
PlanName string // plan name to display in dashboard
Branch string // git branch name
PlanFile string // path to plan file for /api/plan endpoint
}
ServerConfig holds configuration for the web server.
type Session ¶
type Session struct {
ID string // unique identifier (derived from progress filename)
Path string // full path to progress file
Metadata SessionMetadata // parsed header information
State SessionState // current state (active/completed)
SSE *sse.Server // SSE server for this session (handles subscriptions and replay)
Tailer *Tailer // file tailer for reading new content (nil if not tailing)
// contains filtered or unexported fields
}
Session represents a single ralphex execution instance. each session corresponds to one progress file and maintains its own SSE server.
func NewSession ¶
NewSession creates a new session for the given progress file path. the session starts with an SSE server configured for event replay. metadata should be populated by calling ParseMetadata after creation.
func (*Session) Close ¶
func (s *Session) Close()
Close cleans up session resources including the tailer and SSE server.
func (*Session) GetDiffStats ¶ added in v0.10.0
GetDiffStats returns a copy of the diff stats, or nil if not set.
func (*Session) GetLastModified ¶
GetLastModified returns the last modified time thread-safely.
func (*Session) GetMetadata ¶
func (s *Session) GetMetadata() SessionMetadata
GetMetadata returns the session's metadata thread-safely.
func (*Session) GetState ¶
func (s *Session) GetState() SessionState
GetState returns the session's state thread-safely.
func (*Session) IsLoaded ¶
IsLoaded returns whether historical data has been loaded into the SSE server.
func (*Session) IsTailing ¶
IsTailing returns whether the session is currently tailing its progress file.
func (*Session) MarkLoadedIfNot ¶
MarkLoadedIfNot atomically checks if the session is not loaded and marks it as loaded. returns true if the session was successfully marked (was not loaded before), false if it was already loaded. this prevents double-loading race conditions.
func (*Session) Publish ¶
Publish sends an event to all connected SSE clients and stores it for replay. returns an error if publishing fails.
func (*Session) SetDiffStats ¶ added in v0.10.0
SetDiffStats stores diff stats for the session.
func (*Session) SetLastModified ¶
SetLastModified updates the last modified time thread-safely.
func (*Session) SetMetadata ¶
func (s *Session) SetMetadata(meta SessionMetadata)
SetMetadata updates the session's metadata thread-safely.
func (*Session) SetState ¶
func (s *Session) SetState(state SessionState)
SetState updates the session's state thread-safely.
func (*Session) StartTailing ¶
StartTailing begins tailing the progress file and feeding events to SSE clients. if fromStart is true, reads from the beginning of the file. does nothing if already tailing.
func (*Session) StopTailing ¶
func (s *Session) StopTailing()
StopTailing stops the tailer and event feeder goroutine.
type SessionInfo ¶
type SessionInfo struct {
ID string `json:"id"`
State SessionState `json:"state"`
// dir is the short display name for the project (last path segment of session directory).
Dir string `json:"dir"`
// DirPath is the full filesystem path to the session directory (used for grouping and copy-to-clipboard).
DirPath string `json:"dirPath,omitempty"`
PlanPath string `json:"planPath,omitempty"`
Branch string `json:"branch,omitempty"`
Mode string `json:"mode,omitempty"`
StartTime time.Time `json:"startTime"`
LastModified time.Time `json:"lastModified"`
DiffStats *DiffStats `json:"diffStats,omitempty"`
}
SessionInfo represents session data for the API response.
type SessionManager ¶
type SessionManager struct {
// contains filtered or unexported fields
}
SessionManager maintains a registry of all discovered sessions. it handles discovery of progress files, state detection via flock, and provides access to sessions by ID. completed sessions are automatically evicted when MaxCompletedSessions is exceeded.
func NewSessionManager ¶
func NewSessionManager() *SessionManager
NewSessionManager creates a new session manager with an empty registry.
func (*SessionManager) All ¶
func (m *SessionManager) All() []*Session
All returns all sessions in the registry.
func (*SessionManager) Close ¶
func (m *SessionManager) Close()
Close closes all sessions and clears the registry.
func (*SessionManager) Discover ¶
func (m *SessionManager) Discover(dir string) ([]string, error)
Discover scans a directory for progress files matching progress-*.txt pattern. for each file found, it creates or updates a session in the registry. returns the list of discovered session IDs.
func (*SessionManager) DiscoverRecursive ¶
func (m *SessionManager) DiscoverRecursive(root string) ([]string, error)
DiscoverRecursive walks a directory tree and discovers all progress files. unlike Discover, this searches subdirectories recursively. returns the list of all discovered session IDs (deduplicated).
func (*SessionManager) Get ¶
func (m *SessionManager) Get(id string) *Session
Get returns a session by ID, or nil if not found.
func (*SessionManager) RefreshStates ¶
func (m *SessionManager) RefreshStates()
RefreshStates checks all sessions for state changes (active->completed). stops tailing for sessions that have completed.
func (*SessionManager) Register ¶
func (m *SessionManager) Register(session *Session)
Register adds an externally-created session to the manager. This is used when a session is created for live execution (BroadcastLogger) and needs to be visible in the multi-session dashboard. The session's ID is derived from its path using sessionIDFromPath.
func (*SessionManager) Remove ¶
func (m *SessionManager) Remove(id string)
Remove removes a session from the registry and closes its resources.
func (*SessionManager) StartTailingActive ¶
func (m *SessionManager) StartTailingActive()
StartTailingActive starts tailing for all active sessions. for each active session not already tailing, starts tailing from the beginning to populate the buffer with existing content.
type SessionMetadata ¶
type SessionMetadata struct {
PlanPath string // path to plan file (from "Plan:" header line)
Branch string // git branch (from "Branch:" header line)
Mode string // execution mode: full, review, codex-only (from "Mode:" header line)
StartTime time.Time // start time (from "Started:" header line)
}
SessionMetadata holds parsed information from progress file header.
func ParseProgressHeader ¶
func ParseProgressHeader(path string) (SessionMetadata, error)
ParseProgressHeader reads the header section of a progress file and extracts metadata. the header format is:
# Ralphex Progress Log Plan: path/to/plan.md Branch: feature-branch Mode: full Started: 2026-01-22 10:30:00 ------------------------------------------------------------
type SessionState ¶
type SessionState string
SessionState represents the current state of a session.
const ( SessionStateActive SessionState = "active" // session is running (progress file locked) SessionStateCompleted SessionState = "completed" // session finished (no lock held) )
session state constants.
type Tailer ¶
type Tailer struct {
// contains filtered or unexported fields
}
Tailer watches a progress file and emits events for new lines. it parses progress file format (timestamps, sections) into Event structs.
func NewTailer ¶
func NewTailer(path string, config TailerConfig) *Tailer
NewTailer creates a new Tailer for the given progress file. the tailer starts in stopped state; call Start() to begin tailing.
func (*Tailer) Events ¶
Events returns the channel that emits parsed events. events are emitted in order as lines are read from the file.
type TailerConfig ¶
type TailerConfig struct {
PollInterval time.Duration // how often to check for new content (default: 100ms)
InitialPhase status.Phase // phase to use for events (default: PhaseTask)
}
TailerConfig holds configuration for the Tailer.
func DefaultTailerConfig ¶
func DefaultTailerConfig() TailerConfig
DefaultTailerConfig returns default configuration.
type Task ¶
type Task struct {
Number int `json:"number"`
Title string `json:"title"`
Status TaskStatus `json:"status"`
Checkboxes []Checkbox `json:"checkboxes"`
}
Task represents a task section in a plan.
type TaskStatus ¶
type TaskStatus string
TaskStatus represents the execution status of a task.
const ( TaskStatusPending TaskStatus = "pending" TaskStatusActive TaskStatus = "active" TaskStatusDone TaskStatus = "done" TaskStatusFailed TaskStatus = "failed" )
task status constants.
type Watcher ¶
type Watcher struct {
// contains filtered or unexported fields
}
Watcher monitors directories for progress file changes. it uses fsnotify for efficient file system event detection and notifies the SessionManager when new progress files appear.
func NewWatcher ¶
func NewWatcher(dirs []string, sm *SessionManager) (*Watcher, error)
NewWatcher creates a watcher for the specified directories. directories are watched recursively for progress-*.txt files.