/** * @license * Copyright 2026 Steven Roussey * SPDX-License-Identifier: Apache-2.0 */ import type { IHumanConnector, IHumanRequest, IHumanResponse } from "@workglow/util"; import type { RunEventSink } from "./runEventChannel"; /** Opens a reader for answers, returning how to stop it. */ export type AnswerReaderFactory = (onLine: (line: string) => void) => (() => void) | undefined; /** * Asks the human by writing the request to the run's event stream and waiting * for a matching line on stdin. The parent bridges both ends to a browser. * * An aborted run resolves as `cancel` rather than rejecting: a child blocked on * a question nobody is reading any more has to end, and a rejection here would * surface as a task failure rather than as the cancellation it is. */ export declare class RunEventHumanConnector implements IHumanConnector { private readonly sink; private readonly openReader?; private readonly pending; /** Live answer reader, held only while at least one request is outstanding. */ private stopReader; constructor(sink: RunEventSink, openReader?: AnswerReaderFactory | undefined); /** * The reader is opened per outstanding request and released with the last one. * * Kept open for the life of the process it does exactly one thing beyond * reading: it holds the event loop, so a child that has finished its work * never exits. Nothing observes that on a terminal — the command has already * printed — but the web console ends a run on the child's exit, so every * command that asked nothing hung there forever while having done its job in * a second. */ private acquireReader; private releaseReader; send(request: IHumanRequest, signal: AbortSignal): Promise; followUp(request: IHumanRequest, _previous: IHumanResponse, signal: AbortSignal): Promise; /** One NDJSON line from the parent, shaped like an {@link IHumanResponse}. */ feedHumanResponseLine(line: string): void; }