From 79aaddd5665e3b1e4ba11a4b60a6338a7da62efe Mon Sep 17 00:00:00 2001 From: Jinwoo-H Date: Wed, 12 Aug 2026 21:47:58 -0400 Subject: [PATCH] test(terminal): reproduce Fish readiness ESC loss --- src/main/daemon/session.test.ts | 24 +++++++++++++++++++ src/main/providers/local-pty-provider.test.ts | 17 +++++++++++++ 2 files changed, 41 insertions(+) diff --git a/src/main/daemon/session.test.ts b/src/main/daemon/session.test.ts index bc90bf5d97f..5769858f2cf 100644 --- a/src/main/daemon/session.test.ts +++ b/src/main/daemon/session.test.ts @@ -1,5 +1,6 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import { SESSION_FORCE_KILL_RETRY_MS, Session } from './session' +import { HeadlessEmulator } from './headless-emulator' import type { SessionState, ShellReadyState } from './types' import type { TuiAgent } from '../../shared/types' @@ -430,6 +431,29 @@ describe('Session', () => { expect(session.getSnapshot()?.snapshotAnsi).not.toContain('orca-shell-ready') }) + it.each([ + ['after the ready marker', ['\x1b]777;orca-shell-ready\x07', '\x1b[?2004hfish> ']], + ['after the ESC introducer', ['\x1b]777;orca-shell-ready\x07\x1b', '[?2004hfish> ']] + ])('preserves Fish bracketed-paste output split %s', (_boundary, chunks) => { + createSession({ shellReadySupported: true }) + const received: string[] = [] + session.attachClient({ + onData: (data) => received.push(data), + onExit: () => {} + }) + + for (const chunk of chunks) { + subprocess.simulateData(chunk) + } + + const output = received.join('') + expect(output).toBe('\x1b[?2004hfish> ') + const rendered = new HeadlessEmulator({ cols: 80, rows: 24 }) + expect(rendered.writeSync(output)).toBe(true) + expect(rendered.getVisibleLines().join('\n')).not.toContain('[?2004h') + rendered.dispose() + }) + it('publishes an absolute output sequence with live snapshots', () => { createSession() subprocess.simulateData('first') diff --git a/src/main/providers/local-pty-provider.test.ts b/src/main/providers/local-pty-provider.test.ts index 889d75ac7ae..178b60d6caa 100644 --- a/src/main/providers/local-pty-provider.test.ts +++ b/src/main/providers/local-pty-provider.test.ts @@ -658,6 +658,23 @@ describe('LocalPtyProvider', () => { } }) + it.each([ + ['after the ready marker', ['\x1b]777;orca-shell-ready\x07', '\x1b[?2004hfish> ']], + ['after the ESC introducer', ['\x1b]777;orca-shell-ready\x07\x1b', '[?2004hfish> ']] + ])('preserves Fish bracketed-paste output split %s', async (_boundary, chunks) => { + process.env.SHELL = '/usr/bin/fish' + const received: string[] = [] + provider.configure({ onData: (_id, data) => received.push(data) }) + + await provider.spawn({ cols: 80, rows: 24, command: 'printf ready' }) + const dataCallback = mockProc.onData.mock.calls[0]?.[0] as (data: string) => void + for (const chunk of chunks) { + dataCallback(chunk) + } + + expect(received.join('')).toBe('\x1b[?2004hfish> ') + }) + it('releases held marker-prefix bytes when local shell readiness times out', async () => { vi.useFakeTimers() const onData = vi.fn()