1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
# Roadmap — dispatch-web
> Living document of shipped + planned FE work. Updated at each milestone.
> Source of truth for "what's done" + "what's next". Cross-repo handoffs land here
> as committed work (see `backend-handoff.md` for the living backend seam).
## Done
- **Surface system + WS** — generic surface interpreter, catalog subscribe, `SurfaceView` dispatch on field kind (never surface id); custom renderers for `table`, `message-queue`, `todo`.
- **Conversation transcript** — chunk cache + delta streaming (`core/chunks`), provisional → committed fold, IndexedDB persistence, chat-limit bulk unload + 75% fresh-load window + show-earlier backfill (CR-5 `?limit=`/`?beforeSeq=`).
- **Tabs + model selector** — per-conversation tabs (persisted), model catalog, draft → tab promotion on first send.
- **Multi-client live view** — `chat.subscribe`/`chat.unsubscribe`, structural `generating` flag, resync on reconnect, `user-message` event (CR-3 fix).
- **Cache-warming** — toggle + interval, manual warm, authoritative `nextWarmAt` timer + retention, `POST /conversations/:id/close` (CR-4 lifecycle).
- **Per-conversation cwd + LSP** — `GET`/`PUT /cwd`, `GET /lsp` (lazy spawn), draft cwd carries into turn 1.
- **Context size** — `done.contextSize` + `TurnMetrics.contextSize`, composer fill bar (placeholder 1M limit).
- **Reasoning effort** — sticky per-conversation thinking-depth knob (`GET`/`PUT /reasoning-effort`, `null` ⇒ default `high`).
- **Message queue + steering** — `chat.queue` WS op, `steering` AgentEvent → user bubble in transcript, message-queue surface panel above composer.
- **Todo task list** — `rendererId: "todo"` custom renderer, dedicated "Tasks" sidebar view (status indicators: pending/in_progress/completed/cancelled).
- **Conversation.open broadcast** — `conversation.open` WS message handler, opens a tab (without auto-switching) from CLI `--open` flag.
- **Conversation lifecycle (cross-device tab sync)** — `GET /conversations?status=active,idle` on connect restores tabs across devices; `conversation.statusChanged` WS handler updates tab status + removes closed tabs; TabBar shows a spinner on `active` conversations.
- **Conversation compaction** — "Compaction" sidebar view with manual "Compact now" button (`POST /conversations/:id/compact`) + auto-compact threshold input (`GET`/`PUT /conversations/:id/compact-threshold`); `conversation.compacted` WS handler reloads history.
## Next up
### Conversation list + title editing (`frontend-conversation-list-handoff.md`)
Types already in `[email protected]` + `[email protected]` (mirrored, deps re-pinned). The `conversation.open` + lifecycle handlers are already consumed. Remaining FE work:
1. **Conversation list sidebar view** — `GET /conversations` → `ConversationListResponse` (`ConversationMeta[]` with id, title, createdAt, lastActivityAt, status). Render a "Conversations" sidebar view (title + relative time + status). Click to open (create tab + load history + subscribe). Fetch on mount + on focus / manual refresh. Filter by status (active/idle vs closed for a history view).
2. **Title editing** — `GET`/`PUT /conversations/:id/title` (`TitleResponse`/`SetTitleRequest`). Inline rename affordance on the active conversation's title. Auto-title from first user message is backend-owned; FE overrides via PUT.
## Backlog (likely next backend asks — not yet requested)
- **Model max context-window LIMIT** — the denominator for the context-size fill bar (currently hardcoded `1_000_000` in `Composer.svelte`). Wire the real per-model `contextWindow` when the backend ships it.
- **LSP status over WS (push)** — today the FE HTTP-polls `GET /lsp` on mount + manual refresh; a live surface/WS push would remove the manual refresh and reflect server state changes without a reload.
- **Warming opt-in persistence across backend restarts** — currently fail-safe-off after a restart; backend offered boot hydration if it becomes a need.
- **Standalone "stop generating" button** — `POST /conversations/:id/close` aborts AND disables warming; a separate "stop without closing" affordance would need its own op if the product wants it.
- **`GET /conversations/:id/last`** — blocking last-message endpoint (shipped, mirrored, not consumed). Could be used for notification previews or conversation list snippets.
|