// The canonical per-workstream tab order (persisted in papyrus KV) is the source of truth for // how a workstream's tabs are arranged. `reconcileTabOrder` keeps it complete and current: the // user's stored arrangement is preserved (minus ids of sessions that no longer exist), and every // session missing from it — a just-created tab, or one made outside papyrus — is appended in // CREATION order (oldest first; session id as a stable tiebreak). So a new session always lands // at the end rather than at silverwood's arbitrary `session ls` map position. The result is // deterministic, so callers persist it lazily (only when it differs from what's stored). export interface OrderedSession { sessionId: string; createdAt: string; } export function reconcileTabOrder( stored: string[] | undefined, sessions: OrderedSession[], ): string[] { const live = new Set(sessions.map((s) => s.sessionId)); const kept = (stored ?? []).filter((id) => live.has(id)); const have = new Set(kept); const appended = sessions .filter((s) => !have.has(s.sessionId)) .sort( (a, b) => a.createdAt.localeCompare(b.createdAt) || a.sessionId.localeCompare(b.sessionId), ) .map((s) => s.sessionId); return [...kept, ...appended]; } // Positional equality — lets a caller skip the KV write when `stored` is already canonical. // A `undefined` stored order is never equal (an unset workstream must be initialized). export function sameIds(a: string[] | undefined, b: string[]): boolean { return !!a && a.length === b.length && a.every((x, i) => x === b[i]); }