mirror of
https://github.com/stablyai/orca.git
synced 2026-10-22 08:03:37 +00:00
fix(terminal): report restored remote replay grid
This commit is contained in:
@@ -17256,13 +17256,20 @@ describe('connectPanePty', () => {
|
||||
disposable.dispose()
|
||||
})
|
||||
|
||||
it('paints remote replay at its snapshot grid before returning to the live pane grid', async () => {
|
||||
it('paints remote replay at its snapshot grid and reports the live grid from a measurable hidden pane', async () => {
|
||||
const { connectPanePty } = await import('./pty-connection')
|
||||
enableActiveRuntimeEnvironment()
|
||||
const transport = createMockTransport('remote:env-1@@terminal-grid')
|
||||
const capturedReplayCallback: {
|
||||
current:
|
||||
| ((data: string, meta?: { snapshotCols?: number; snapshotRows?: number }) => void)
|
||||
| ((
|
||||
data: string,
|
||||
meta?: {
|
||||
snapshotCols?: number
|
||||
snapshotRows?: number
|
||||
pendingEscapeTailAnsi?: string
|
||||
}
|
||||
) => void)
|
||||
| null
|
||||
} = { current: null }
|
||||
transport.connect.mockImplementation(async ({ callbacks }: { callbacks: ConnectCallbacks }) => {
|
||||
@@ -17285,9 +17292,10 @@ describe('connectPanePty', () => {
|
||||
callback?.()
|
||||
}) as typeof pane.terminal.write
|
||||
const manager = createManager(1)
|
||||
const deps = createDeps()
|
||||
const deps = createDeps({ isVisibleRef: { current: false } })
|
||||
const disposable = connectPanePty(pane as never, manager as never, deps as never)
|
||||
await flushAsyncTicks(6)
|
||||
transport.resize.mockClear()
|
||||
|
||||
capturedReplayCallback.current?.('snapshot payload', {
|
||||
snapshotCols: 60,
|
||||
@@ -17304,6 +17312,40 @@ describe('connectPanePty', () => {
|
||||
)
|
||||
expect(pane.terminal.cols).toBe(180)
|
||||
expect(pane.terminal.rows).toBe(50)
|
||||
expect(transport.resize).toHaveBeenCalledWith(180, 50)
|
||||
|
||||
vi.mocked(pane.terminal.resize).mockClear()
|
||||
capturedReplayCallback.current?.('unknown-size payload', {
|
||||
snapshotCols: 0,
|
||||
snapshotRows: 0
|
||||
})
|
||||
await flushAsyncTicks(12)
|
||||
expect(pane.terminal.resize).not.toHaveBeenCalledWith(0, 0)
|
||||
|
||||
vi.mocked(pane.terminal.resize).mockClear()
|
||||
capturedReplayCallback.current?.('', {
|
||||
snapshotCols: 30,
|
||||
snapshotRows: 10,
|
||||
pendingEscapeTailAnsi: '\x1b[3'
|
||||
})
|
||||
await flushAsyncTicks(12)
|
||||
expect(pane.terminal.resize).not.toHaveBeenCalledWith(30, 10)
|
||||
|
||||
const { setDriverForPty } = await import('@/lib/pane-manager/mobile-driver-state')
|
||||
setDriverForPty('remote:env-1@@terminal-grid', { kind: 'mobile', clientId: 'phone-1' })
|
||||
transport.resize.mockClear()
|
||||
try {
|
||||
capturedReplayCallback.current?.('mobile-owned payload', {
|
||||
snapshotCols: 60,
|
||||
snapshotRows: 20
|
||||
})
|
||||
await flushAsyncTicks(12)
|
||||
expect(pane.terminal.cols).toBe(180)
|
||||
expect(pane.terminal.rows).toBe(50)
|
||||
expect(transport.resize).not.toHaveBeenCalled()
|
||||
} finally {
|
||||
setDriverForPty('remote:env-1@@terminal-grid', { kind: 'idle' })
|
||||
}
|
||||
disposable.dispose()
|
||||
})
|
||||
|
||||
@@ -25807,6 +25849,7 @@ describe('connectPanePty', () => {
|
||||
|
||||
expect(getSize).not.toHaveBeenCalled()
|
||||
expect(pane.fitAddon.proposeDimensions).toHaveBeenCalled()
|
||||
expect(pane.fitAddon.fit).not.toHaveBeenCalled()
|
||||
expect(transport.resize).toHaveBeenCalledWith(120, 40)
|
||||
})
|
||||
|
||||
|
||||
@@ -4350,8 +4350,29 @@ export function connectPanePty(
|
||||
}
|
||||
}
|
||||
}
|
||||
const reportRemoteViewportAfterFit = (
|
||||
ptyId: string | null,
|
||||
expectedStreamGeneration: number
|
||||
): void => {
|
||||
if (
|
||||
!ptyId ||
|
||||
!isRemoteRuntimePtyId(ptyId) ||
|
||||
disposed ||
|
||||
transport.getPtyId() !== ptyId ||
|
||||
transportStreamGeneration !== expectedStreamGeneration ||
|
||||
shouldSuppressDesktopPtyResize()
|
||||
) {
|
||||
return
|
||||
}
|
||||
const cols = pane.terminal.cols
|
||||
const rows = pane.terminal.rows
|
||||
if (Number.isFinite(cols) && Number.isFinite(rows) && cols > 0 && rows > 0) {
|
||||
transport.resize(cols, rows)
|
||||
}
|
||||
}
|
||||
const reportRemoteViewportOnReveal = (): void => {
|
||||
const revealedPtyId = transport.getPtyId()
|
||||
const revealedStreamGeneration = transportStreamGeneration
|
||||
if (
|
||||
!revealedPtyId ||
|
||||
!isRemoteRuntimePtyId(revealedPtyId) ||
|
||||
@@ -4362,14 +4383,7 @@ export function connectPanePty(
|
||||
return
|
||||
}
|
||||
safeFitAndThen(pane, 'remote-reveal-viewport', () => {
|
||||
if (disposed || transport.getPtyId() !== revealedPtyId || shouldSuppressDesktopPtyResize()) {
|
||||
return
|
||||
}
|
||||
const cols = pane.terminal.cols
|
||||
const rows = pane.terminal.rows
|
||||
if (Number.isFinite(cols) && Number.isFinite(rows) && cols > 0 && rows > 0) {
|
||||
transport.resize(cols, rows)
|
||||
}
|
||||
reportRemoteViewportAfterFit(revealedPtyId, revealedStreamGeneration)
|
||||
})
|
||||
}
|
||||
let pendingForegroundGridDriftCheckRaf: number | null = null
|
||||
@@ -5649,7 +5663,8 @@ export function connectPanePty(
|
||||
let replayDrainQueued = false
|
||||
const drainReplayDataQueue = async (
|
||||
expectedPtyId: string | null,
|
||||
expectedStreamGeneration: number
|
||||
expectedStreamGeneration: number,
|
||||
noteSnapshotGridReplay: () => void
|
||||
): Promise<boolean> => {
|
||||
let appliedCurrentPayload = false
|
||||
while (pendingReplayData !== null) {
|
||||
@@ -5692,9 +5707,11 @@ export function connectPanePty(
|
||||
)
|
||||
if (
|
||||
snapshotDimensions &&
|
||||
data.length > 0 &&
|
||||
(pane.terminal.cols !== snapshotDimensions.cols ||
|
||||
pane.terminal.rows !== snapshotDimensions.rows)
|
||||
) {
|
||||
noteSnapshotGridReplay()
|
||||
suppressStructuralReplayPtyResize = true
|
||||
try {
|
||||
pane.terminal.resize(snapshotDimensions.cols, snapshotDimensions.rows)
|
||||
@@ -5760,6 +5777,7 @@ export function connectPanePty(
|
||||
pendingReplayData?.streamGeneration ?? transportStreamGeneration
|
||||
beginReattachLiveDataDeferral(scheduledStreamGeneration)
|
||||
let replayCompleted = false
|
||||
let replayUsedSnapshotGrid = false
|
||||
replayWriteQueue = replayWriteQueue
|
||||
.catch(() => undefined)
|
||||
.then(() =>
|
||||
@@ -5767,7 +5785,10 @@ export function connectPanePty(
|
||||
async () => {
|
||||
replayCompleted = await drainReplayDataQueue(
|
||||
scheduledPtyId,
|
||||
scheduledStreamGeneration
|
||||
scheduledStreamGeneration,
|
||||
() => {
|
||||
replayUsedSnapshotGrid = true
|
||||
}
|
||||
)
|
||||
},
|
||||
{
|
||||
@@ -5776,8 +5797,9 @@ export function connectPanePty(
|
||||
transport.getPtyId() === scheduledPtyId &&
|
||||
transportStreamGeneration === scheduledStreamGeneration,
|
||||
afterRestore: () => {
|
||||
if (replayCompleted) {
|
||||
safeFit(pane)
|
||||
if (replayCompleted && replayUsedSnapshotGrid && safeFit(pane)) {
|
||||
// Why: a measurable hidden pane is authoritative; only presence ownership gates this report (#12768).
|
||||
reportRemoteViewportAfterFit(scheduledPtyId, scheduledStreamGeneration)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user