feat(tasks): task board UI — chat window becomes Tasks + card grid

Reframes the chat surface as tasks:
- New Tasks.svelte: a card grid of tasks, each showing status (Running /
  Needs input / Done / Failed), the goal as title, the outcome summary, and
  relative time; filterable by status with live counts; delete on hover;
  "New task" and per-card click open the conversation.
- Board updates LIVE off the events stream (goal.set / task.status /
  question.*) via an explicit liveEvents.subscribe with a debounced refetch —
  scanning all events newer than the last seen, since entity.touched bursts
  bury task events below index 0.
- App shell: primary nav "Chat" → "Tasks" (board is now the home route),
  "New chat" → "New task", conversation header gets a Tasks / Conversation
  breadcrumb. Removed the superseded Sessions page.
- api.ts Session type carries the task fields (goal/status/outcome/summary).

Also fixes a pre-existing SSE bug that blocked ALL live updates app-wide:
writeSSE emitted `event: <type>`, which EventSource only delivers to
addEventListener(type) handlers — but stores/events.ts (and every page reading
liveEvents) consumes via onmessage, which never fires for named events. So the
live stream delivered nothing to the UI. Dropped the event-name line; the type
is already in the JSON payload, and new event types now need zero client
changes. SSE test still green (it parses data: lines).

Verified in the browser against the live stack: the board renders 50 tasks
with correct status buckets; a goal-driven task appears and flips to a Done
card with its summary in real time without a reload; Events page confirms the
stream now delivers to onmessage.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-11 13:22:27 +02:00
parent 014e5c74e0
commit 413bf54daf
5 changed files with 251 additions and 185 deletions

View File

@@ -1,10 +1,18 @@
const BASE = '/agent'
const API = '/api/v1'
// A session IS a task: a goal-structured unit of work with a lifecycle status
// and an outcome. goal/outcome/summary/entity_id are empty until the agent sets
// them (see the task-board plan). status defaults to 'active'.
export interface Session {
id: string
title: string
actor: string
goal?: string
status?: string // active | planning | executing | awaiting_input | done | failed | abandoned
outcome?: string // success | failure | partial
summary?: string
entity_id?: string
created_at: string
last_active_at: string
}