mirror of
https://github.com/stablyai/orca.git
synced 2026-10-23 08:03:39 +00:00
fix: preserve owner-unverified terminal bindings
This commit is contained in:
@@ -484,6 +484,50 @@ describe('connectPanePty', () => {
|
||||
expect(mockStoreState.deferredSshSessionIdsByTabId['tab-1']).toBe(restoredPtyId)
|
||||
}
|
||||
)
|
||||
it('preserves a restored pane binding when its daemon owner is unverifiable', async () => {
|
||||
const { connectPanePty } = await import('./pty-connection')
|
||||
const transport = createMockTransport()
|
||||
transport.connect.mockImplementation(
|
||||
async (opts: { sessionId?: string; callbacks?: ConnectCallbacks }) => {
|
||||
opts.callbacks?.onError?.('terminal_pane_owner_unverified')
|
||||
return undefined
|
||||
}
|
||||
)
|
||||
transportFactoryQueue.push(transport)
|
||||
mockStoreState = {
|
||||
...mockStoreState,
|
||||
tabsByWorktree: { 'wt-1': [{ id: 'tab-1', ptyId: 'unverifiable-pty' }] },
|
||||
ptyIdsByTabId: { 'tab-1': ['unverifiable-pty'] },
|
||||
terminalLayoutsByTabId: {
|
||||
'tab-1': {
|
||||
root: { type: 'leaf', leafId: LEAF_2 },
|
||||
activeLeafId: LEAF_2,
|
||||
expandedLeafId: null,
|
||||
ptyIdsByLeafId: { [LEAF_2]: 'unverifiable-pty' }
|
||||
}
|
||||
}
|
||||
} as StoreState
|
||||
const deps = createDeps({
|
||||
restoredLeafId: LEAF_2,
|
||||
restoredPtyIdByLeafId: { [LEAF_2]: 'unverifiable-pty' }
|
||||
})
|
||||
|
||||
connectPanePty(createPane(2) as never, createManager(2) as never, deps as never)
|
||||
await flushAsyncTicks()
|
||||
|
||||
expect(transport.connect).toHaveBeenCalledTimes(1)
|
||||
expect(transport.connect).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ sessionId: 'unverifiable-pty' })
|
||||
)
|
||||
expect(deps.clearExitedPanePtyLayoutBinding).not.toHaveBeenCalled()
|
||||
expect(deps.clearTabPtyId).not.toHaveBeenCalled()
|
||||
expect(deps.syncPanePtyLayoutBinding).not.toHaveBeenCalled()
|
||||
expect(mockStoreState.tabsByWorktree['wt-1'][0]?.ptyId).toBe('unverifiable-pty')
|
||||
expect(mockStoreState.ptyIdsByTabId?.['tab-1']).toEqual(['unverifiable-pty'])
|
||||
expect(mockStoreState.terminalLayoutsByTabId?.['tab-1']?.ptyIdsByLeafId).toEqual({
|
||||
[LEAF_2]: 'unverifiable-pty'
|
||||
})
|
||||
})
|
||||
|
||||
it('reattaches via the tab-level SSH pty id when deferred bookkeeping missed the tab', async () => {
|
||||
// Why: restore can miss the deferred maps; the tab's SSH pty id must still drive connect-then-reattach, not a fresh spawn into a missing provider.
|
||||
|
||||
+18
@@ -6,6 +6,8 @@ import { toProcessExitStartup } from './process-exit-startup'
|
||||
import { recoverUnverifiableDirectSshReattach } from './direct-ssh-reattach-recovery'
|
||||
import type { ConnectPanePtySession } from './connect-pane-pty-session'
|
||||
|
||||
const PANE_OWNER_UNVERIFIED_ERROR = 'terminal_pane_owner_unverified'
|
||||
|
||||
export function startDeferredSessionReattach(
|
||||
session: ConnectPanePtySession,
|
||||
deferredReattachSessionId: string
|
||||
@@ -22,6 +24,7 @@ export function startDeferredSessionReattach(
|
||||
: window.api.pty.declarePendingPaneSerializer(session.cacheKey).catch(() => null)
|
||||
|
||||
let expiredReattachError = false
|
||||
let paneOwnerUnverified = false
|
||||
const coldRestoreStartup = session.buildColdRestoreAgentResumeStartup()
|
||||
const outputCallbacks = session.captureTransportOutputCallbacks(
|
||||
(message) => {
|
||||
@@ -29,6 +32,9 @@ export function startDeferredSessionReattach(
|
||||
expiredReattachError = true
|
||||
return
|
||||
}
|
||||
if (message.includes(PANE_OWNER_UNVERIFIED_ERROR)) {
|
||||
paneOwnerUnverified = true
|
||||
}
|
||||
if (!session.isCapturedDirectSshReattachCurrent(deferredReattachSessionId)) {
|
||||
return
|
||||
}
|
||||
@@ -75,6 +81,14 @@ export function startDeferredSessionReattach(
|
||||
}
|
||||
return
|
||||
}
|
||||
if (!result && paneOwnerUnverified) {
|
||||
session.finishReattachLiveDataDeferral(false, outputCallbacks.generation)
|
||||
const gen = await preSignalPromise
|
||||
if (typeof gen === 'number') {
|
||||
void window.api.pty.clearPendingPaneSerializer(session.cacheKey, gen).catch(() => {})
|
||||
}
|
||||
return
|
||||
}
|
||||
if (!result && expiredReattachError) {
|
||||
session.finishReattachLiveDataDeferral(false, outputCallbacks.generation)
|
||||
const gen = await preSignalPromise
|
||||
@@ -133,6 +147,10 @@ export function startDeferredSessionReattach(
|
||||
if (session.rejectObsoleteDirectSshReattach(deferredReattachSessionId)) {
|
||||
return
|
||||
}
|
||||
if (message.includes(PANE_OWNER_UNVERIFIED_ERROR)) {
|
||||
session.reportError(message)
|
||||
return
|
||||
}
|
||||
warnTerminalLifecycleAnomaly('restored PTY reattach threw', {
|
||||
tabId: session.deps.tabId,
|
||||
worktreeId: session.deps.worktreeId,
|
||||
|
||||
Reference in New Issue
Block a user