mirror of
https://github.com/stablyai/orca.git
synced 2026-10-23 08:03:39 +00:00
fix structured completion focus scope
This commit is contained in:
@@ -121,6 +121,7 @@ export type IpcEventsHarness = {
|
||||
useIpcEvents: () => void
|
||||
createTerminal: (request: CreateTerminalRequest) => void
|
||||
requestTerminalCreate: (request: RequestTerminalCreateRequest) => void
|
||||
focusEditorTab: (request: { tabId: string; worktreeId: string }) => void
|
||||
replyTerminalCreate: ReturnType<typeof vi.fn>
|
||||
/** Fire a main-process digit chord (zero-based index). */
|
||||
jumpToWorktreeIndex: (index: number) => void
|
||||
@@ -136,8 +137,7 @@ export type IpcEventsHarnessOptions = {
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads useIpcEvents against a stubbed preload API and returns a driver for the
|
||||
* create-terminal IPC, so reveal/adoption behavior is asserted through the hook.
|
||||
* Loads useIpcEvents against a stubbed preload API so IPC behavior is asserted through the hook.
|
||||
*/
|
||||
export async function loadIpcEventsHarness(
|
||||
storeState: HarnessStoreState,
|
||||
@@ -147,6 +147,8 @@ export async function loadIpcEventsHarness(
|
||||
const activateAndRevealWorkspace = vi.fn()
|
||||
let createTerminalListener: ((request: CreateTerminalRequest) => void) | null = null
|
||||
let requestTerminalCreateListener: ((request: RequestTerminalCreateRequest) => void) | null = null
|
||||
let focusEditorTabListener: ((request: { tabId: string; worktreeId: string }) => void) | null =
|
||||
null
|
||||
let navigationUpdateListener:
|
||||
| ((event: { browserPageId: string; url: string; title: string }) => void)
|
||||
| null = null
|
||||
@@ -209,6 +211,12 @@ export async function loadIpcEventsHarness(
|
||||
requestTerminalCreateListener = listener
|
||||
return () => {}
|
||||
},
|
||||
onFocusEditorTab: (
|
||||
listener: (request: { tabId: string; worktreeId: string }) => void
|
||||
) => {
|
||||
focusEditorTabListener = listener
|
||||
return () => {}
|
||||
},
|
||||
onJumpToWorktreeIndex: (listener: (index: number) => void) => {
|
||||
indexJumpListeners.set('worktree', listener)
|
||||
return () => {}
|
||||
@@ -279,6 +287,12 @@ export async function loadIpcEventsHarness(
|
||||
}
|
||||
requestTerminalCreateListener(request)
|
||||
},
|
||||
focusEditorTab: (request) => {
|
||||
if (typeof focusEditorTabListener !== 'function') {
|
||||
throw new Error('Expected the focus-editor-tab listener to be registered')
|
||||
}
|
||||
focusEditorTabListener(request)
|
||||
},
|
||||
replyTerminalCreate,
|
||||
jumpToWorktreeIndex: (index) => fireIndexJump(indexJumpListeners, 'worktree', index),
|
||||
jumpToTabIndex: (index) => fireIndexJump(indexJumpListeners, 'tab', index),
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import {
|
||||
createHarnessStoreState,
|
||||
loadIpcEventsHarness,
|
||||
type HarnessStoreState
|
||||
} from './ipc-events-test-harness'
|
||||
|
||||
const SESSION_WORKSPACE_ID = 'repo-1::/session-workspace'
|
||||
const OTHER_WORKSPACE_ID = 'repo-1::/other-workspace'
|
||||
const TAB_ID = 'structured-agent-session-session-1'
|
||||
|
||||
function createStoreState(activeWorktreeId: string): HarnessStoreState {
|
||||
return createHarnessStoreState({
|
||||
tabsByWorktree: {},
|
||||
activeWorktreeId,
|
||||
unifiedTabsByWorktree: {
|
||||
[SESSION_WORKSPACE_ID]: [
|
||||
{
|
||||
id: TAB_ID,
|
||||
entityId: 'session-1',
|
||||
groupId: 'group-1',
|
||||
worktreeId: SESSION_WORKSPACE_ID,
|
||||
contentType: 'agent-session'
|
||||
}
|
||||
]
|
||||
},
|
||||
focusGroup: vi.fn(),
|
||||
activateTab: vi.fn()
|
||||
})
|
||||
}
|
||||
|
||||
describe('structured session completion focus', () => {
|
||||
it('focuses the chat tab when its workspace is active', async () => {
|
||||
const store = createStoreState(SESSION_WORKSPACE_ID)
|
||||
const harness = await loadIpcEventsHarness(store)
|
||||
harness.useIpcEvents()
|
||||
|
||||
harness.focusEditorTab({ tabId: TAB_ID, worktreeId: SESSION_WORKSPACE_ID })
|
||||
|
||||
expect(store.focusGroup).toHaveBeenCalledWith(SESSION_WORKSPACE_ID, 'group-1')
|
||||
expect(store.activateTab).toHaveBeenCalledWith(TAB_ID)
|
||||
expect(store.setActiveTabType).toHaveBeenCalledWith('agent-session')
|
||||
})
|
||||
|
||||
it('does not apply focus after the user moves to another workspace', async () => {
|
||||
const store = createStoreState(OTHER_WORKSPACE_ID)
|
||||
const harness = await loadIpcEventsHarness(store)
|
||||
harness.useIpcEvents()
|
||||
|
||||
harness.focusEditorTab({ tabId: TAB_ID, worktreeId: SESSION_WORKSPACE_ID })
|
||||
|
||||
expect(store.setActiveWorktree).not.toHaveBeenCalled()
|
||||
expect(store.markWorktreeVisited).not.toHaveBeenCalled()
|
||||
expect(store.setActiveView).not.toHaveBeenCalled()
|
||||
expect(store.focusGroup).not.toHaveBeenCalled()
|
||||
expect(store.activateTab).not.toHaveBeenCalled()
|
||||
expect(store.setActiveTabType).not.toHaveBeenCalled()
|
||||
expect(store.revealWorktreeInSidebar).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
@@ -1867,6 +1867,9 @@ export function useIpcEvents(): void {
|
||||
(item) => item.id === tabId
|
||||
)
|
||||
const browserTarget = resolveBrowserSessionTabTarget(store, worktreeId, tabId)
|
||||
if (tab?.contentType === 'agent-session' && store.activeWorktreeId !== worktreeId) {
|
||||
return
|
||||
}
|
||||
if (!tab) {
|
||||
if (browserTarget) {
|
||||
// Why: older/mobile fallback snapshots identify browser tabs by workspace id when no unified tab wrapper exists.
|
||||
|
||||
Reference in New Issue
Block a user