mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 00:02:31 +00:00
Fix Windows ConPTY probe failures by removing startup control bytes (#5893)
* Fix Windows ConPTY probe failures by removing startup control bytes Avoid prepending terminal probes with interrupt (`\x03`) or line-kill (`\x15`) control characters on fresh shell launches. In Windows ConPTY, echoing a startup Ctrl+C can print a literal "^C" and corrupt the subsequent PowerShell commands. - Extract probe command sequence generation to a dedicated helper - Include E2E unit tests in the Vitest test suite config * Rename terminal probe E2E test to match unit test pattern Update the Vitest configuration glob pattern to target only E2E tests ending in `.unit.test.ts`, and rename the terminal probe input sequence test to match. This ensures only unit-like E2E tests are picked up by Vitest.
This commit is contained in:
@@ -15,7 +15,12 @@ export default defineConfig({
|
||||
},
|
||||
test: {
|
||||
environment: 'node',
|
||||
include: ['src/**/*.test.ts', 'src/**/*.test.tsx', 'config/scripts/**/*.test.mjs'],
|
||||
include: [
|
||||
'src/**/*.test.ts',
|
||||
'src/**/*.test.tsx',
|
||||
'config/scripts/**/*.test.mjs',
|
||||
'tests/e2e/**/*.unit.test.ts'
|
||||
],
|
||||
// Why: the full suite runs heavy TS transforms plus real git/http fixtures;
|
||||
// the Vitest 5s defaults are too tight for the slowest integration cases.
|
||||
hookTimeout: 60_000,
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
waitForPtyShellEcho
|
||||
} from './terminal-pty-readiness'
|
||||
import { nodeTerminalCommand } from './terminal-node-command'
|
||||
import { buildFreshShellProbeInputSequence } from './terminal-probe-input-sequence'
|
||||
|
||||
type TerminalColumnProbeWindow = Window & {
|
||||
__store?: {
|
||||
@@ -78,21 +79,14 @@ export async function waitForPtyColumnsAtMost(
|
||||
while (Date.now() < deadline) {
|
||||
const marker = `ORCA_PTY_COLUMNS_${randomUUID()}`
|
||||
lastMarker = marker
|
||||
// Why: a few CI shells occasionally eat the first printable byte when a
|
||||
// command is written immediately after Ctrl+C/Ctrl+U. Split control bytes
|
||||
// from the probe command so the shell sees the whole `node` executable.
|
||||
await sendToTerminal(page, ptyId, '\x03')
|
||||
await page.waitForTimeout(50)
|
||||
await sendToTerminal(page, ptyId, '\x15')
|
||||
await page.waitForTimeout(50)
|
||||
await sendToTerminal(
|
||||
page,
|
||||
ptyId,
|
||||
for (const input of buildFreshShellProbeInputSequence(
|
||||
`${nodeTerminalCommand([
|
||||
'-e',
|
||||
`console.log('${marker}:' + (process.stdout.columns || 0))`
|
||||
])}\r`
|
||||
)
|
||||
)) {
|
||||
await sendToTerminal(page, ptyId, input)
|
||||
}
|
||||
const probeDeadline = Date.now() + Math.min(5_000, Math.max(0, deadline - Date.now()))
|
||||
while (Date.now() < probeDeadline) {
|
||||
const content = await getTerminalContentForPtyId(page, ptyId, 30_000)
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
export function buildFreshShellProbeInputSequence(command: string): readonly string[] {
|
||||
// Why: Windows ConPTY can echo a startup Ctrl+C as literal "^C", which
|
||||
// corrupts the following PowerShell command before the shell is ready.
|
||||
return [command]
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { buildFreshShellProbeInputSequence } from './terminal-probe-input-sequence'
|
||||
|
||||
describe('buildFreshShellProbeInputSequence', () => {
|
||||
it('does not prefix fresh shell probes with interrupt or line-kill bytes', () => {
|
||||
const command = "& 'C:\\node\\node.exe' '-e' 'console.log(1)'\r"
|
||||
|
||||
expect(buildFreshShellProbeInputSequence(command)).toEqual([command])
|
||||
expect(buildFreshShellProbeInputSequence(command).join('')).not.toContain('\x03')
|
||||
expect(buildFreshShellProbeInputSequence(command).join('')).not.toContain('\x15')
|
||||
})
|
||||
})
|
||||
@@ -3,6 +3,7 @@ import type { Page } from '@stablyai/playwright-test'
|
||||
import { expect } from '@stablyai/playwright-test'
|
||||
import { sendToTerminal } from './helpers/terminal'
|
||||
import { nodeTerminalCommand } from './terminal-node-command'
|
||||
import { buildFreshShellProbeInputSequence } from './terminal-probe-input-sequence'
|
||||
|
||||
type TerminalPtyReadinessWindow = Window & {
|
||||
__paneManagers?: Map<
|
||||
@@ -83,14 +84,11 @@ export async function waitForPtyShellEcho(
|
||||
const deadline = Date.now() + timeoutMs
|
||||
await waitForPtyPaneMounted(page, ptyId, Math.min(10_000, timeoutMs))
|
||||
while (Date.now() < deadline) {
|
||||
await sendToTerminal(page, ptyId, '\x03')
|
||||
await page.waitForTimeout(50)
|
||||
await sendToTerminal(page, ptyId, '\x15')
|
||||
await page.waitForTimeout(50)
|
||||
|
||||
// Why: terminal scrollback includes command echo. Encode the marker inside
|
||||
// the node snippet so seeing the plain marker proves the shell executed it.
|
||||
await sendToTerminal(page, ptyId, encodedMarkerCommand(marker))
|
||||
for (const input of buildFreshShellProbeInputSequence(encodedMarkerCommand(marker))) {
|
||||
await sendToTerminal(page, ptyId, input)
|
||||
}
|
||||
|
||||
const probeDeadline = Date.now() + Math.min(3_000, Math.max(0, deadline - Date.now()))
|
||||
while (Date.now() < probeDeadline) {
|
||||
|
||||
Reference in New Issue
Block a user