mirror of
https://github.com/stablyai/orca.git
synced 2026-10-25 16:03:53 +00:00
fix(dashboard): follow active agent pane mode
This commit is contained in:
@@ -199,7 +199,7 @@ describe('buildDashboardSnapshot', () => {
|
||||
expect(card.unseen).toBe(true)
|
||||
})
|
||||
|
||||
it('carries native-chat session identity when Chat UI is the default view', () => {
|
||||
it('carries native-chat session identity when the exact live leaf is in chat', () => {
|
||||
const snapshot = buildDashboardSnapshot(
|
||||
baseState({
|
||||
agentStatusByPaneKey: {
|
||||
@@ -211,32 +211,35 @@ describe('buildDashboardSnapshot', () => {
|
||||
}
|
||||
})
|
||||
},
|
||||
settings: { experimentalNativeChat: true, openAgentTabsInChatByDefault: true } as never
|
||||
runtimeNativeChatLeafIdByTabId: { [TAB_ID]: LEAF_ID },
|
||||
settings: { experimentalNativeChat: true, openAgentTabsInChatByDefault: false } as never
|
||||
} as unknown as Partial<DashboardSnapshotState>),
|
||||
NOW
|
||||
)
|
||||
|
||||
expect(snapshot.cards[0]).toMatchObject({
|
||||
hostKind: 'local',
|
||||
viewMode: 'chat',
|
||||
sessionId: 'session-abc',
|
||||
transcriptPath: '/home/dev/.claude/projects/orca/session-abc.jsonl'
|
||||
transcriptPath: expect.stringContaining('session-abc')
|
||||
})
|
||||
})
|
||||
|
||||
it('keeps native chat disabled when the experiment is off', () => {
|
||||
it.each([
|
||||
['the experiment is off', 'claude', false],
|
||||
['the leaf agent is unsupported', 'aider', true]
|
||||
] as const)('keeps native chat disabled when %s', (_case, agentType, experimentEnabled) => {
|
||||
const snapshot = buildDashboardSnapshot(
|
||||
baseState({
|
||||
agentStatusByPaneKey: { [PANE_KEY]: entry({}) },
|
||||
settings: { experimentalNativeChat: false, openAgentTabsInChatByDefault: true }
|
||||
agentStatusByPaneKey: { [PANE_KEY]: entry({ agentType }) },
|
||||
runtimeNativeChatLeafIdByTabId: { [TAB_ID]: LEAF_ID },
|
||||
settings: { experimentalNativeChat: experimentEnabled, openAgentTabsInChatByDefault: true }
|
||||
} as unknown as Partial<DashboardSnapshotState>),
|
||||
NOW
|
||||
)
|
||||
|
||||
expect(snapshot.cards[0].viewMode).toBeUndefined()
|
||||
})
|
||||
|
||||
it('omits native-chat payload when the default view is the terminal', () => {
|
||||
it('omits native-chat payload when the live leaf is terminal despite a chat default', () => {
|
||||
const snapshot = buildDashboardSnapshot(
|
||||
baseState({
|
||||
agentStatusByPaneKey: {
|
||||
@@ -248,26 +251,43 @@ describe('buildDashboardSnapshot', () => {
|
||||
}
|
||||
})
|
||||
},
|
||||
settings: { experimentalNativeChat: true, openAgentTabsInChatByDefault: false }
|
||||
} as unknown as Partial<DashboardSnapshotState>),
|
||||
NOW
|
||||
)
|
||||
|
||||
expect(snapshot.cards[0]).not.toHaveProperty('viewMode')
|
||||
expect(snapshot.cards[0]).not.toHaveProperty('sessionId')
|
||||
expect(snapshot.cards[0]).not.toHaveProperty('transcriptPath')
|
||||
})
|
||||
|
||||
it('keeps agents without a native-chat renderer in terminal mode', () => {
|
||||
const snapshot = buildDashboardSnapshot(
|
||||
baseState({
|
||||
agentStatusByPaneKey: { [PANE_KEY]: entry({ agentType: 'aider' }) },
|
||||
terminalLayoutsByTabId: {},
|
||||
runtimeNativeChatLeafIdByTabId: { [TAB_ID]: LEAF_ID },
|
||||
settings: { experimentalNativeChat: true, openAgentTabsInChatByDefault: true }
|
||||
} as unknown as Partial<DashboardSnapshotState>),
|
||||
NOW
|
||||
)
|
||||
|
||||
expect(snapshot.cards[0].viewMode).toBeUndefined()
|
||||
expect(snapshot.cards[0]).not.toHaveProperty('viewMode')
|
||||
})
|
||||
|
||||
it('marks only the native-chat owner in a split tab as chat', () => {
|
||||
const snapshot = buildDashboardSnapshot(
|
||||
baseState({
|
||||
agentStatusByPaneKey: {
|
||||
[PANE_KEY]: entry({}),
|
||||
[CHILD_PANE_KEY]: entry({ paneKey: CHILD_PANE_KEY })
|
||||
},
|
||||
terminalLayoutsByTabId: {
|
||||
[TAB_ID]: {
|
||||
root: {
|
||||
type: 'split',
|
||||
direction: 'horizontal',
|
||||
first: { type: 'leaf', leafId: LEAF_ID },
|
||||
second: { type: 'leaf', leafId: CHILD_LEAF_ID }
|
||||
},
|
||||
ptyIdsByLeafId: { [LEAF_ID]: 'pty1', [CHILD_LEAF_ID]: 'pty-child' }
|
||||
} as never
|
||||
},
|
||||
ptyIdsByTabId: { [TAB_ID]: ['pty1', 'pty-child'] },
|
||||
runtimeNativeChatLeafIdByTabId: { [TAB_ID]: LEAF_ID },
|
||||
settings: { experimentalNativeChat: true, openAgentTabsInChatByDefault: true } as never
|
||||
}),
|
||||
NOW
|
||||
)
|
||||
|
||||
expect(snapshot.cards.find((card) => card.paneKey === PANE_KEY)?.viewMode).toBe('chat')
|
||||
expect(snapshot.cards.find((card) => card.paneKey === CHILD_PANE_KEY)?.viewMode).toBeUndefined()
|
||||
})
|
||||
|
||||
it('marks SSH transcript paths as remote from the dashboard renderer', () => {
|
||||
|
||||
@@ -39,10 +39,7 @@ import {
|
||||
resolveDashboardCardContext,
|
||||
type DashboardCardContextState
|
||||
} from './dashboard-card-context'
|
||||
import {
|
||||
dashboardCardNativeChatMetadata,
|
||||
dashboardNativeChatByDefault
|
||||
} from './dashboard-card-native-chat'
|
||||
import { dashboardCardNativeChatMetadata } from './dashboard-card-native-chat'
|
||||
import {
|
||||
dashboardCardMapWorkspaceMetadata,
|
||||
collectActiveDashboardWorkspaces
|
||||
@@ -79,7 +76,11 @@ export type DashboardSnapshotState = Pick<
|
||||
| 'settings'
|
||||
> &
|
||||
DashboardCardContextState &
|
||||
Partial<DashboardCardTerminalInputState & DashboardLaunchDetectionState>
|
||||
Partial<
|
||||
DashboardCardTerminalInputState &
|
||||
DashboardLaunchDetectionState &
|
||||
Pick<AppState, 'runtimeNativeChatLeafIdByTabId'>
|
||||
>
|
||||
|
||||
/**
|
||||
* Derive the serializable dashboard snapshot from the live renderer store.
|
||||
@@ -101,7 +102,6 @@ export function buildDashboardSnapshot(
|
||||
const includeCardDetails = options.includeCardDetails !== false
|
||||
const generatedTitlesEnabled = state.settings?.tabAutoGenerateTitle === true
|
||||
const showIdle = state.settings?.experimentalAgentDashboardShowIdle === true
|
||||
const nativeChatByDefault = includeCardDetails && dashboardNativeChatByDefault(state.settings)
|
||||
const activeWorktrees = collectActiveDashboardWorkspaces(state, includeCardDetails)
|
||||
const filterOptions =
|
||||
options.includeFilterOptions === false
|
||||
@@ -277,9 +277,13 @@ export function buildDashboardSnapshot(
|
||||
terminalInput ?? undefined,
|
||||
clientHost.platform
|
||||
),
|
||||
...(nativeChatByDefault
|
||||
? dashboardCardNativeChatMetadata(row.agentType, row.entry.providerSession)
|
||||
: {})
|
||||
...dashboardCardNativeChatMetadata(
|
||||
row.agentType,
|
||||
row.entry.providerSession,
|
||||
state.settings?.experimentalNativeChat === true &&
|
||||
layoutPtyId !== null &&
|
||||
state.runtimeNativeChatLeafIdByTabId?.[tabId] === leafId
|
||||
)
|
||||
}
|
||||
: {}),
|
||||
workspaceStatusId: context?.workspaceStatus.id,
|
||||
|
||||
@@ -1,28 +1,15 @@
|
||||
import type { GlobalSettings } from '../../../../shared/types'
|
||||
import { isNativeChatSupportedAgent } from '../../../../shared/native-chat-agent-support'
|
||||
import type { DashboardCard } from '../../../../shared/dashboard-snapshot'
|
||||
import type { DashboardAgentRow } from './useDashboardData'
|
||||
|
||||
/** The inspector follows the user's existing Chat UI default-view setting —
|
||||
* no separate dashboard opt-in, and no per-tab mode reads. */
|
||||
export function dashboardNativeChatByDefault(
|
||||
settings:
|
||||
| Pick<GlobalSettings, 'experimentalNativeChat' | 'openAgentTabsInChatByDefault'>
|
||||
| null
|
||||
| undefined
|
||||
): boolean {
|
||||
return (
|
||||
settings?.experimentalNativeChat === true && settings?.openAgentTabsInChatByDefault === true
|
||||
)
|
||||
}
|
||||
|
||||
/** Chat-mode cards carry the transcript coordinates the inspector reads.
|
||||
* hostKind comes from the map's workspace metadata, not from here. */
|
||||
export function dashboardCardNativeChatMetadata(
|
||||
agentType: string,
|
||||
providerSession: DashboardAgentRow['entry']['providerSession']
|
||||
providerSession: DashboardAgentRow['entry']['providerSession'],
|
||||
isNativeChatView: boolean
|
||||
): Pick<DashboardCard, 'viewMode' | 'sessionId' | 'transcriptPath'> {
|
||||
if (!isNativeChatSupportedAgent(agentType)) {
|
||||
if (!isNativeChatView || !isNativeChatSupportedAgent(agentType)) {
|
||||
return {}
|
||||
}
|
||||
return {
|
||||
|
||||
@@ -65,6 +65,7 @@ function makeSnapshotWatchState(): DashboardSnapshotWatchState {
|
||||
terminalLayoutsByTabId: {},
|
||||
ptyIdsByTabId: {},
|
||||
runtimePaneTitlesByTabId: {},
|
||||
runtimeNativeChatLeafIdByTabId: {},
|
||||
acknowledgedAgentsByPaneKey: {},
|
||||
settings: null,
|
||||
agentStatusEpoch: 0,
|
||||
@@ -186,6 +187,7 @@ describe('useDashboardPopoutBridge', () => {
|
||||
'terminalLayoutsByTabId',
|
||||
'ptyIdsByTabId',
|
||||
'runtimePaneTitlesByTabId',
|
||||
'runtimeNativeChatLeafIdByTabId',
|
||||
'acknowledgedAgentsByPaneKey',
|
||||
'hostedReviewCache',
|
||||
'prCache',
|
||||
|
||||
@@ -52,6 +52,7 @@ export function dashboardSnapshotInputsChanged(
|
||||
state.terminalLayoutsByTabId !== previousState.terminalLayoutsByTabId ||
|
||||
state.ptyIdsByTabId !== previousState.ptyIdsByTabId ||
|
||||
state.runtimePaneTitlesByTabId !== previousState.runtimePaneTitlesByTabId ||
|
||||
state.runtimeNativeChatLeafIdByTabId !== previousState.runtimeNativeChatLeafIdByTabId ||
|
||||
state.acknowledgedAgentsByPaneKey !== previousState.acknowledgedAgentsByPaneKey ||
|
||||
state.hostedReviewCache !== previousState.hostedReviewCache ||
|
||||
state.prCache !== previousState.prCache ||
|
||||
|
||||
@@ -22,6 +22,7 @@ export function useLiveDashboardSnapshot(): DashboardSnapshot {
|
||||
const terminalLayoutsByTabId = useAppStore((s) => s.terminalLayoutsByTabId)
|
||||
const ptyIdsByTabId = useAppStore((s) => s.ptyIdsByTabId)
|
||||
const runtimePaneTitlesByTabId = useAppStore((s) => s.runtimePaneTitlesByTabId)
|
||||
const runtimeNativeChatLeafIdByTabId = useAppStore((s) => s.runtimeNativeChatLeafIdByTabId)
|
||||
const acknowledgedAgentsByPaneKey = useAppStore((s) => s.acknowledgedAgentsByPaneKey)
|
||||
const hostedReviewCache = useAppStore((s) => s.hostedReviewCache)
|
||||
const prCache = useAppStore((s) => s.prCache)
|
||||
@@ -74,6 +75,7 @@ export function useLiveDashboardSnapshot(): DashboardSnapshot {
|
||||
terminalLayoutsByTabId,
|
||||
ptyIdsByTabId,
|
||||
runtimePaneTitlesByTabId,
|
||||
runtimeNativeChatLeafIdByTabId,
|
||||
acknowledgedAgentsByPaneKey,
|
||||
hostedReviewCache,
|
||||
prCache,
|
||||
@@ -112,6 +114,7 @@ export function useLiveDashboardSnapshot(): DashboardSnapshot {
|
||||
terminalLayoutsByTabId,
|
||||
ptyIdsByTabId,
|
||||
runtimePaneTitlesByTabId,
|
||||
runtimeNativeChatLeafIdByTabId,
|
||||
acknowledgedAgentsByPaneKey,
|
||||
hostedReviewCache,
|
||||
prCache,
|
||||
|
||||
@@ -510,6 +510,7 @@ function TerminalPane(
|
||||
?.viewMode === 'chat'
|
||||
)
|
||||
const nativeChatEnabled = useAppStore((store) => store.settings?.experimentalNativeChat === true)
|
||||
const settings = useAppStore((store) => store.settings)
|
||||
const effectiveChatViewMode = nativeChatEnabled && isChatViewMode
|
||||
const unifiedTabLabel = useAppStore(
|
||||
(store) =>
|
||||
@@ -707,7 +708,6 @@ function TerminalPane(
|
||||
const clearTerminalPaneUnread = useAppStore((store) => store.clearTerminalPaneUnread)
|
||||
const openSpacePage = useAppStore((store) => store.openSpacePage)
|
||||
const refreshWorkspaceSpace = useAppStore((store) => store.refreshWorkspaceSpace)
|
||||
const settings = useAppStore((store) => store.settings)
|
||||
const updateSettings = useAppStore((store) => store.updateSettings)
|
||||
const requestLinkRoutingPreference = useLinkRoutingPreferenceDialog()
|
||||
const keybindings = useAppStore((store) => store.keybindings)
|
||||
@@ -2876,6 +2876,27 @@ function TerminalPane(
|
||||
applyNativeChatLeafRoute,
|
||||
isChatEligibleForLeaf
|
||||
])
|
||||
useEffect(() => {
|
||||
const leafId =
|
||||
settings?.experimentalAgentDashboardPopout === true &&
|
||||
effectiveChatViewMode &&
|
||||
chatLeafStillMounted
|
||||
? chatLeafId
|
||||
: null
|
||||
useAppStore.getState().setRuntimeNativeChatLeafId(tabId, leafId)
|
||||
}, [
|
||||
chatLeafId,
|
||||
chatLeafStillMounted,
|
||||
effectiveChatViewMode,
|
||||
settings?.experimentalAgentDashboardPopout,
|
||||
tabId
|
||||
])
|
||||
useEffect(
|
||||
() => () => {
|
||||
useAppStore.getState().setRuntimeNativeChatLeafId(tabId, null)
|
||||
},
|
||||
[tabId]
|
||||
)
|
||||
const chatPane =
|
||||
isChatViewMode && chatLeafId
|
||||
? (managedPanes.find((pane) => pane.leafId === chatLeafId) ?? null)
|
||||
|
||||
@@ -109,6 +109,7 @@ function seedMaps(store: ReturnType<typeof createTestStore>): void {
|
||||
[TAB2]: { command: 'setup-b', direction: 'vertical' }
|
||||
},
|
||||
pendingStartupByTabId: { [TAB1]: { command: 'start-a' }, [TAB2]: { command: 'start-b' } },
|
||||
runtimeNativeChatLeafIdByTabId: { [TAB1]: 'leaf-1', [TAB2]: 'leaf-2' },
|
||||
codexRestartNoticeByPtyId: {
|
||||
[PTY1]: { previousAccountLabel: 'a1', nextAccountLabel: 'a2' },
|
||||
[PTY2]: { previousAccountLabel: 'b1', nextAccountLabel: 'b2' }
|
||||
@@ -173,6 +174,16 @@ function seedMaps(store: ReturnType<typeof createTestStore>): void {
|
||||
describe('bulk worktree purge evicts the per-tab/per-pty terminal maps it previously leaked', () => {
|
||||
beforeEach(() => vi.clearAllMocks())
|
||||
|
||||
it('drops native-chat ownership immediately when a tab closes', () => {
|
||||
const store = createTestStore()
|
||||
seedMaps(store)
|
||||
|
||||
store.getState().closeTab(TAB1, { remoteCloseOwnedByHost: true })
|
||||
|
||||
expect(store.getState().runtimeNativeChatLeafIdByTabId[TAB1]).toBeUndefined()
|
||||
expect(store.getState().runtimeNativeChatLeafIdByTabId[TAB2]).toBe('leaf-2')
|
||||
})
|
||||
|
||||
it('drops removed worktree entries (both tabId- and ptyId-keyed), retains survivors', () => {
|
||||
const store = createTestStore()
|
||||
seedMaps(store)
|
||||
@@ -188,6 +199,7 @@ describe('bulk worktree purge evicts the per-tab/per-pty terminal maps it previo
|
||||
expect(s.pendingIssueCommandSplitByTabId[TAB1]).toBeUndefined()
|
||||
expect(s.pendingSetupSplitByTabId[TAB1]).toBeUndefined()
|
||||
expect(s.pendingStartupByTabId[TAB1]).toBeUndefined()
|
||||
expect(s.runtimeNativeChatLeafIdByTabId[TAB1]).toBeUndefined()
|
||||
expect(s.codexRestartNoticeByPtyId[PTY1]).toBeUndefined()
|
||||
expect(s.migrationUnsupportedByPtyId[PTY1]).toBeUndefined()
|
||||
expect(s.suppressedPtyExitIds[PTY1]).toBeUndefined()
|
||||
@@ -208,6 +220,7 @@ describe('bulk worktree purge evicts the per-tab/per-pty terminal maps it previo
|
||||
expect(s.pendingIssueCommandSplitByTabId[TAB2]).toEqual({ command: 'b' })
|
||||
expect(s.pendingSetupSplitByTabId[TAB2]).toEqual({ command: 'setup-b', direction: 'vertical' })
|
||||
expect(s.pendingStartupByTabId[TAB2]).toEqual({ command: 'start-b' })
|
||||
expect(s.runtimeNativeChatLeafIdByTabId[TAB2]).toBe('leaf-2')
|
||||
expect(s.codexRestartNoticeByPtyId[PTY2]).toBeDefined()
|
||||
expect(s.migrationUnsupportedByPtyId[PTY2]).toBeDefined()
|
||||
expect(s.suppressedPtyExitIds[PTY2]).toBe(true)
|
||||
|
||||
@@ -81,4 +81,23 @@ describe('tab view mode', () => {
|
||||
store.getState().toggleTabViewMode('missing-tab')
|
||||
expect(store.getState().unifiedTabsByWorktree[WT]).toBe(before)
|
||||
})
|
||||
|
||||
it('tracks and clears the exact runtime chat leaf without retaining stale tabs', () => {
|
||||
store.getState().setRuntimeNativeChatLeafId('left-tab', 'leaf-chat')
|
||||
expect(store.getState().runtimeNativeChatLeafIdByTabId).toEqual({
|
||||
'left-tab': 'leaf-chat'
|
||||
})
|
||||
|
||||
store.getState().setRuntimeNativeChatLeafId('left-tab', null)
|
||||
expect(store.getState().runtimeNativeChatLeafIdByTabId).toEqual({})
|
||||
})
|
||||
|
||||
it('preserves the runtime chat map reference for repeated ownership', () => {
|
||||
store.getState().setRuntimeNativeChatLeafId('left-tab', 'leaf-chat')
|
||||
const before = store.getState().runtimeNativeChatLeafIdByTabId
|
||||
|
||||
store.getState().setRuntimeNativeChatLeafId('left-tab', 'leaf-chat')
|
||||
|
||||
expect(store.getState().runtimeNativeChatLeafIdByTabId).toBe(before)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -522,6 +522,9 @@ export type TerminalSlice = {
|
||||
ptyIdsByTabId: Record<string, string[]>
|
||||
/** Live pane titles by tabId then paneId; preserves per-pane agent status (unlike the legacy tab title) while TerminalPane is mounted. */
|
||||
runtimePaneTitlesByTabId: Record<string, Record<number, string>>
|
||||
/** Dashboard-only live ownership of the leaf currently rendered as native chat. */
|
||||
runtimeNativeChatLeafIdByTabId: Record<string, string>
|
||||
setRuntimeNativeChatLeafId: (tabId: string, leafId: string | null) => void
|
||||
/** Per-tab unread flags (BEL or agent-complete); ephemeral UI state, not persisted. Cleared when the user activates/interacts with the tab. */
|
||||
unreadTerminalTabs: Record<string, true>
|
||||
/** Pane-keyed attention marker (narrower than unreadTerminalTabs); clears when the user interacts with the exact pane that raised it. */
|
||||
@@ -1051,6 +1054,7 @@ export const createTerminalSlice: StateCreator<AppState, [], [], TerminalSlice>
|
||||
activeTabIdByWorktree: {},
|
||||
ptyIdsByTabId: {},
|
||||
runtimePaneTitlesByTabId: {},
|
||||
runtimeNativeChatLeafIdByTabId: {},
|
||||
unreadTerminalTabs: {},
|
||||
unreadTerminalPanes: {},
|
||||
unreadAgentCompletionPanes: {},
|
||||
@@ -1674,6 +1678,8 @@ export const createTerminalSlice: StateCreator<AppState, [], [], TerminalSlice>
|
||||
delete nextPendingReconnectPtyIdByTabId[tabId]
|
||||
const nextRuntimePaneTitlesByTabId = { ...s.runtimePaneTitlesByTabId }
|
||||
delete nextRuntimePaneTitlesByTabId[tabId]
|
||||
const nextRuntimeNativeChatLeafIdByTabId = { ...s.runtimeNativeChatLeafIdByTabId }
|
||||
delete nextRuntimeNativeChatLeafIdByTabId[tabId]
|
||||
const nextDirectSshPaneRetryByTabId = { ...s.directSshPaneRetryByTabId }
|
||||
delete nextDirectSshPaneRetryByTabId[tabId]
|
||||
const nextDirectSshLivePtyBindingByTabId = {
|
||||
@@ -1786,6 +1792,7 @@ export const createTerminalSlice: StateCreator<AppState, [], [], TerminalSlice>
|
||||
deferredSshSessionIdsByTabId: nextDeferredSshSessionIdsByTabId,
|
||||
pendingReconnectPtyIdByTabId: nextPendingReconnectPtyIdByTabId,
|
||||
runtimePaneTitlesByTabId: nextRuntimePaneTitlesByTabId,
|
||||
runtimeNativeChatLeafIdByTabId: nextRuntimeNativeChatLeafIdByTabId,
|
||||
directSshPaneRetryByTabId: nextDirectSshPaneRetryByTabId,
|
||||
directSshLivePtyBindingByTabId: nextDirectSshLivePtyBindingByTabId,
|
||||
directSshPaneRetryHistoryByTabId: nextDirectSshPaneRetryHistoryByTabId,
|
||||
@@ -3614,6 +3621,29 @@ export const createTerminalSlice: StateCreator<AppState, [], [], TerminalSlice>
|
||||
transferNormalizedTerminalLayoutPtyOwnership(get(), tabId, ownershipTransfers)
|
||||
},
|
||||
|
||||
setRuntimeNativeChatLeafId: (tabId, leafId) => {
|
||||
set((s) => {
|
||||
const current = s.runtimeNativeChatLeafIdByTabId[tabId]
|
||||
if (leafId === null) {
|
||||
if (current === undefined) {
|
||||
return s
|
||||
}
|
||||
const next = { ...s.runtimeNativeChatLeafIdByTabId }
|
||||
delete next[tabId]
|
||||
return { runtimeNativeChatLeafIdByTabId: next }
|
||||
}
|
||||
if (current === leafId) {
|
||||
return s
|
||||
}
|
||||
return {
|
||||
runtimeNativeChatLeafIdByTabId: {
|
||||
...s.runtimeNativeChatLeafIdByTabId,
|
||||
[tabId]: leafId
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
syncPaneDetachPtyOwnership: ({
|
||||
detachedLeafId,
|
||||
detachedPtyId,
|
||||
|
||||
@@ -2582,6 +2582,7 @@ function buildWorktreePurgeState(s: AppState, worktreeIds: string[]): Partial<Ap
|
||||
terminalLayoutsByTabId: omitByTabId(s.terminalLayoutsByTabId),
|
||||
ptyIdsByTabId: omitByTabId(s.ptyIdsByTabId),
|
||||
runtimePaneTitlesByTabId: omitByTabId(s.runtimePaneTitlesByTabId),
|
||||
runtimeNativeChatLeafIdByTabId: omitByTabId(s.runtimeNativeChatLeafIdByTabId),
|
||||
automaticAgentResumeClaimsByTabId: omitByTabId(s.automaticAgentResumeClaimsByTabId),
|
||||
nativeChatLaunchPromptByTabId: omitByTabId(s.nativeChatLaunchPromptByTabId),
|
||||
nativeChatLaunchDraftByTabId: omitByTabId(s.nativeChatLaunchDraftByTabId),
|
||||
|
||||
Reference in New Issue
Block a user