diff --git a/packages/ui/src/apps/MobileSessionsSheet.tsx b/packages/ui/src/apps/MobileSessionsSheet.tsx index 39449100..97587436 100644 --- a/packages/ui/src/apps/MobileSessionsSheet.tsx +++ b/packages/ui/src/apps/MobileSessionsSheet.tsx @@ -45,7 +45,7 @@ import { PROJECT_COLOR_MAP, PROJECT_ICON_MAP, ProjectIconImage } from '@/lib/pro import { cn } from '@/lib/utils'; import { listProjectWorktrees } from '@/lib/worktrees/worktreeManager'; import { useDirectoryStore } from '@/stores/useDirectoryStore'; -import { mergeSessionDirectoryMetadata, refreshGlobalSessions, useGlobalSessionsStore } from '@/stores/useGlobalSessionsStore'; +import { mergeLiveSessionWithGlobalSession, refreshGlobalSessions, useGlobalSessionsStore } from '@/stores/useGlobalSessionsStore'; import { useMobileSessionExpansionStore } from '@/stores/useMobileSessionExpansionStore'; import { useMobileSessionTreeStore } from '@/stores/useMobileSessionTreeStore'; import { useProjectsStore } from '@/stores/useProjectsStore'; @@ -632,7 +632,7 @@ export const MobileSessionsSheet: React.FC = ({ open, const liveById = new Map(liveSessions.map((session) => [session.id, session])); const merged = globalActiveSessions.map((session) => { const liveSession = liveById.get(session.id); - return liveSession ? mergeSessionDirectoryMetadata(liveSession, session) : session; + return liveSession ? mergeLiveSessionWithGlobalSession(liveSession, session) : session; }); const seenIds = new Set(merged.map((session) => session.id)); for (const session of liveSessions) { diff --git a/packages/ui/src/components/chat/MobileSessionStatusBar.tsx b/packages/ui/src/components/chat/MobileSessionStatusBar.tsx index 32baad4a..fe47a173 100644 --- a/packages/ui/src/components/chat/MobileSessionStatusBar.tsx +++ b/packages/ui/src/components/chat/MobileSessionStatusBar.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { useSessionUIStore } from '@/sync/session-ui-store'; import { useAllSessionStatuses, useAllLiveSessions } from '@/sync/sync-context'; -import { mergeSessionDirectoryMetadata, useGlobalSessionsStore, ensureGlobalSessionsLoaded, refreshGlobalSessions } from '@/stores/useGlobalSessionsStore'; +import { mergeLiveSessionWithGlobalSession, useGlobalSessionsStore, ensureGlobalSessionsLoaded, refreshGlobalSessions } from '@/stores/useGlobalSessionsStore'; import { useUIStore } from '@/stores/useUIStore'; import { useProjectsStore } from '@/stores/useProjectsStore'; import type { Session } from '@opencode-ai/sdk/v2'; @@ -37,7 +37,7 @@ function useAllProjectSessions(): Session[] { const liveById = new Map(liveSessions.map((session) => [session.id, session])); const merged = globalActiveSessions.map((session) => { const liveSession = liveById.get(session.id); - return liveSession ? mergeSessionDirectoryMetadata(liveSession, session) : session; + return liveSession ? mergeLiveSessionWithGlobalSession(liveSession, session) : session; }); const seen = new Set(merged.map((session) => session.id)); for (const session of liveSessions) { diff --git a/packages/ui/src/components/session/SessionSidebar.tsx b/packages/ui/src/components/session/SessionSidebar.tsx index 8b4edaf3..eefb1666 100644 --- a/packages/ui/src/components/session/SessionSidebar.tsx +++ b/packages/ui/src/components/session/SessionSidebar.tsx @@ -70,7 +70,7 @@ import { normalizePath, } from './sidebar/utils'; import { - mergeSessionDirectoryMetadata, + mergeLiveSessionWithGlobalSession, refreshGlobalSessions, refreshGlobalSessionsForDirectories, resolveGlobalSessionDirectory, @@ -361,7 +361,7 @@ export const SessionSidebar: React.FC = ({ const liveById = new Map(liveSessions.map((session) => [session.id, session])); const merged = globalActiveSessions.map((session) => { const liveSession = liveById.get(session.id); - return liveSession ? mergeSessionDirectoryMetadata(liveSession, session) : session; + return liveSession ? mergeLiveSessionWithGlobalSession(liveSession, session) : session; }); const seenIds = new Set(merged.map((session) => session.id)); diff --git a/packages/ui/src/stores/useGlobalSessionsStore.test.ts b/packages/ui/src/stores/useGlobalSessionsStore.test.ts index 9c829cbd..3aaaa6d0 100644 --- a/packages/ui/src/stores/useGlobalSessionsStore.test.ts +++ b/packages/ui/src/stores/useGlobalSessionsStore.test.ts @@ -1,7 +1,7 @@ import { beforeEach, describe, expect, test } from 'bun:test'; import type { Session } from '@opencode-ai/sdk/v2'; -import { resolveGlobalSessionDirectory, useGlobalSessionsStore } from './useGlobalSessionsStore'; +import { resolveGlobalSessionDirectory, mergeLiveSessionWithGlobalSession, useGlobalSessionsStore } from './useGlobalSessionsStore'; type SessionExtra = Partial & { directory?: string | null; @@ -79,3 +79,30 @@ describe('useGlobalSessionsStore', () => { expect(resolveGlobalSessionDirectory(useGlobalSessionsStore.getState().archivedSessions[0])).toBe('/repo/app'); }); }); + +describe('mergeLiveSessionWithGlobalSession', () => { + test('preserves global share over live share', () => { + const live = buildSession('https://live.example/s', { time: { created: 1, updated: 5 } }); + const global = buildSession('https://global.example/s', { time: { created: 1, updated: 3 } }); + + const merged = mergeLiveSessionWithGlobalSession(live, global); + expect(merged.share?.url).toBe('https://global.example/s'); + expect(merged.time?.updated).toBe(5); + }); + + test('preserves directory from global when live omits it', () => { + const live = buildSession('https://live.example/s', { time: { created: 1, updated: 5 } }); + const global = buildSession('https://global.example/s', { directory: '/repo/app' }); + + const merged = mergeLiveSessionWithGlobalSession(live, global); + expect(resolveGlobalSessionDirectory(merged)).toBe('/repo/app'); + }); + + test('live directory takes precedence over global when present', () => { + const live = buildSession('https://live.example/s', { directory: '/repo/worktree' }); + const global = buildSession('https://global.example/s', { directory: '/repo/app' }); + + const merged = mergeLiveSessionWithGlobalSession(live, global); + expect(resolveGlobalSessionDirectory(merged)).toBe('/repo/worktree'); + }); +}); diff --git a/packages/ui/src/stores/useGlobalSessionsStore.ts b/packages/ui/src/stores/useGlobalSessionsStore.ts index 0fa8d101..354c76c0 100644 --- a/packages/ui/src/stores/useGlobalSessionsStore.ts +++ b/packages/ui/src/stores/useGlobalSessionsStore.ts @@ -100,6 +100,17 @@ export const mergeSessionDirectoryMetadata = (incoming: Session, existing?: Sess return changed ? next : incoming; }; +export const mergeLiveSessionWithGlobalSession = ( + liveSession: Session, + globalSession: Session, +): Session => { + const merged = mergeSessionDirectoryMetadata(liveSession, globalSession); + if (merged.share !== globalSession.share) { + return { ...merged, share: globalSession.share }; + } + return merged; +}; + const buildSessionsByDirectory = (sessions: Session[]): Map => { const next = new Map(); for (const session of sessions) {