mirror of
https://github.com/stablyai/orca.git
synced 2026-10-17 08:03:14 +00:00
fix(terminal): scope mode 2031 retries to subscription
This commit is contained in:
@@ -17,6 +17,7 @@ describe('pushMode2031SeedReply', () => {
|
||||
const sendInputImmediate = vi.fn<(data: string) => boolean>(() => true)
|
||||
const scheduled: (() => void)[] = []
|
||||
const recordMode = vi.fn()
|
||||
const currentAttempt = { current: Symbol() }
|
||||
const transport = {
|
||||
isConnected: () => connectedState.current,
|
||||
sendInput,
|
||||
@@ -29,15 +30,19 @@ describe('pushMode2031SeedReply', () => {
|
||||
sendInputImmediate,
|
||||
scheduled,
|
||||
recordMode,
|
||||
push: () =>
|
||||
push: () => {
|
||||
const attempt = Symbol()
|
||||
currentAttempt.current = attempt
|
||||
pushMode2031SeedReply(1, {
|
||||
hasPane: () => true,
|
||||
isSubscribed: () => subscribed.current,
|
||||
isCurrentAttempt: () => currentAttempt.current === attempt,
|
||||
getTransport: () => transport,
|
||||
getMode: () => 'dark',
|
||||
recordMode,
|
||||
schedule: (callback) => scheduled.push(callback)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,4 +70,21 @@ describe('pushMode2031SeedReply', () => {
|
||||
expect(harness.sendInput).not.toHaveBeenCalled()
|
||||
expect(harness.scheduled).toHaveLength(0)
|
||||
})
|
||||
|
||||
it('does not let an old retry answer a later subscription', () => {
|
||||
const harness = createHarness(false)
|
||||
|
||||
harness.push()
|
||||
harness.subscribed.current = false
|
||||
harness.subscribed.current = true
|
||||
harness.push()
|
||||
expect(harness.scheduled).toHaveLength(2)
|
||||
|
||||
harness.connected.current = true
|
||||
harness.scheduled.shift()?.()
|
||||
harness.scheduled.shift()?.()
|
||||
|
||||
expect(harness.sendInputImmediate).toHaveBeenCalledTimes(1)
|
||||
expect(harness.recordMode).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -10,6 +10,7 @@ type Mode2031ReplyTransport = Pick<PtyTransport, 'isConnected' | 'sendInputImmed
|
||||
type Mode2031SeedReplyDeps = {
|
||||
hasPane: (paneId: number) => boolean
|
||||
isSubscribed: (paneId: number) => boolean
|
||||
isCurrentAttempt: (paneId: number) => boolean
|
||||
getTransport: (paneId: number) => Mode2031ReplyTransport | undefined
|
||||
getMode: () => TerminalColorSchemeMode | null
|
||||
recordMode: (paneId: number, mode: TerminalColorSchemeMode) => void
|
||||
@@ -30,7 +31,7 @@ export function pushMode2031SeedReply(paneId: number, deps: Mode2031SeedReplyDep
|
||||
const send = (): void => {
|
||||
// Why: a TUI can unsubscribe while the PTY is connecting; every delayed
|
||||
// attempt must revalidate intent or its color reply can land at a shell prompt.
|
||||
if (!deps.hasPane(paneId) || !deps.isSubscribed(paneId)) {
|
||||
if (!deps.hasPane(paneId) || !deps.isSubscribed(paneId) || !deps.isCurrentAttempt(paneId)) {
|
||||
return
|
||||
}
|
||||
const transport = deps.getTransport(paneId)
|
||||
|
||||
@@ -575,6 +575,7 @@ export function useTerminalPaneLifecycle({
|
||||
const selectionDisposablesRef = useRef(new Map<number, IDisposable>())
|
||||
const selectionCaptureTimersRef = useRef(new Map<number, number>())
|
||||
const mode2031DisposablesRef = useRef(new Map<number, IDisposable[]>())
|
||||
const mode2031SeedAttemptTokensRef = useRef(new Map<number, symbol>())
|
||||
const osc52DisposablesRef = useRef(new Map<number, IDisposable>())
|
||||
const osc7DisposablesRef = useRef(new Map<number, IDisposable>())
|
||||
const mouseHideDisposablesRef = useRef(new Map<number, IDisposable>())
|
||||
@@ -601,10 +602,15 @@ export function useTerminalPaneLifecycle({
|
||||
}
|
||||
|
||||
const pushMode2031ForPane = (paneId: number): void => {
|
||||
const attemptToken = Symbol()
|
||||
mode2031SeedAttemptTokensRef.current.set(paneId, attemptToken)
|
||||
pushMode2031SeedReply(paneId, {
|
||||
hasPane: (candidateId) =>
|
||||
managerRef.current?.getPanes().some((pane) => pane.id === candidateId) === true,
|
||||
isSubscribed: (candidateId) => paneMode2031Ref.current.get(candidateId) === true,
|
||||
// Why: an older connect retry must not answer a later resubscription.
|
||||
isCurrentAttempt: (candidateId) =>
|
||||
mode2031SeedAttemptTokensRef.current.get(candidateId) === attemptToken,
|
||||
getTransport: (candidateId) => paneTransportsRef.current.get(candidateId),
|
||||
getMode: () => {
|
||||
const currentSettings = settingsRef.current
|
||||
@@ -1222,6 +1228,7 @@ export function useTerminalPaneLifecycle({
|
||||
mode2031DisposablesRef.current.delete(paneId)
|
||||
}
|
||||
paneMode2031Ref.current.delete(paneId)
|
||||
mode2031SeedAttemptTokensRef.current.delete(paneId)
|
||||
paneKittyKeyboardModesRef.current.delete(paneId)
|
||||
paneLastThemeModeRef.current.delete(paneId)
|
||||
const osc52Disposable = osc52DisposablesRef.current.get(paneId)
|
||||
|
||||
Reference in New Issue
Block a user