diff options
| author | Claude <noreply@anthropic.com> | 2026-05-25 05:05:27 +0000 |
|---|---|---|
| committer | Claude <noreply@anthropic.com> | 2026-05-25 05:05:27 +0000 |
| commit | b44c8277465c3b4e03fe4de4dd93850413023b69 (patch) | |
| tree | f79131cb5f4d7444f2c358f35ad7749bad612bda /internal/api/events.go | |
| parent | 6890bafa65a309b540cbe1562c39df137f202369 (diff) | |
feat(api,web): event-stream timeline (Phase 3)
Adds GET /api/tasks/{id}/events (seq-ordered, ?since_seq for incremental
polling) as the timeline data source, and a per-task Timeline section in the
web UI that fetches and renders the observability event stream. New pure,
unit-tested JS helpers: formatEventText, renderEventTimeline, fetchTaskEvents.
The timeline load is async and guarded on a global fetch so the synchronous
renderTaskPanel path (and its DOM-mock unit tests) is unaffected. Verified via
Go endpoint tests and node --test (272 JS tests pass). Note: the live in-browser
panel render was not exercised in this environment — only unit-level coverage.
https://claude.ai/code/session_01SESwn7kQ7oP62trWw6pc39
Diffstat (limited to 'internal/api/events.go')
| -rw-r--r-- | internal/api/events.go | 38 |
1 files changed, 38 insertions, 0 deletions
diff --git a/internal/api/events.go b/internal/api/events.go new file mode 100644 index 0000000..eefe064 --- /dev/null +++ b/internal/api/events.go @@ -0,0 +1,38 @@ +package api + +import ( + "net/http" + "strconv" + + "github.com/thepeterstone/claudomator/internal/event" +) + +// handleListTaskEvents returns a task's observability event stream in seq order. +// Pass ?since_seq=N to fetch only events newer than seq N (incremental polling). +func (s *Server) handleListTaskEvents(w http.ResponseWriter, r *http.Request) { + id := r.PathValue("id") + if _, err := s.store.GetTask(id); err != nil { + writeJSON(w, http.StatusNotFound, map[string]string{"error": "task not found"}) + return + } + + var sinceSeq int64 + if v := r.URL.Query().Get("since_seq"); v != "" { + n, err := strconv.ParseInt(v, 10, 64) + if err != nil || n < 0 { + writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid since_seq"}) + return + } + sinceSeq = n + } + + events, err := s.store.ListEvents(id, sinceSeq) + if err != nil { + writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()}) + return + } + if events == nil { + events = []*event.Event{} + } + writeJSON(w, http.StatusOK, events) +} |
