Connect Sybil to the Pi root conversation with authenticated REST and WebSocket APIs, persistent read state, and a dedicated agent tab. Keep optimistic messages stable through delivery and retries, and animate arrivals without losing the reader's scroll position. Share bubble styling with regular chats and remove the obsolete admission sender. Reject malformed upstream receipts and WebSocket upgrade requests, with regression coverage and updated API documentation. Validated with 51 web tests, 44 server tests, both production builds, desktop/mobile bubble comparisons, and 11 browser animation and scrolling checks.
54 lines
2.2 KiB
JavaScript
54 lines
2.2 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import test from "node:test";
|
|
import { resolveSidebarSelectionAfterRefresh } from "../src/lib/sidebar-selection.ts";
|
|
|
|
const workspaceItems = [
|
|
{ type: "chat", id: "completed-chat" },
|
|
{ type: "chat", id: "selected-chat" },
|
|
{ type: "search", id: "selected-search" },
|
|
];
|
|
|
|
test("persistent agent selection survives history refreshes and empty collections", () => {
|
|
const agent = { kind: "agent", id: "root" };
|
|
assert.deepEqual(resolveSidebarSelectionAfterRefresh(agent, workspaceItems, { selectFallback: true }), agent);
|
|
assert.deepEqual(resolveSidebarSelectionAfterRefresh(agent, []), agent);
|
|
assert.deepEqual(resolveSidebarSelectionAfterRefresh(null, workspaceItems, { initialSelection: agent, selectFallback: true }), agent);
|
|
assert.deepEqual(resolveSidebarSelectionAfterRefresh({ kind: "chat", id: "selected-chat" }, workspaceItems, { initialSelection: agent }), { kind: "chat", id: "selected-chat" });
|
|
});
|
|
|
|
test("a collection refresh preserves the current thread selection", () => {
|
|
assert.deepEqual(
|
|
resolveSidebarSelectionAfterRefresh({ kind: "chat", id: "selected-chat" }, workspaceItems),
|
|
{ kind: "chat", id: "selected-chat" }
|
|
);
|
|
});
|
|
|
|
test("an initial route selection cannot override a current thread selection", () => {
|
|
assert.deepEqual(
|
|
resolveSidebarSelectionAfterRefresh(
|
|
{ kind: "search", id: "selected-search" },
|
|
workspaceItems,
|
|
{ initialSelection: { kind: "chat", id: "completed-chat" }, selectFallback: true }
|
|
),
|
|
{ kind: "search", id: "selected-search" }
|
|
);
|
|
});
|
|
|
|
test("a collection refresh preserves an intentionally empty selection", () => {
|
|
assert.equal(resolveSidebarSelectionAfterRefresh(null, workspaceItems), null);
|
|
});
|
|
|
|
test("initial load can select the URL thread or fall back to the first item", () => {
|
|
assert.deepEqual(
|
|
resolveSidebarSelectionAfterRefresh(null, workspaceItems, {
|
|
initialSelection: { kind: "search", id: "selected-search" },
|
|
selectFallback: true,
|
|
}),
|
|
{ kind: "search", id: "selected-search" }
|
|
);
|
|
assert.deepEqual(resolveSidebarSelectionAfterRefresh(null, workspaceItems, { selectFallback: true }), {
|
|
kind: "chat",
|
|
id: "completed-chat",
|
|
});
|
|
});
|