fix(editor): record mirrored-close intent synchronously to close the ghost-tab window

Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
Neil
2026-07-21 00:20:27 -07:00
co-authored by Orca
parent 7376a9f00c
commit 9f89548b15
2 changed files with 21 additions and 0 deletions
@@ -16,6 +16,11 @@ import {
notifyHostOfMirroredEditorClose,
type MirroredEditorCloseState
} from './close-mirrored-editor-tab'
import {
isWebSessionCloseIntentPending,
resetWebSessionCloseIntentForTests
} from './web-session-close-intent'
import { toHostSessionTabId } from '../../../shared/terminal-surface-id'
function buildState(overrides: Partial<MirroredEditorCloseState> = {}): MirroredEditorCloseState {
return {
@@ -32,6 +37,16 @@ describe('notifyHostOfMirroredEditorClose', () => {
closeWebRuntimeSessionTabMock.mockReset()
getRuntimeEnvironmentIdForWorktreeMock.mockReset()
getRuntimeEnvironmentIdForWorktreeMock.mockReturnValue('env-1')
resetWebSessionCloseIntentForTests()
})
it('records the host close intent SYNCHRONOUSLY (before the async close resolves)', () => {
const now = Date.now()
// No await: the intent must be pending the instant the call returns, so a
// host snapshot in the dynamic-import gap can't flash the old-path tab back.
notifyHostOfMirroredEditorClose(buildState(), 'wt-1', 'file-1')
expect(isWebSessionCloseIntentPending('wt-1', toHostSessionTabId('host-tab-1'), now)).toBe(true)
})
it('closes the mirrored editor tab on the host using the host tab id', async () => {
@@ -2,6 +2,8 @@ import {
getRuntimeEnvironmentIdForWorktree,
type WorktreeRuntimeOwnerState
} from '@/lib/worktree-runtime-owner'
import { recordWebSessionCloseIntent } from './web-session-close-intent'
import { toHostSessionTabId } from '../../../shared/terminal-surface-id'
import type { OpenFile } from '@/store/slices/editor'
import type { Tab } from '../../../shared/types'
@@ -40,6 +42,10 @@ export function notifyHostOfMirroredEditorClose(
if (!unifiedTab) {
return false
}
// Record the close intent SYNCHRONOUSLY (leaf modules, no cycle) so a host
// snapshot landing before the dynamic import below resolves can't flash the
// old-path tab back. closeWebRuntimeSessionTab re-records it idempotently.
recordWebSessionCloseIntent(worktreeId, toHostSessionTabId(unifiedTab.id), Date.now())
// Why: this helper is imported by the editor slice during store creation.
// Importing web-runtime-session eagerly would import the store back and can
// trip cyclic initialization in full-suite test/import order.