import { describe, expect, it, vi } from "vitest"; import { legacyPreferences, removeLegacyPreferences, presentationState, } from "./persistence"; import { initialWorkspaceState, reconcileWorkspace, workspaceReducer, } from "./reducer"; import type { Workspace } from "./types"; const workspace: Workspace = { bridgeInstanceId: "e", latestSeq: 7, directories: [ { worktreePath: "/repo", isHome: true, openCount: 1, workingCount: 0, attentionCount: 0, recoveringCount: 0, errorCount: 0, runtimes: [ { runtimeId: "r", worktreePath: "/repo", state: "idle", label: "r", attention: false, queueCount: 0, lastActivity: "now", openedAt: "now", agentId: "ephemeral", }, ], }, ], }; describe("presentation persistence", () => { it("persists only allowlisted presentation state, never agent or session payloads", () => { let state = reconcileWorkspace(initialWorkspaceState, workspace); state = workspaceReducer(state, { type: "draftChanged", runtimeId: "r", draft: "safe draft", }); state = workspaceReducer(state, { type: "setDefaultNewSessionWorktree", worktreePath: "/repo", }); const persisted = presentationState(state); const encoded = JSON.stringify(persisted); expect(persisted.drafts.r).toBe("safe draft"); expect(persisted.defaultNewSessionWorktree).toBe("/repo"); expect(encoded).not.toContain("ephemeral"); expect(encoded).not.toContain("messages"); expect(encoded).not.toContain("extensions"); }); it("reads and removes legacy worktree/scale only after caller saves", () => { const getItem = vi.fn((key: string) => key.includes("selected") ? "/repo" : "1.2", ); expect(legacyPreferences({ getItem })).toEqual({ path: "/repo", scale: 1.2, }); const removeItem = vi.fn(); removeLegacyPreferences({ removeItem }); expect(removeItem).toHaveBeenCalledTimes(2); }); });