fix(pty): observe readiness before exact probe threshold
This commit is contained in:
@@ -125,7 +125,8 @@ class LocalSendOperation implements PtySendOperation {
|
|||||||
|
|
||||||
acceptsStdinWait(pgid: number, waiting: boolean): boolean {
|
acceptsStdinWait(pgid: number, waiting: boolean): boolean {
|
||||||
// The same group may still expose the wait that existed before terminal.write.
|
// The same group may still expose the wait that existed before terminal.write.
|
||||||
// It becomes post-write evidence only after polling observes it leave that wait.
|
// Observe every poll so a departure before the exact-settlement threshold
|
||||||
|
// still makes a later return to that wait post-write evidence.
|
||||||
if (pgid !== this.initialForegroundPgid) return waiting
|
if (pgid !== this.initialForegroundPgid) return waiting
|
||||||
if (!waiting) this.initialForegroundLeftWait = true
|
if (!waiting) this.initialForegroundLeftWait = true
|
||||||
return waiting && this.initialForegroundLeftWait
|
return waiting && this.initialForegroundLeftWait
|
||||||
@@ -338,12 +339,15 @@ export class LocalPtySession implements PtyBackendSession {
|
|||||||
}
|
}
|
||||||
const elapsed = Date.now() - operation.startedAt
|
const elapsed = Date.now() - operation.startedAt
|
||||||
const startupHasOutput = !this.initializing || this.scrollback.snapshot().text.length > 0
|
const startupHasOutput = !this.initializing || this.scrollback.snapshot().text.length > 0
|
||||||
if (startupHasOutput && elapsed >= this.config.exactProbeAfterMs) {
|
let acceptsStdinWait = false
|
||||||
|
if (startupHasOutput) {
|
||||||
const pgid = this.inspector.foregroundPgid(this.pid)
|
const pgid = this.inspector.foregroundPgid(this.pid)
|
||||||
if (pgid !== undefined && operation.acceptsStdinWait(pgid, this.inspector.isStdinWaiting(pgid))) {
|
acceptsStdinWait = pgid !== undefined
|
||||||
this.settleActive('stdin_read')
|
&& operation.acceptsStdinWait(pgid, this.inspector.isStdinWaiting(pgid))
|
||||||
return
|
}
|
||||||
}
|
if (elapsed >= this.config.exactProbeAfterMs && acceptsStdinWait) {
|
||||||
|
this.settleActive('stdin_read')
|
||||||
|
return
|
||||||
}
|
}
|
||||||
// A prompt candidate can race bash's foreground handoff, but an interactive
|
// A prompt candidate can race bash's foreground handoff, but an interactive
|
||||||
// child also inherits PROMPT_COMMAND. Silence therefore remains the bound
|
// child also inherits PROMPT_COMMAND. Silence therefore remains the bound
|
||||||
|
|||||||
@@ -144,6 +144,31 @@ describe('LocalPtySession readiness and output', () => {
|
|||||||
expect((await operation.done).waitReason).toBe('stdin_read')
|
expect((await operation.done).waitReason).toBe('stdin_read')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('tracks a pre-write wait exit before exact probing begins', async () => {
|
||||||
|
vi.useFakeTimers()
|
||||||
|
const terminal = new FakeTerminal()
|
||||||
|
const inspector = new FakeInspector()
|
||||||
|
const session = new LocalPtySession(terminal.asPty(), inspector, config({
|
||||||
|
exactProbeAfterMs: 50,
|
||||||
|
idleSilenceMs: 100,
|
||||||
|
timeoutMs: 200,
|
||||||
|
}))
|
||||||
|
await initialize(session, terminal)
|
||||||
|
|
||||||
|
inspector.waiting = true
|
||||||
|
const operation = session.startSend({ text: 'fast command', submit: true })
|
||||||
|
let settled = false
|
||||||
|
void operation.done.then(() => { settled = true })
|
||||||
|
inspector.waiting = false
|
||||||
|
await vi.advanceTimersByTimeAsync(10)
|
||||||
|
inspector.waiting = true
|
||||||
|
await vi.advanceTimersByTimeAsync(30)
|
||||||
|
expect(settled).toBe(false)
|
||||||
|
await vi.advanceTimersByTimeAsync(10)
|
||||||
|
expect(settled).toBe(true)
|
||||||
|
expect((await operation.done).waitReason).toBe('stdin_read')
|
||||||
|
})
|
||||||
|
|
||||||
it('distinguishes inferred idle, timeout, exit signal, and operation reads', async () => {
|
it('distinguishes inferred idle, timeout, exit signal, and operation reads', async () => {
|
||||||
vi.useFakeTimers()
|
vi.useFakeTimers()
|
||||||
const terminal = new FakeTerminal()
|
const terminal = new FakeTerminal()
|
||||||
|
|||||||
Reference in New Issue
Block a user