mirror of
https://github.com/stablyai/orca.git
synced 2026-10-17 16:02:55 +00:00
fix(terminal): exclude passive mobile query responders
This commit is contained in:
@@ -104,11 +104,11 @@ arrived while the initial snapshot was being built and its output sequence is
|
||||
covered by that snapshot, runtime RPC re-emits only the bounded query sequence
|
||||
after the snapshot; ordinary covered output stays deduplicated. `terminal.send`
|
||||
accepts the resulting `inputKind: query-reply` only from the earliest active
|
||||
mobile subscriber while mobile owns the terminal driver. Earliest is determined
|
||||
by preserved `subscribedAt`, so a soft-leave resubscribe does not change reply
|
||||
ownership. Peer phones are rejected, the next subscriber is promoted on
|
||||
unsubscribe, and desktop parser and capability handlers stay silent until
|
||||
desktop retakes the driver.
|
||||
phone-fitted mobile subscriber while mobile owns the terminal driver. Earliest
|
||||
is determined by preserved `subscribedAt`, so a soft-leave resubscribe does not
|
||||
change reply ownership; passive desktop-mode watchers are excluded. Peer phones
|
||||
are rejected, the next subscriber is promoted on unsubscribe, and desktop
|
||||
parser and capability handlers stay silent until desktop retakes the driver.
|
||||
|
||||
Everything the emulator emits outside a forwarding window is discarded, which
|
||||
also swallows unsolicited core emissions (e.g. native 997 color-scheme pushes
|
||||
|
||||
@@ -271,6 +271,22 @@ describe('mobile presence lock — multi-mobile semantics', () => {
|
||||
expect(runtime.isMobileTerminalQueryReplyAuthority('pty-1', 'phone-B')).toBe(false)
|
||||
})
|
||||
|
||||
it('excludes an older passive desktop-mode subscriber from reply authority', async () => {
|
||||
const { runtime } = createRuntime()
|
||||
runtime.setMobileDisplayMode('pty-1', 'desktop')
|
||||
await runtime.handleMobileSubscribe('pty-1', 'phone-A', { cols: 45, rows: 20 })
|
||||
await vi.advanceTimersByTimeAsync(10)
|
||||
await runtime.handleMobileSubscribe('pty-1', 'phone-B', { cols: 38, rows: 18 })
|
||||
|
||||
await vi.advanceTimersByTimeAsync(10)
|
||||
runtime.markMobileActor('pty-1', 'phone-B')
|
||||
runtime.setMobileDisplayMode('pty-1', 'auto')
|
||||
await runtime.applyMobileDisplayMode('pty-1')
|
||||
|
||||
expect(runtime.isMobileTerminalQueryReplyAuthority('pty-1', 'phone-A')).toBe(false)
|
||||
expect(runtime.isMobileTerminalQueryReplyAuthority('pty-1', 'phone-B')).toBe(true)
|
||||
})
|
||||
|
||||
it('most-recent actor wins active phone-fit dims (B subscribes after A)', async () => {
|
||||
const { runtime, ptySizes } = createRuntime()
|
||||
await runtime.handleMobileSubscribe('pty-1', 'phone-A', { cols: 45, rows: 20 })
|
||||
|
||||
@@ -6487,9 +6487,13 @@ export class OrcaRuntimeService {
|
||||
return false
|
||||
}
|
||||
// Why: soft-leave resubscribe preserves the original subscription time but
|
||||
// reinserts the record. Elect from that stable age, not mutable Map order.
|
||||
// reinserts the record. Elect fitted responders from that stable age, not
|
||||
// mutable Map order or passive desktop-mode watchers.
|
||||
let earliest: { clientId: string; subscribedAt: number } | null = null
|
||||
for (const subscriber of subscribers.values()) {
|
||||
if (!subscriber.wasResizedToPhone) {
|
||||
continue
|
||||
}
|
||||
if (earliest === null || subscriber.subscribedAt < earliest.subscribedAt) {
|
||||
earliest = subscriber
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user