mirror of
https://github.com/stablyai/orca.git
synced 2026-09-29 16:02:50 +00:00
refactor(native-chat): unify host snapshot versioning
This commit is contained in:
@@ -142,7 +142,7 @@ export class OrcaRuntimeWithApplyMobileSessionTabNavigation extends OrcaRuntimeW
|
||||
tabs
|
||||
}
|
||||
this.persistHeadlessTerminalActiveLeaf(worktreeId, activeTab)
|
||||
this.mobileSessionTabsByWorktree.set(worktreeId, nextSnapshot)
|
||||
this.storeMobileSessionSnapshot(worktreeId, nextSnapshot)
|
||||
this.emitMobileSessionTabsSnapshot(nextSnapshot)
|
||||
}
|
||||
|
||||
|
||||
@@ -107,7 +107,7 @@ export class OrcaRuntimeWithCloseHeadlessMobileTerminalTab extends OrcaRuntimeWi
|
||||
: {}),
|
||||
tabs: nextTabs
|
||||
}
|
||||
this.mobileSessionTabsByWorktree.set(worktreeId, nextSnapshot)
|
||||
this.storeMobileSessionSnapshot(worktreeId, nextSnapshot)
|
||||
this.emitMobileSessionTabsSnapshot(nextSnapshot)
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ export class OrcaRuntimeWithCloseStructuredAgentSessionTab extends OrcaRuntimeWi
|
||||
})),
|
||||
tabs: nextTabs
|
||||
}
|
||||
this.mobileSessionTabsByWorktree.set(worktreeId, nextSnapshot)
|
||||
this.storeMobileSessionSnapshot(worktreeId, nextSnapshot)
|
||||
this.emitMobileSessionTabsSnapshot(nextSnapshot)
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ export class OrcaRuntimeWithCloseStructuredAgentSessionTab extends OrcaRuntimeWi
|
||||
protected republishMobileSessionTabsSnapshot(worktreeId: string): void {
|
||||
const snapshot = this.mobileSessionTabsByWorktree.get(worktreeId)
|
||||
if (snapshot) {
|
||||
this.mobileSessionTabsByWorktree.set(worktreeId, {
|
||||
this.storeMobileSessionSnapshot(worktreeId, {
|
||||
...snapshot,
|
||||
snapshotVersion: snapshot.snapshotVersion + 1
|
||||
})
|
||||
@@ -161,7 +161,7 @@ export class OrcaRuntimeWithCloseStructuredAgentSessionTab extends OrcaRuntimeWi
|
||||
})),
|
||||
tabs: nextTabs
|
||||
}
|
||||
this.mobileSessionTabsByWorktree.set(worktreeId, nextSnapshot)
|
||||
this.storeMobileSessionSnapshot(worktreeId, nextSnapshot)
|
||||
this.emitMobileSessionTabsSnapshot(nextSnapshot)
|
||||
return true
|
||||
}
|
||||
@@ -203,7 +203,7 @@ export class OrcaRuntimeWithCloseStructuredAgentSessionTab extends OrcaRuntimeWi
|
||||
focusesHost,
|
||||
publicationEpoch: `headless:${Date.now().toString(36)}`
|
||||
})
|
||||
this.mobileSessionTabsByWorktree.set(worktreeId, nextSnapshot)
|
||||
this.storeMobileSessionSnapshot(worktreeId, nextSnapshot)
|
||||
// Why: browser group membership is otherwise live-only; persist it so a
|
||||
// later rebuild keeps the browser in its group instead of coalescing left.
|
||||
if (placedInTargetGroup && nextSnapshot.tabGroupLayout) {
|
||||
|
||||
@@ -139,7 +139,7 @@ export class OrcaRuntimeWithCreateRuntimeOwnedMobileSessionTerminal extends Orca
|
||||
...(existing?.tabGroupLayout ? { tabGroupLayout: existing.tabGroupLayout } : {}),
|
||||
tabs
|
||||
}
|
||||
this.mobileSessionTabsByWorktree.set(worktreeId, next)
|
||||
this.storeMobileSessionSnapshot(worktreeId, next)
|
||||
const result = this.toMobileSessionTabsResult(next)
|
||||
const changeSequence = ++this.mobileSessionTabsChangeSequence
|
||||
for (const subscription of this.mobileSessionTabListeners) {
|
||||
|
||||
@@ -65,7 +65,7 @@ export class OrcaRuntimeWithHasExactPersistedTerminalSurfaceIdentity extends Orc
|
||||
exactOnly: true
|
||||
})
|
||||
if (retired) {
|
||||
this.mobileSessionTabsByWorktree.set(candidate.worktreeId, retired.snapshot)
|
||||
this.storeMobileSessionSnapshot(candidate.worktreeId, retired.snapshot)
|
||||
this.notifyMobileSessionTabsChanged(candidate.worktreeId)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -236,7 +236,7 @@ export class OrcaRuntimeWithHydrateHeadlessMobileSessionTabsFromWorkspaceSession
|
||||
if (existing && headlessMobileSnapshotContentUnchanged(existing, nextSnapshot)) {
|
||||
continue
|
||||
}
|
||||
this.mobileSessionTabsByWorktree.set(entryWorktreeId, nextSnapshot)
|
||||
this.storeMobileSessionSnapshot(entryWorktreeId, nextSnapshot)
|
||||
}
|
||||
return reconciledWorktreeIds
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ export class OrcaRuntimeWithMoveHeadlessMobileSessionTab extends OrcaRuntimeWith
|
||||
if (nextGroups.length > 1 && snapshot.tabGroupLayout) {
|
||||
this.persistHeadlessTabGroups(worktreeId, nextGroups, snapshot.tabGroupLayout)
|
||||
}
|
||||
this.mobileSessionTabsByWorktree.set(worktreeId, nextSnapshot)
|
||||
this.storeMobileSessionSnapshot(worktreeId, nextSnapshot)
|
||||
this.emitMobileSessionTabsSnapshot(nextSnapshot)
|
||||
return { moved: true }
|
||||
}
|
||||
@@ -111,7 +111,7 @@ export class OrcaRuntimeWithMoveHeadlessMobileSessionTab extends OrcaRuntimeWith
|
||||
tabGroupLayout: split.layout
|
||||
}
|
||||
this.persistHeadlessTabGroups(worktreeId, split.groups, split.layout)
|
||||
this.mobileSessionTabsByWorktree.set(worktreeId, nextSnapshot)
|
||||
this.storeMobileSessionSnapshot(worktreeId, nextSnapshot)
|
||||
this.emitMobileSessionTabsSnapshot(nextSnapshot)
|
||||
return { moved: true }
|
||||
}
|
||||
@@ -147,7 +147,7 @@ export class OrcaRuntimeWithMoveHeadlessMobileSessionTab extends OrcaRuntimeWith
|
||||
tabGroupLayout: layout
|
||||
}
|
||||
this.persistHeadlessTabGroups(worktreeId, moved.groups, layout)
|
||||
this.mobileSessionTabsByWorktree.set(worktreeId, nextSnapshot)
|
||||
this.storeMobileSessionSnapshot(worktreeId, nextSnapshot)
|
||||
this.emitMobileSessionTabsSnapshot(nextSnapshot)
|
||||
return { moved: true }
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ export class OrcaRuntimeWithPersistHeadlessSessionTabProps extends OrcaRuntimeWi
|
||||
snapshotVersion: snapshot.snapshotVersion + 1,
|
||||
tabs
|
||||
}
|
||||
this.mobileSessionTabsByWorktree.set(worktreeId, nextSnapshot)
|
||||
this.storeMobileSessionSnapshot(worktreeId, nextSnapshot)
|
||||
this.emitMobileSessionTabsSnapshot(nextSnapshot)
|
||||
}
|
||||
|
||||
@@ -181,7 +181,7 @@ export class OrcaRuntimeWithPersistHeadlessSessionTabProps extends OrcaRuntimeWi
|
||||
snapshotVersion: snapshot.snapshotVersion + 1,
|
||||
tabs
|
||||
}
|
||||
this.mobileSessionTabsByWorktree.set(worktreeId, nextSnapshot)
|
||||
this.storeMobileSessionSnapshot(worktreeId, nextSnapshot)
|
||||
this.emitMobileSessionTabsSnapshot(nextSnapshot)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,7 +173,7 @@ export class OrcaRuntimeWithPersistTerminalSurfaceRetirements extends OrcaRuntim
|
||||
: {})
|
||||
})
|
||||
if (retired) {
|
||||
this.mobileSessionTabsByWorktree.set(worktreeId, retired.snapshot)
|
||||
this.storeMobileSessionSnapshot(worktreeId, retired.snapshot)
|
||||
this.notifyMobileSessionTabsChanged(worktreeId)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,7 +142,7 @@ export class OrcaRuntimeWithPublishPtyBackedMobileSessionTerminal extends OrcaRu
|
||||
...(existing?.tabGroupLayout ? { tabGroupLayout: existing.tabGroupLayout } : {}),
|
||||
tabs
|
||||
}
|
||||
this.mobileSessionTabsByWorktree.set(worktreeId, next)
|
||||
this.storeMobileSessionSnapshot(worktreeId, next)
|
||||
if (args.notify !== false) {
|
||||
this.notifyMobileSessionTabsChanged(worktreeId)
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ export class OrcaRuntimeWithReconcileHeadlessMobileSessionBrowserTabs extends Or
|
||||
const active = activeStillPresent
|
||||
? null
|
||||
: (nextTabs.find((tab) => tab.isActive) ?? nextTabs[0] ?? null)
|
||||
this.mobileSessionTabsByWorktree.set(worktreeId, {
|
||||
this.storeMobileSessionSnapshot(worktreeId, {
|
||||
...existing,
|
||||
publicationEpoch: `headless-hydrated:${Date.now().toString(36)}`,
|
||||
snapshotVersion: existing.snapshotVersion + 1,
|
||||
|
||||
+1
-1
@@ -39,7 +39,7 @@ export class OrcaRuntimeWithRestoreLivePairedRendererSessionOwnedMobileTerminals
|
||||
continue
|
||||
}
|
||||
if (!existing) {
|
||||
this.mobileSessionTabsByWorktree.set(targetWorktreeId, {
|
||||
this.storeMobileSessionSnapshot(targetWorktreeId, {
|
||||
worktree: targetWorktreeId,
|
||||
publicationEpoch: `renderer-rescue:${Date.now().toString(36)}`,
|
||||
snapshotVersion: 0,
|
||||
|
||||
@@ -94,7 +94,7 @@ export class OrcaRuntimeWithRestoreStructuredAgentSessionTabsOnce extends OrcaRu
|
||||
),
|
||||
tabs: existing.tabs.map((tab) => ({ ...tab, isActive: tab.id === id }))
|
||||
}
|
||||
this.mobileSessionTabsByWorktree.set(input.workspaceId, snapshot)
|
||||
this.storeMobileSessionSnapshot(input.workspaceId, snapshot)
|
||||
if (input.notify !== false) {
|
||||
this.emitMobileSessionTabsSnapshot(snapshot)
|
||||
}
|
||||
@@ -143,7 +143,7 @@ export class OrcaRuntimeWithRestoreStructuredAgentSessionTabsOnce extends OrcaRu
|
||||
...(existing?.tabGroupLayout ? { tabGroupLayout: existing.tabGroupLayout } : {}),
|
||||
tabs
|
||||
}
|
||||
this.mobileSessionTabsByWorktree.set(input.workspaceId, snapshot)
|
||||
this.storeMobileSessionSnapshot(input.workspaceId, snapshot)
|
||||
if (input.notify !== false) {
|
||||
this.emitMobileSessionTabsSnapshot(snapshot)
|
||||
}
|
||||
|
||||
@@ -96,6 +96,21 @@ export class OrcaRuntimeWithRuntimeId {
|
||||
|
||||
protected mobileSessionTabsByWorktree = new Map<string, RuntimeMobileSessionTabsSnapshot>()
|
||||
|
||||
/** Single host writer for mobile session snapshots; versions are total-order stamps. */
|
||||
protected storeMobileSessionSnapshot(
|
||||
worktreeId: string,
|
||||
snapshot: RuntimeMobileSessionTabsSnapshot
|
||||
): RuntimeMobileSessionTabsSnapshot {
|
||||
const existing = this.mobileSessionTabsByWorktree.get(worktreeId)
|
||||
const snapshotVersion = existing
|
||||
? Math.max(snapshot.snapshotVersion, existing.snapshotVersion + 1)
|
||||
: snapshot.snapshotVersion
|
||||
const stamped =
|
||||
snapshotVersion === snapshot.snapshotVersion ? snapshot : { ...snapshot, snapshotVersion }
|
||||
this.mobileSessionTabsByWorktree.set(worktreeId, stamped)
|
||||
return stamped
|
||||
}
|
||||
|
||||
protected structuredAgentSessionTabRestorePromise: Promise<void> | null = null
|
||||
|
||||
protected structuredAgentSessionStartupRestorePromise: Promise<void> | null = null
|
||||
|
||||
@@ -57,7 +57,7 @@ export class OrcaRuntimeWithStopRequestedPtyIds extends OrcaRuntimeWithRuntimeId
|
||||
resolveOwner: (handle) => this.resolveNativeChatLaunchDraftOwner(handle),
|
||||
listMobileSnapshots: () => this.mobileSessionTabsByWorktree,
|
||||
setMobileSnapshot: (worktreeId, snapshot) =>
|
||||
this.mobileSessionTabsByWorktree.set(worktreeId, snapshot),
|
||||
this.storeMobileSessionSnapshot(worktreeId, snapshot),
|
||||
scheduleMobileSnapshot: (worktreeId) => this.scheduleMobileSessionTabsChanged(worktreeId),
|
||||
notifyResolved: (tabId, resolution, event) => {
|
||||
this.notifier?.nativeChatLaunchDraftResolved?.(tabId, resolution)
|
||||
|
||||
@@ -8,7 +8,6 @@ import type {
|
||||
import { getMobileSessionSnapshotTabIdentityKeys } from './mobile-session-tab-merge'
|
||||
import { getRuntimeBrowserPageRegistry } from './runtime-browser-page-registry'
|
||||
import { sameRuntimeBrowserPlacement } from '../../shared/runtime-browser-placement'
|
||||
import { createHash } from 'node:crypto'
|
||||
import type { ClientHostedBrowserRowsEvent } from '../../shared/client-hosted-browser-rows'
|
||||
|
||||
export class OrcaRuntimeWithStoredMobileSnapshotHasStalePreservedTab extends OrcaRuntimeWithMergePreservedHeadlessMobileSessionTabs {
|
||||
@@ -115,23 +114,14 @@ export class OrcaRuntimeWithStoredMobileSnapshotHasStalePreservedTab extends Orc
|
||||
|
||||
protected getMergedMobileSessionPublicationEpoch(
|
||||
snapshot: RuntimeMobileSessionTabsSnapshot,
|
||||
preservedTabs: readonly RuntimeMobileSessionSnapshotTab[]
|
||||
_preservedTabs: readonly RuntimeMobileSessionSnapshotTab[]
|
||||
): string {
|
||||
// Why: preserved snapshots can merge repeatedly; strip the prior merge suffix first so the publication epoch stays idempotent.
|
||||
const normalizedPublicationEpoch = snapshot.publicationEpoch.split(':headless-merge:')[0]
|
||||
const signature = createHash('sha1')
|
||||
.update(
|
||||
preservedTabs
|
||||
.map((tab) =>
|
||||
tab.type === 'terminal'
|
||||
? `${tab.id}:${tab.parentTabId}:${tab.ptyId ?? ''}:${tab.leafId}`
|
||||
: tab.id
|
||||
)
|
||||
.join('|')
|
||||
)
|
||||
.digest('hex')
|
||||
.slice(0, 12)
|
||||
return `${normalizedPublicationEpoch}:headless-merge:${signature}`
|
||||
// The epoch identifies the publisher generation, not the merged content.
|
||||
// Content changes are ordered by snapshotVersion, so encoding a merge hash
|
||||
// here would make the identity oscillate and permanently fence later rows.
|
||||
return normalizedPublicationEpoch
|
||||
}
|
||||
|
||||
/** Serves a hydrating host renderer; the publisher counts this as a delivery, not a read. */
|
||||
|
||||
@@ -167,7 +167,7 @@ export class OrcaRuntimeWithSyncMobileSessionTabs extends OrcaRuntimeWithWriteOr
|
||||
const storedVersion = existing
|
||||
? Math.max(nextSnapshot.snapshotVersion, existing.snapshotVersion + 1)
|
||||
: nextSnapshot.snapshotVersion
|
||||
this.mobileSessionTabsByWorktree.set(
|
||||
this.storeMobileSessionSnapshot(
|
||||
snapshot.worktree,
|
||||
storedVersion === nextSnapshot.snapshotVersion
|
||||
? nextSnapshot
|
||||
@@ -195,7 +195,7 @@ export class OrcaRuntimeWithSyncMobileSessionTabs extends OrcaRuntimeWithWriteOr
|
||||
preserved.tabs.length === existing.tabs.length &&
|
||||
preserved.tabs.every((tab, index) => tab === existing.tabs[index])
|
||||
if (!preservedIsNoOp) {
|
||||
this.mobileSessionTabsByWorktree.set(worktreeId, preserved)
|
||||
this.storeMobileSessionSnapshot(worktreeId, preserved)
|
||||
}
|
||||
// Why: the stored entry is no longer the renderer's publication, so a
|
||||
// future renderer frame must be re-merged even if it reuses the pair.
|
||||
|
||||
@@ -238,7 +238,7 @@ export class OrcaRuntimeWithSyncWindowGraph extends OrcaRuntimeWithAttachWindow
|
||||
// the PTY touch path does) or the re-emitted payload — e.g. the
|
||||
// pending-handle → ready flip — is discarded and the client stays stale.
|
||||
// The accepted-renderer tracking is untouched: this is a main-local bump.
|
||||
this.mobileSessionTabsByWorktree.set(worktreeId, {
|
||||
this.storeMobileSessionSnapshot(worktreeId, {
|
||||
...stored,
|
||||
snapshotVersion: stored.snapshotVersion + 1
|
||||
})
|
||||
|
||||
@@ -595,7 +595,7 @@ describe('OrcaRuntimeService', () => {
|
||||
const secondMerge = await runtime.listMobileSessionTabs(`id:${TEST_WORKTREE_ID}`)
|
||||
|
||||
expect(secondMerge.publicationEpoch).toBe(firstMerge.publicationEpoch)
|
||||
expect(secondMerge.publicationEpoch.match(/:headless-merge:/g) ?? []).toHaveLength(1)
|
||||
expect(secondMerge.publicationEpoch).toBe('headless:stable-epoch')
|
||||
})
|
||||
|
||||
it('keeps the graph ready when a mobile snapshot references a removed folder workspace', () => {
|
||||
|
||||
@@ -21,7 +21,7 @@ export class OrcaRuntimeWithTouchMobileSessionTabsForWorktree extends OrcaRuntim
|
||||
if (!snapshot) {
|
||||
return
|
||||
}
|
||||
this.mobileSessionTabsByWorktree.set(worktreeId, {
|
||||
this.storeMobileSessionSnapshot(worktreeId, {
|
||||
...snapshot,
|
||||
snapshotVersion: snapshot.snapshotVersion + 1
|
||||
})
|
||||
|
||||
@@ -6,7 +6,8 @@ import { buildPersistedUnifiedTabSessionData } from '../lib/workspace-session-un
|
||||
import { buildHydratedTabState } from '../store/slices/tabs-hydration'
|
||||
import {
|
||||
applyLocalStructuredSessionTabSnapshots,
|
||||
projectLocalStructuredSessionTabs
|
||||
projectLocalStructuredSessionTabs,
|
||||
resetLocalStructuredSessionVersionForTests
|
||||
} from './local-structured-session-tabs-sync'
|
||||
import {
|
||||
applyWebSessionTabsSnapshot,
|
||||
@@ -25,6 +26,7 @@ const PRIMARY_GROUP = 'primary-group'
|
||||
const SECONDARY_GROUP = 'secondary-group'
|
||||
|
||||
afterEach(() => {
|
||||
resetLocalStructuredSessionVersionForTests()
|
||||
resetWebSessionFocusIntentForTests()
|
||||
resetWebSessionTabsSnapshotFreshnessForTests()
|
||||
})
|
||||
@@ -148,6 +150,49 @@ function expectExactSplit(state: {
|
||||
}
|
||||
|
||||
describe('local structured session tab projection', () => {
|
||||
it('accepts a newer session after merged content returns to the base epoch', () => {
|
||||
const state = createSnapshot()
|
||||
const base = {
|
||||
...({
|
||||
worktree: WORKTREE_ID,
|
||||
publicationEpoch: 'renderer:generation-1',
|
||||
snapshotVersion: 4,
|
||||
activeGroupId: null,
|
||||
activeTabId: null,
|
||||
activeTabType: null,
|
||||
tabs: []
|
||||
} satisfies RuntimeMobileSessionTabsResult)
|
||||
}
|
||||
const withChat = {
|
||||
...base,
|
||||
snapshotVersion: 5,
|
||||
tabs: [
|
||||
{
|
||||
type: 'agent-session' as const,
|
||||
id: STRUCTURED_ID,
|
||||
title: 'Codex Chat',
|
||||
sessionId: 'codex-1',
|
||||
agent: 'codex' as const,
|
||||
isActive: true
|
||||
}
|
||||
]
|
||||
}
|
||||
const afterClose = { ...base, snapshotVersion: 6 }
|
||||
const next = applyLocalStructuredSessionTabSnapshots(
|
||||
state,
|
||||
[
|
||||
base,
|
||||
withChat,
|
||||
afterClose,
|
||||
{ ...base, snapshotVersion: 7, tabs: [{ ...withChat.tabs[0], isActive: true }] }
|
||||
],
|
||||
'local-structured-session'
|
||||
)
|
||||
expect(next.unifiedTabsByWorktree[WORKTREE_ID]).toEqual(
|
||||
expect.arrayContaining([expect.objectContaining({ contentType: 'agent-session' })])
|
||||
)
|
||||
})
|
||||
|
||||
it('drops terminal topology while retaining structured tabs', () => {
|
||||
const snapshot = {
|
||||
worktree: 'workspace-1',
|
||||
|
||||
@@ -4,15 +4,19 @@ import type { RuntimeMobileSessionTabsResult } from '../../../shared/runtime-typ
|
||||
import { useAppStore } from '../store'
|
||||
import type { WorktreeRuntimeOwnerState } from '../lib/worktree-runtime-owner'
|
||||
import { getExecutionHostIdForWorktree } from '../lib/worktree-runtime-owner'
|
||||
import {
|
||||
applyWebSessionTabsSnapshot,
|
||||
applyWebSessionTabsStorePatch,
|
||||
decideWebSessionTabsSnapshot
|
||||
} from './web-session-tabs-sync'
|
||||
import { applyWebSessionTabsSnapshot, applyWebSessionTabsStorePatch } from './web-session-tabs-sync'
|
||||
import type { WebSessionTabsSyncState } from './web-session-tabs-sync'
|
||||
|
||||
export const LOCAL_STRUCTURED_SESSION_OWNER = 'local-structured-session'
|
||||
let localStructuredSessionTabsRestorePromise: Promise<void> | null = null
|
||||
const localStructuredSessionVersionByWorktree = new Map<
|
||||
string,
|
||||
{ publicationEpoch: string; snapshotVersion: number }
|
||||
>()
|
||||
|
||||
export function resetLocalStructuredSessionVersionForTests(): void {
|
||||
localStructuredSessionVersionByWorktree.clear()
|
||||
}
|
||||
|
||||
type SessionTabsEvent =
|
||||
| (RuntimeMobileSessionTabsResult & { type: 'snapshot' | 'updated' })
|
||||
@@ -79,7 +83,9 @@ export function applyLocalStructuredSessionTabSnapshots<
|
||||
if (getExecutionHostIdForWorktree(next, snapshot.worktree) !== 'local') {
|
||||
continue
|
||||
}
|
||||
if (!decideWebSessionTabsSnapshot(snapshot, owner).apply) {
|
||||
const prior = localStructuredSessionVersionByWorktree.get(snapshot.worktree)
|
||||
const isNewerPublisher = prior?.publicationEpoch !== snapshot.publicationEpoch
|
||||
if (prior && !isNewerPublisher && snapshot.snapshotVersion <= prior.snapshotVersion) {
|
||||
continue
|
||||
}
|
||||
const patch = applyWebSessionTabsSnapshot(
|
||||
@@ -94,6 +100,10 @@ export function applyLocalStructuredSessionTabSnapshots<
|
||||
}
|
||||
)
|
||||
next = patch === next ? next : ({ ...next, ...patch } as State)
|
||||
localStructuredSessionVersionByWorktree.set(snapshot.worktree, {
|
||||
publicationEpoch: snapshot.publicationEpoch,
|
||||
snapshotVersion: snapshot.snapshotVersion
|
||||
})
|
||||
}
|
||||
return next
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user