From 54e88b71efd9a6fd9d880b6e90d844a875808662 Mon Sep 17 00:00:00 2001 From: Adam Malczewski Date: Mon, 22 Jun 2026 00:36:31 +0900 Subject: feat(tabs): cross-device tab sync via conversation lifecycle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Consume the conversation lifecycle handoff (wire@0.10.0, transport-contract@0.14.0). 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. --- src/core/wire/conformance.test.ts | 13 +++++++++++++ src/core/wire/conformance.ts | 4 ++++ 2 files changed, 17 insertions(+) (limited to 'src/core/wire') diff --git a/src/core/wire/conformance.test.ts b/src/core/wire/conformance.test.ts index f5d6608..58cba3a 100644 --- a/src/core/wire/conformance.test.ts +++ b/src/core/wire/conformance.test.ts @@ -140,6 +140,17 @@ describe("classifies every WsServerMessage type", () => { }, { type: "chat.error" as const, message: "e" }, { type: "conversation.open" as const, conversationId: "c1" }, + { + type: "conversation.statusChanged" as const, + conversationId: "c1", + status: "active" as const, + }, + { + type: "conversation.compacted" as const, + conversationId: "c1", + messagesSummarized: 10, + messagesKept: 5, + }, ]; const labels = msgs.map(assertWsServerMessageExhaustive); expect(labels).toEqual([ @@ -150,6 +161,8 @@ describe("classifies every WsServerMessage type", () => { "chat.delta", "chat.error", "conversation.open", + "conversation.statusChanged", + "conversation.compacted", ]); }); }); diff --git a/src/core/wire/conformance.ts b/src/core/wire/conformance.ts index 05a15aa..07808fc 100644 --- a/src/core/wire/conformance.ts +++ b/src/core/wire/conformance.ts @@ -83,6 +83,10 @@ export function assertWsServerMessageExhaustive(msg: WsServerMessage): string { return "chat.error"; case "conversation.open": return "conversation.open"; + case "conversation.statusChanged": + return "conversation.statusChanged"; + case "conversation.compacted": + return "conversation.compacted"; default: return msg satisfies never; } -- cgit v1.2.3