summaryrefslogtreecommitdiff
path: root/internal/api/events.go
diff options
context:
space:
mode:
authorClaude <noreply@anthropic.com>2026-05-25 05:05:27 +0000
committerClaude <noreply@anthropic.com>2026-05-25 05:05:27 +0000
commitb44c8277465c3b4e03fe4de4dd93850413023b69 (patch)
treef79131cb5f4d7444f2c358f35ad7749bad612bda /internal/api/events.go
parent6890bafa65a309b540cbe1562c39df137f202369 (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.go38
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)
+}