diff options
| author | Adam Malczewski <[email protected]> | 2026-06-22 00:36:31 +0900 |
|---|---|---|
| committer | Adam Malczewski <[email protected]> | 2026-06-22 00:36:31 +0900 |
| commit | 54e88b71efd9a6fd9d880b6e90d844a875808662 (patch) | |
| tree | 7d8292486f845225f4f03801531db2dc6ba8b7b1 /.dispatch/wire.reference.md | |
| parent | a8de5b2b9bec07a5ed5df54b859fa6ff5f98406f (diff) | |
| download | dispatch-web-54e88b71efd9a6fd9d880b6e90d844a875808662.tar.gz dispatch-web-54e88b71efd9a6fd9d880b6e90d844a875808662.zip | |
feat(tabs): cross-device tab sync via conversation lifecycle
Consume the conversation lifecycle handoff ([email protected], [email protected]).
Re-pinned file: deps + re-mirrored .dispatch/*.reference.md.
- fetchOpenConversations() on connect: GET /conversations?status=active,idle
restores the tab bar across devices (merges with localStorage — opens new
tabs, removes closed ones, updates titles from backend)
- conversation.statusChanged WS handler: closed → removeTabLocally (no
re-POST); active → open tab + spinner; idle → update status map
- conversation.compacted WS handler: dispose stale store + cache, reload
history from server
- TabBar shows a spinner on active conversations (statusFor prop)
- closeTab refactored to use removeTabLocally (extracted cleanup)
- conformance guards + WS adapter tests cover all 3 new WsServerMessage types
686 tests green.
Diffstat (limited to '.dispatch/wire.reference.md')
| -rw-r--r-- | .dispatch/wire.reference.md | 19 |
1 files changed, 18 insertions, 1 deletions
diff --git a/.dispatch/wire.reference.md b/.dispatch/wire.reference.md index e96c353..ead4d9c 100644 --- a/.dispatch/wire.reference.md +++ b/.dispatch/wire.reference.md @@ -4,9 +4,17 @@ > types WITHOUT following the `file:` dep symlink out of this repo (which hangs on a permission > prompt). Your CODE still imports `@dispatch/wire` normally — this file is for READING only. > -> **Orchestrator:** SNAPSHOT of `[email protected]` (conversation metadata). Regenerate +> **Orchestrator:** SNAPSHOT of `[email protected]` (conversation lifecycle status). Regenerate > whenever `@dispatch/wire` changes. > +> **2026-06-22 delta (conversation lifecycle handoff — package bumped `0.9.0` → `0.10.0`, ADDITIVE):** +> adds `ConversationStatus` (`"active" | "idle" | "closed"`) — the per-conversation lifecycle +> status. `ConversationMeta` gains a `status` field. `active` = a turn is generating; `idle` = +> exists, not generating; `closed` = dismissed (hidden from the tab bar). Transitions are +> backend-owned: `idle → active` on turn start, `active → idle` on turn settle, `→ closed` on +> `POST /conversations/:id/close`. Pushed to all WS clients via `conversation.statusChanged` +> (see `[email protected]`). +> > **2026-06-21 delta (conversation.open handoff — package bumped `0.8.0` → `0.9.0`, ADDITIVE):** > adds `ConversationMeta` — metadata for a conversation (id, title, createdAt, lastActivityAt), > returned by `GET /conversations` (the list endpoint, see `[email protected]`). @@ -585,6 +593,14 @@ export interface TurnSteeringEvent { // ─── Conversation metadata ─────────────────────────────────────────────────── /** + * The per-conversation lifecycle status. `active` = a turn is generating; + * `idle` = exists, not generating; `closed` = dismissed (hidden from the tab + * bar, not deleted). Transitions are backend-owned and pushed via the + * `conversation.statusChanged` WS message (see `transport-contract`). + */ +export type ConversationStatus = "active" | "idle" | "closed"; + +/** * Metadata for a conversation, returned by `GET /conversations` (the list * endpoint). The title defaults to the first user message (truncated) and can * be set via `PUT /conversations/:id/title`. `createdAt` is set on first write; @@ -595,5 +611,6 @@ export interface ConversationMeta { readonly createdAt: number; readonly lastActivityAt: number; readonly title: string; + readonly status: ConversationStatus; } ``` |
