import { type CallerDispatchFn } from '../context/session_context.ts';
import type { StatusWriter } from './types.ts';
import type { SessionState } from './session/session.ts';
/**
 * Run `fn` as the body of the line `signal` belongs to. Everything the
 * body awaits, down to the status write, can then ask `abortedLine`
 * whether its caller is still waiting, without the signal being threaded
 * through every handler. `shell` is the only caller.
 */
export declare function runWithLineAbort<T>(signal: AbortSignal | undefined, sessions: readonly SessionState[], writer: StatusWriter, fn: () => Promise<T>, stop?: AbortSignal): Promise<T>;
/**
 * The identity of the line stamping on `session`, for `recordStatus` to
 * record and an aborted line to compare its snapshot against.
 *
 * Null when no line is running (a background job, a test driving a
 * handler directly) and null when more than one line is live on this
 * session, which is the case the comparison exists to refuse: with two
 * writers in play nothing can attribute the last stamp, so an aborted
 * line declines to restore rather than guess.
 */
export declare function lineStatusWriter(session: SessionState): StatusWriter | null;
/**
 * The aborted signal of the line stamping on `session`, or undefined
 * when that line is still wanted, or when no line is running at all (a
 * background job, a test driving a handler directly): nobody is
 * waiting there and nothing is an orphan.
 *
 * Read from every live frame for the session rather than the newest
 * frame. On an isolating runtime the live frames are the current task's
 * alone, so the answer is exact. On the browser fallback the newest
 * frame may belong to another line that happens to overlap, so the status write
 * refuses only when every live line on this session has aborted: one
 * line's abort never reaches a concurrent line's statement, and the one
 * case left open is two aborted-or-not lines overlapping on one session
 * without task isolation, where the fallback cannot tell them apart.
 */
export declare function abortedLine(session: SessionState): AbortSignal | undefined;
/**
 * A dispatch that refuses to start an op once `signal` has fired. A
 * cancelled asyncio task unwinds at its next await, so a Python handler
 * that loops over operands (`rm link1 link2`, `chmod`, `touch`) never
 * reaches the next one. A JS handler resumes after the await that was in
 * flight when the caller was released and would begin the next write.
 * Refusing at the dispatcher, the one seam every handler's I/O goes through,
 * stops it there without threading the signal through each handler. An
 * op already in flight settles on its own.
 *
 * The command's ops also share one yield budget: a walk the index answers
 * resolves each op in a microtask, which no timer or abort ever runs between,
 * so the budget hands the loop a task-queue turn every few milliseconds and
 * the abort or timeout that fired there refuses the next op. Python's
 * dispatcher spends the running task's budget, `task_turn`, the same way.
 * The ops a command issues at once (the patterns of one grep) take the first
 * one's answer, a turn or none, and go on together, as the tasks Python
 * gathers start on budgets of their own: a turn each would let one op finish
 * all it resolves without I/O before the next starts, and share nothing in
 * flight with it.
 */
export declare function guardDispatch(dispatch: CallerDispatchFn, signal: AbortSignal | undefined): CallerDispatchFn;
/** A fresh line identity. */
export declare function newStatusWriter(): StatusWriter;
//# sourceMappingURL=abort.d.ts.map